From 4e5b55786831f4dcf1078a5755a74dc314281435 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 10 Apr 2017 17:50:27 -0500 Subject: [PATCH] Initial commit for Labs 11-15 --- L11.zip | Bin 0 -> 10136 bytes L11/CMakeLists.txt | 127 + L11/resources/simple_frag.glsl | 8 + L11/resources/simple_vert.glsl | 11 + L11/src/GLSL.cpp | 152 + L11/src/GLSL.h | 40 + L11/src/MatrixStack.cpp | 114 + L11/src/MatrixStack.h | 50 + L11/src/Program.cpp | 126 + L11/src/Program.h | 44 + L11/src/main.cpp | 270 + L12.zip | Bin 0 -> 137574 bytes L12/CMakeLists.txt | 126 + L12/resources/bunny.obj | 11051 +++++++++++++++++++++++++++++++ L12/resources/normal_frag.glsl | 11 + L12/resources/normal_vert.glsl | 12 + L12/resources/simple_frag.glsl | 8 + L12/resources/simple_vert.glsl | 11 + L12/src/Camera.cpp | 68 + L12/src/Camera.h | 50 + L12/src/GLSL.cpp | 152 + L12/src/GLSL.h | 40 + L12/src/MatrixStack.cpp | 114 + L12/src/MatrixStack.h | 50 + L12/src/Program.cpp | 126 + L12/src/Program.h | 44 + L12/src/Shape.cpp | 166 + L12/src/Shape.h | 37 + L12/src/main.cpp | 299 + L12/src/tiny_obj_loader.h | 1922 ++++++ L13.zip | Bin 0 -> 10824 bytes L13/CMakeLists.txt | 126 + L13/resources/simple_frag.glsl | 8 + L13/resources/simple_vert.glsl | 11 + L13/src/GLSL.cpp | 152 + L13/src/GLSL.h | 40 + L13/src/MatrixStack.cpp | 114 + L13/src/MatrixStack.h | 50 + L13/src/Program.cpp | 126 + L13/src/Program.h | 44 + L13/src/main.cpp | 360 + L14.zip | Bin 0 -> 9821 bytes L14/CMakeLists.txt | 148 + L14/resources/simple_frag.glsl | 8 + L14/resources/simple_vert.glsl | 11 + L14/src/GLSL.cpp | 152 + L14/src/GLSL.h | 40 + L14/src/MatrixStack.cpp | 114 + L14/src/MatrixStack.h | 50 + L14/src/Program.cpp | 126 + L14/src/Program.h | 44 + L14/src/main.cpp | 230 + L15.zip | Bin 0 -> 109737 bytes L15/CMakeLists.txt | 127 + L15/resources/man.obj | 1011 +++ L15/resources/simple_frag.glsl | 8 + L15/resources/simple_vert.glsl | 11 + L15/resources/tex_frag.glsl | 10 + L15/resources/tex_vert.glsl | 13 + L15/resources/wood_tex.jpg | Bin 0 -> 13994 bytes L15/src/GLSL.cpp | 152 + L15/src/GLSL.h | 40 + L15/src/Grid.cpp | 185 + L15/src/Grid.h | 36 + L15/src/MatrixStack.cpp | 114 + L15/src/MatrixStack.h | 50 + L15/src/Program.cpp | 126 + L15/src/Program.h | 44 + L15/src/ShapeCage.cpp | 151 + L15/src/ShapeCage.h | 35 + L15/src/Texture.cpp | 80 + L15/src/Texture.h | 32 + L15/src/main.cpp | 260 + L15/src/stb_image.h | 6755 +++++++++++++++++++ L15/src/tiny_obj_loader.h | 1922 ++++++ 75 files changed, 28345 insertions(+) create mode 100644 L11.zip create mode 100644 L11/CMakeLists.txt create mode 100644 L11/resources/simple_frag.glsl create mode 100644 L11/resources/simple_vert.glsl create mode 100644 L11/src/GLSL.cpp create mode 100644 L11/src/GLSL.h create mode 100644 L11/src/MatrixStack.cpp create mode 100644 L11/src/MatrixStack.h create mode 100644 L11/src/Program.cpp create mode 100644 L11/src/Program.h create mode 100644 L11/src/main.cpp create mode 100644 L12.zip create mode 100644 L12/CMakeLists.txt create mode 100644 L12/resources/bunny.obj create mode 100644 L12/resources/normal_frag.glsl create mode 100644 L12/resources/normal_vert.glsl create mode 100644 L12/resources/simple_frag.glsl create mode 100644 L12/resources/simple_vert.glsl create mode 100644 L12/src/Camera.cpp create mode 100644 L12/src/Camera.h create mode 100644 L12/src/GLSL.cpp create mode 100644 L12/src/GLSL.h create mode 100644 L12/src/MatrixStack.cpp create mode 100644 L12/src/MatrixStack.h create mode 100644 L12/src/Program.cpp create mode 100644 L12/src/Program.h create mode 100644 L12/src/Shape.cpp create mode 100644 L12/src/Shape.h create mode 100644 L12/src/main.cpp create mode 100644 L12/src/tiny_obj_loader.h create mode 100644 L13.zip create mode 100644 L13/CMakeLists.txt create mode 100644 L13/resources/simple_frag.glsl create mode 100644 L13/resources/simple_vert.glsl create mode 100644 L13/src/GLSL.cpp create mode 100644 L13/src/GLSL.h create mode 100644 L13/src/MatrixStack.cpp create mode 100644 L13/src/MatrixStack.h create mode 100644 L13/src/Program.cpp create mode 100644 L13/src/Program.h create mode 100644 L13/src/main.cpp create mode 100644 L14.zip create mode 100644 L14/CMakeLists.txt create mode 100644 L14/resources/simple_frag.glsl create mode 100644 L14/resources/simple_vert.glsl create mode 100644 L14/src/GLSL.cpp create mode 100644 L14/src/GLSL.h create mode 100644 L14/src/MatrixStack.cpp create mode 100644 L14/src/MatrixStack.h create mode 100644 L14/src/Program.cpp create mode 100644 L14/src/Program.h create mode 100644 L14/src/main.cpp create mode 100644 L15.zip create mode 100644 L15/CMakeLists.txt create mode 100755 L15/resources/man.obj create mode 100644 L15/resources/simple_frag.glsl create mode 100644 L15/resources/simple_vert.glsl create mode 100644 L15/resources/tex_frag.glsl create mode 100644 L15/resources/tex_vert.glsl create mode 100644 L15/resources/wood_tex.jpg create mode 100644 L15/src/GLSL.cpp create mode 100644 L15/src/GLSL.h create mode 100644 L15/src/Grid.cpp create mode 100644 L15/src/Grid.h create mode 100644 L15/src/MatrixStack.cpp create mode 100644 L15/src/MatrixStack.h create mode 100644 L15/src/Program.cpp create mode 100644 L15/src/Program.h create mode 100644 L15/src/ShapeCage.cpp create mode 100644 L15/src/ShapeCage.h create mode 100644 L15/src/Texture.cpp create mode 100644 L15/src/Texture.h create mode 100644 L15/src/main.cpp create mode 100644 L15/src/stb_image.h create mode 100644 L15/src/tiny_obj_loader.h diff --git a/L11.zip b/L11.zip new file mode 100644 index 0000000000000000000000000000000000000000..161379d561d723bb71b728c0b881dd16ae2a5432 GIT binary patch literal 10136 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

@vFqv?{sFpGdEbgUTp zUy>qC#S$>}X>z%7>!ucTE9I%{=-puWyeEewVVKPLEDv*fx;N@jww7k8=^tcSRCw+Yzgp$r!@gQt?)n_yJzn-u^L|@HJ%SGA zhV@>{y=kuRl#C#)5uol6eqrGu4;;_m!~6D`!E?_1t1U$9^57RhxCs!(Qb*<Lv@=AR<)bYp7UzZ49lN^Y4JP;F6|?3kN5C_CC0?Dn>F8KGMV49l>s4LhU3 zUBR)HHCZ$P{!UK;&rFfm7(P( zKo1~M_}43Ea$;s+EE!}QZL&bKxRQ!h<1&msD~~|D3XJW?70Di>w2k}K{{+ai?1Mo9%@Wm_t!TZ|}cp?7q1O6ex zUpHkx6GJfnB>uKV`{z)9ubqDebHCUZKSKQ({Qvp|eqevCk$%P&;r)sIrDFR3#ro?a z@G}&T=vU}J#QERk=}+XJSvgA#_(iN +#include +#include +#include + +using namespace std; + +namespace GLSL { + +const char * errorString(GLenum err) +{ + switch(err) { + case GL_NO_ERROR: + return "No error"; + case GL_INVALID_ENUM: + return "Invalid enum"; + case GL_INVALID_VALUE: + return "Invalid value"; + case GL_INVALID_OPERATION: + return "Invalid operation"; + case GL_STACK_OVERFLOW: + return "Stack overflow"; + case GL_STACK_UNDERFLOW: + return "Stack underflow"; + case GL_OUT_OF_MEMORY: + return "Out of memory"; + default: + return "No error"; + } +} + +void checkVersion() +{ + int major, minor; + major = minor = 0; + const char *verstr = (const char *)glGetString(GL_VERSION); + + if((verstr == NULL) || (sscanf(verstr, "%d.%d", &major, &minor) != 2)) { + printf("Invalid GL_VERSION format %d.%d\n", major, minor); + } + if(major < 2) { + printf("This shader example will not work due to the installed Opengl version, which is %d.%d.\n", major, minor); + exit(0); + } +} + +void checkError(const char *str) +{ + GLenum glErr = glGetError(); + if(glErr != GL_NO_ERROR) { + if(str) { + printf("%s: ", str); + } + printf("GL_ERROR = %s.\n", errorString(glErr)); + assert(false); + } +} + +void printShaderInfoLog(GLuint shader) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + GLchar *infoLog = 0; + + checkError(GET_FILE_LINE); + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength); + checkError(GET_FILE_LINE); + + if(infologLength > 0) { + infoLog = (GLchar *)malloc(infologLength); + if(infoLog == NULL) { + puts("ERROR: Could not allocate InfoLog buffer"); + exit(1); + } + glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog); + checkError(GET_FILE_LINE); + printf("Shader InfoLog:\n%s\n\n", infoLog); + free(infoLog); + } +} + +void printProgramInfoLog(GLuint program) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + GLchar *infoLog = 0; + + checkError(GET_FILE_LINE); + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infologLength); + checkError(GET_FILE_LINE); + + if(infologLength > 0) { + infoLog = (GLchar *)malloc(infologLength); + if(infoLog == NULL) { + puts("ERROR: Could not allocate InfoLog buffer"); + exit(1); + } + glGetProgramInfoLog(program, infologLength, &charsWritten, infoLog); + checkError(GET_FILE_LINE); + printf("Program InfoLog:\n%s\n\n", infoLog); + free(infoLog); + } +} + +char *textFileRead(const char *fn) +{ + FILE *fp; + char *content = NULL; + int count = 0; + if(fn != NULL) { + fp = fopen(fn,"rt"); + if(fp != NULL) { + fseek(fp, 0, SEEK_END); + count = (int)ftell(fp); + rewind(fp); + if(count > 0) { + content = (char *)malloc(sizeof(char) * (count+1)); + count = (int)fread(content,sizeof(char),count,fp); + content[count] = '\0'; + } + fclose(fp); + } else { + printf("error loading %s\n", fn); + } + } + return content; +} + +int textFileWrite(const char *fn, const char *s) +{ + FILE *fp; + int status = 0; + if(fn != NULL) { + fp = fopen(fn,"w"); + if(fp != NULL) { + if(fwrite(s,sizeof(char),strlen(s),fp) == strlen(s)) { + status = 1; + } + fclose(fp); + } + } + return(status); +} + +} diff --git a/L11/src/GLSL.h b/L11/src/GLSL.h new file mode 100644 index 0000000..f945fdd --- /dev/null +++ b/L11/src/GLSL.h @@ -0,0 +1,40 @@ +// +// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book +// Created by zwood on 2/21/10. +// Modified by sueda 10/15/15. +// + +#pragma once +#ifndef __GLSL__ +#define __GLSL__ + +#define GLEW_STATIC +#include + +/////////////////////////////////////////////////////////////////////////////// +// For printing out the current file and line number // +/////////////////////////////////////////////////////////////////////////////// +#include + +template +std::string NumberToString(T x) +{ + std::ostringstream ss; + ss << x; + return ss.str(); +} + +#define GET_FILE_LINE (std::string(__FILE__) + ":" + NumberToString(__LINE__)).c_str() +/////////////////////////////////////////////////////////////////////////////// + +namespace GLSL { + + void checkVersion(); + void checkError(const char *str = 0); + void printProgramInfoLog(GLuint program); + void printShaderInfoLog(GLuint shader); + int textFileWrite(const char *filename, const char *s); + char *textFileRead(const char *filename); +} + +#endif diff --git a/L11/src/MatrixStack.cpp b/L11/src/MatrixStack.cpp new file mode 100644 index 0000000..eaa6e6c --- /dev/null +++ b/L11/src/MatrixStack.cpp @@ -0,0 +1,114 @@ +#include "MatrixStack.h" + +#include +#include +#include + +#define GLM_FORCE_RADIANS +#include +#include + +using namespace std; + +MatrixStack::MatrixStack() +{ + mstack = make_shared< stack >(); + mstack->push(glm::mat4(1.0)); +} + +MatrixStack::~MatrixStack() +{ +} + +void MatrixStack::pushMatrix() +{ + const glm::mat4 &top = mstack->top(); + mstack->push(top); + assert(mstack->size() < 100); +} + +void MatrixStack::popMatrix() +{ + assert(!mstack->empty()); + mstack->pop(); + // There should always be one matrix left. + assert(!mstack->empty()); +} + +void MatrixStack::loadIdentity() +{ + glm::mat4 &top = mstack->top(); + top = glm::mat4(1.0); +} + +void MatrixStack::translate(const glm::vec3 &t) +{ + glm::mat4 &top = mstack->top(); + top *= glm::translate(t); +} + +void MatrixStack::translate(float x, float y, float z) +{ + translate(glm::vec3(x, y, z)); +} + +void MatrixStack::scale(const glm::vec3 &s) +{ + glm::mat4 &top = mstack->top(); + top *= glm::scale(s); +} + +void MatrixStack::scale(float x, float y, float z) +{ + scale(glm::vec3(x, y, z)); +} + +void MatrixStack::scale(float s) +{ + scale(glm::vec3(s, s, s)); +} + +void MatrixStack::rotate(float angle, const glm::vec3 &axis) +{ + glm::mat4 &top = mstack->top(); + top *= glm::rotate(angle, axis); +} + +void MatrixStack::rotate(float angle, float x, float y, float z) +{ + rotate(angle, glm::vec3(x, y, z)); +} + +void MatrixStack::multMatrix(const glm::mat4 &matrix) +{ + glm::mat4 &top = mstack->top(); + top *= matrix; +} + +const glm::mat4 &MatrixStack::topMatrix() const +{ + return mstack->top(); +} + +void MatrixStack::print(const glm::mat4 &mat, const char *name) +{ + if(name) { + printf("%s = [\n", name); + } + for(int i = 0; i < 4; ++i) { + for(int j = 0; j < 4; ++j) { + // mat[j] returns the jth column + printf("%- 5.2f ", mat[j][i]); + } + printf("\n"); + } + if(name) { + printf("];"); + } + printf("\n"); +} + +void MatrixStack::print(const char *name) const +{ + print(mstack->top(), name); +} diff --git a/L11/src/MatrixStack.h b/L11/src/MatrixStack.h new file mode 100644 index 0000000..66278ce --- /dev/null +++ b/L11/src/MatrixStack.h @@ -0,0 +1,50 @@ +#pragma once +#ifndef _MatrixStack_H_ +#define _MatrixStack_H_ + +#include +#include +#include + +class MatrixStack +{ +public: + MatrixStack(); + virtual ~MatrixStack(); + + // glPushMatrix(): Copies the current matrix and adds it to the top of the stack + void pushMatrix(); + // glPopMatrix(): Removes the top of the stack and sets the current matrix to be the matrix that is now on top + void popMatrix(); + + // glLoadIdentity(): Sets the top matrix to be the identity + void loadIdentity(); + // glMultMatrix(): Right multiplies the top matrix + void multMatrix(const glm::mat4 &matrix); + + // glTranslate(): Right multiplies the top matrix by a translation matrix + void translate(const glm::vec3 &trans); + void translate(float x, float y, float z); + // glScale(): Right multiplies the top matrix by a scaling matrix + void scale(const glm::vec3 &scale); + void scale(float x, float y, float z); + // glScale(): Right multiplies the top matrix by a scaling matrix + void scale(float size); + // glRotate(): Right multiplies the top matrix by a rotation matrix (angle in radians) + void rotate(float angle, const glm::vec3 &axis); + void rotate(float angle, float x, float y, float z); + + // glGet(GL_MODELVIEW_MATRIX): Gets the top matrix + const glm::mat4 &topMatrix() const; + + // Prints out the specified matrix + static void print(const glm::mat4 &mat, const char *name = 0); + // Prints out the top matrix + void print(const char *name = 0) const; + +private: + std::shared_ptr< std::stack > mstack; + +}; + +#endif diff --git a/L11/src/Program.cpp b/L11/src/Program.cpp new file mode 100644 index 0000000..1e85538 --- /dev/null +++ b/L11/src/Program.cpp @@ -0,0 +1,126 @@ +#include "Program.h" + +#include +#include + +#include "GLSL.h" + +using namespace std; + +Program::Program() : + vShaderName(""), + fShaderName(""), + pid(0), + verbose(true) +{ + +} + +Program::~Program() +{ + +} + +void Program::setShaderNames(const string &v, const string &f) +{ + vShaderName = v; + fShaderName = f; +} + +bool Program::init() +{ + GLint rc; + + // Create shader handles + GLuint VS = glCreateShader(GL_VERTEX_SHADER); + GLuint FS = glCreateShader(GL_FRAGMENT_SHADER); + + // Read shader sources + const char *vshader = GLSL::textFileRead(vShaderName.c_str()); + const char *fshader = GLSL::textFileRead(fShaderName.c_str()); + glShaderSource(VS, 1, &vshader, NULL); + glShaderSource(FS, 1, &fshader, NULL); + + // Compile vertex shader + glCompileShader(VS); + glGetShaderiv(VS, GL_COMPILE_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printShaderInfoLog(VS); + cout << "Error compiling vertex shader " << vShaderName << endl; + } + return false; + } + + // Compile fragment shader + glCompileShader(FS); + glGetShaderiv(FS, GL_COMPILE_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printShaderInfoLog(FS); + cout << "Error compiling fragment shader " << fShaderName << endl; + } + return false; + } + + // Create the program and link + pid = glCreateProgram(); + glAttachShader(pid, VS); + glAttachShader(pid, FS); + glLinkProgram(pid); + glGetProgramiv(pid, GL_LINK_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printProgramInfoLog(pid); + cout << "Error linking shaders " << vShaderName << " and " << fShaderName << endl; + } + return false; + } + + GLSL::checkError(GET_FILE_LINE); + return true; +} + +void Program::bind() +{ + glUseProgram(pid); +} + +void Program::unbind() +{ + glUseProgram(0); +} + +void Program::addAttribute(const string &name) +{ + attributes[name] = glGetAttribLocation(pid, name.c_str()); +} + +void Program::addUniform(const string &name) +{ + uniforms[name] = glGetUniformLocation(pid, name.c_str()); +} + +GLint Program::getAttribute(const string &name) const +{ + map::const_iterator attribute = attributes.find(name.c_str()); + if(attribute == attributes.end()) { + if(isVerbose()) { + cout << name << " is not an attribute variable" << endl; + } + return -1; + } + return attribute->second; +} + +GLint Program::getUniform(const string &name) const +{ + map::const_iterator uniform = uniforms.find(name.c_str()); + if(uniform == uniforms.end()) { + if(isVerbose()) { + cout << name << " is not a uniform variable" << endl; + } + return -1; + } + return uniform->second; +} diff --git a/L11/src/Program.h b/L11/src/Program.h new file mode 100644 index 0000000..51e58bb --- /dev/null +++ b/L11/src/Program.h @@ -0,0 +1,44 @@ +#pragma once +#ifndef __Program__ +#define __Program__ + +#include +#include + +#define GLEW_STATIC +#include + +/** + * An OpenGL Program (vertex and fragment shaders) + */ +class Program +{ +public: + Program(); + virtual ~Program(); + + void setVerbose(bool v) { verbose = v; } + bool isVerbose() const { return verbose; } + + void setShaderNames(const std::string &v, const std::string &f); + virtual bool init(); + virtual void bind(); + virtual void unbind(); + + void addAttribute(const std::string &name); + void addUniform(const std::string &name); + GLint getAttribute(const std::string &name) const; + GLint getUniform(const std::string &name) const; + +protected: + std::string vShaderName; + std::string fShaderName; + +private: + GLuint pid; + std::map attributes; + std::map uniforms; + bool verbose; +}; + +#endif diff --git a/L11/src/main.cpp b/L11/src/main.cpp new file mode 100644 index 0000000..5060de2 --- /dev/null +++ b/L11/src/main.cpp @@ -0,0 +1,270 @@ +#include +#include +#include + +#define GLEW_STATIC +#include +#include + +#define GLM_FORCE_RADIANS +#include +#include +#include + +#include "GLSL.h" +#include "Program.h" +#include "MatrixStack.h" + +using namespace std; + +GLFWwindow *window; // Main application window +string RESOURCE_DIR = ""; // Where the resources are loaded from +shared_ptr prog; + +bool keyToggles[256] = {false}; // only for English keyboards! +glm::vec2 cameraRotations(0, 0); +glm::vec2 mousePrev(-1, -1); + +// Control points +vector cps; + +enum SplineType +{ + BEZIER = 0, + CATMULL_ROM, + BASIS, + SPLINE_TYPE_COUNT +}; + +SplineType type = BEZIER; + +static void error_callback(int error, const char *description) +{ + cerr << description << endl; +} + +static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) +{ + if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, GL_TRUE); + } + + if(action == GLFW_PRESS) { + switch(key) { + case GLFW_KEY_S: + type = (SplineType)((type + 1) % SPLINE_TYPE_COUNT); + break; + case GLFW_KEY_C: + cps.clear(); + break; + case GLFW_KEY_R: + cps.clear(); + default_random_engine generator; + uniform_real_distribution distribution(-0.8, 0.8); + for(int i = 0; i < 10; ++i) { + float x = distribution(generator); + float y = distribution(generator); + float z = distribution(generator); + cps.push_back(glm::vec3(x, y, z)); + } + break; + } + } +} + +static void char_callback(GLFWwindow *window, unsigned int key) +{ + keyToggles[key] = !keyToggles[key]; +} + +static void cursor_position_callback(GLFWwindow* window, double xmouse, double ymouse) +{ + if(mousePrev.x >= 0) { + glm::vec2 mouseCurr(xmouse, ymouse); + cameraRotations += 0.01f * (mouseCurr - mousePrev); + mousePrev = mouseCurr; + } +} + +void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) +{ + // Get the current mouse position. + double xmouse, ymouse; + glfwGetCursorPos(window, &xmouse, &ymouse); + // Get current window size. + int width, height; + glfwGetWindowSize(window, &width, &height); + if(action == GLFW_PRESS) { + if(mods & GLFW_MOD_SHIFT) { + // Insert a new control point + // Convert from window coord to world coord assuming that we're + // using an orthgraphic projection from -1 to 1. + float aspect = (float)width/height; + glm::vec4 x; + x[0] = 2.0f * ((xmouse / width) - 0.5f)* aspect; + x[1] = 2.0f * (((height - ymouse) / height) - 0.5f); + x[2] = 0.0f; + x[3] = 1.0f; + // Build the current modelview matrix. + auto MV = make_shared(); + MV->rotate(cameraRotations[1], glm::vec3(1, 0, 0)); + MV->rotate(cameraRotations[0], glm::vec3(0, 1, 0)); + // Since the modelview matrix transforms from world to eye coords, + // we want to invert to go from eye to world. + x = glm::inverse(MV->topMatrix()) * x; + cps.push_back(glm::vec3(x)); + } else { + mousePrev.x = xmouse; + mousePrev.y = ymouse; + } + } else { + mousePrev[0] = -1; + mousePrev[1] = -1; + } +} + +static void init() +{ + GLSL::checkVersion(); + + // Set background color + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + // Enable z-buffer test + glEnable(GL_DEPTH_TEST); + + // Initialize the GLSL program. + prog = make_shared(); + prog->setVerbose(true); + prog->setShaderNames(RESOURCE_DIR + "simple_vert.glsl", RESOURCE_DIR + "simple_frag.glsl"); + prog->init(); + prog->addUniform("P"); + prog->addUniform("MV"); + prog->setVerbose(false); + + // Initialize time. + glfwSetTime(0.0); + + keyToggles[(unsigned)'l'] = true; + + // If there were any OpenGL errors, this will print something. + // You can intersperse this line in your code to find the exact location + // of your OpenGL error. + GLSL::checkError(GET_FILE_LINE); +} + +void render() +{ + // Update time. + double t = glfwGetTime(); + + // Get current frame buffer size. + int width, height; + glfwGetFramebufferSize(window, &width, &height); + glViewport(0, 0, width, height); + + // Clear buffers + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + auto P = make_shared(); + auto MV = make_shared(); + P->pushMatrix(); + MV->pushMatrix(); + + double aspect = (double)width/height; + P->multMatrix(glm::ortho(-aspect, aspect, -1.0, 1.0, -2.0, 2.0)); + MV->rotate(cameraRotations.y, glm::vec3(1, 0, 0)); + MV->rotate(cameraRotations.x, glm::vec3(0, 1, 0)); + + // Bind the program + prog->bind(); + glUniformMatrix4fv(prog->getUniform("P"), 1, GL_FALSE, glm::value_ptr(P->topMatrix())); + glUniformMatrix4fv(prog->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix())); + + // Draw control points + int ncps = (int)cps.size(); + glPointSize(5.0f); + glColor3f(1.0f, 0.0f, 0.0f); + glBegin(GL_POINTS); + for(int i = 0; i < ncps; ++i) { + glVertex3f(cps[i].x, cps[i].y, cps[i].z); + } + glEnd(); + glLineWidth(1.0f); + if(keyToggles[(unsigned)'l']) { + glColor3f(1.0f, 0.5f, 0.5f); + glBegin(GL_LINE_STRIP); + for(int i = 0; i < ncps; ++i) { + glVertex3f(cps[i].x, cps[i].y, cps[i].z); + } + glEnd(); + } + + // INSERT CODE HERE + + // Unbind the program + prog->unbind(); + + // Pop matrix stacks. + MV->popMatrix(); + P->popMatrix(); + + GLSL::checkError(GET_FILE_LINE); +} + +int main(int argc, char **argv) +{ + if(argc < 2) { + cout << "Please specify the resource directory." << endl; + return 0; + } + RESOURCE_DIR = argv[1] + string("/"); + + // Set error callback. + glfwSetErrorCallback(error_callback); + // Initialize the library. + if(!glfwInit()) { + return -1; + } + // Create a windowed mode window and its OpenGL context. + window = glfwCreateWindow(640, 480, "YOUR NAME", NULL, NULL); + if(!window) { + glfwTerminate(); + return -1; + } + // Make the window's context current. + glfwMakeContextCurrent(window); + // Initialize GLEW. + glewExperimental = true; + if(glewInit() != GLEW_OK) { + cerr << "Failed to initialize GLEW" << endl; + return -1; + } + glGetError(); // A bug in glewInit() causes an error that we can safely ignore. + cout << "OpenGL version: " << glGetString(GL_VERSION) << endl; + cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl; + // Set vsync. + glfwSwapInterval(1); + // Set keyboard callback. + glfwSetKeyCallback(window, key_callback); + // Set char callback. + glfwSetCharCallback(window, char_callback); + // Set cursor position callback. + glfwSetCursorPosCallback(window, cursor_position_callback); + // Set mouse button callback. + glfwSetMouseButtonCallback(window, mouse_button_callback); + // Initialize scene. + init(); + // Loop until the user closes the window. + while(!glfwWindowShouldClose(window)) { + // Render scene. + render(); + // Swap front and back buffers. + glfwSwapBuffers(window); + // Poll for and process events. + glfwPollEvents(); + } + // Quit program. + glfwDestroyWindow(window); + glfwTerminate(); + return 0; +} diff --git a/L12.zip b/L12.zip new file mode 100644 index 0000000000000000000000000000000000000000..d9f7722f3ea6a1bbc171a2940a51063dfdc98a91 GIT binary patch literal 137574 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 YX#T{f2S)_}>;f;P;MP5MaE<`}2R~<8hyVZp literal 0 HcmV?d00001 diff --git a/L12/CMakeLists.txt b/L12/CMakeLists.txt new file mode 100644 index 0000000..a1fd875 --- /dev/null +++ b/L12/CMakeLists.txt @@ -0,0 +1,126 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +# Name of the project +PROJECT(L12) + +# FOR LAB MACHINES ONLY! +# DO NOT EDIT +SET(DEF_DIR_GLM "C:\\c++\\glm") +SET(DEF_DIR_GLFW "C:\\c++\\glfw-3.2.1") +SET(DEF_DIR_GLEW "C:\\c++\\glew-2.0.0") + +# Is this the solution? +# Override with `cmake -DSOL=ON ..` +OPTION(SOL "Solution" OFF) + +# Use glob to get the list of all source files. +# We don't really need to include header and resource files to build, but it's +# nice to have them also show up in IDEs. +IF(${SOL}) + FILE(GLOB_RECURSE SOURCES "src0/*.cpp") + FILE(GLOB_RECURSE HEADERS "src0/*.h") +ELSE() + FILE(GLOB_RECURSE SOURCES "src/*.cpp") + FILE(GLOB_RECURSE HEADERS "src/*.h") +ENDIF() +FILE(GLOB_RECURSE GLSL "resources/*.glsl") + +# Set the executable. +ADD_EXECUTABLE(${CMAKE_PROJECT_NAME} ${SOURCES} ${HEADERS} ${GLSL}) + +# Get the GLM environment variable. Since GLM is a header-only library, we +# just need to add it to the include directory. +SET(GLM_INCLUDE_DIR "$ENV{GLM_INCLUDE_DIR}") +IF(NOT GLM_INCLUDE_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLM_INCLUDE_DIR to the root directory of your GLM installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLM in ${DEF_DIR_GLM}") + IF(IS_DIRECTORY ${DEF_DIR_GLM}) + MESSAGE(STATUS "Found!") + SET(GLM_INCLUDE_DIR ${DEF_DIR_GLM}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +INCLUDE_DIRECTORIES(${GLM_INCLUDE_DIR}) + +# Get the GLFW environment variable. There should be a CMakeLists.txt in the +# specified directory. +SET(GLFW_DIR "$ENV{GLFW_DIR}") +IF(NOT GLFW_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLFW_DIR to the root directory of your GLFW installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLFW in ${DEF_DIR_GLFW}") + IF(IS_DIRECTORY ${DEF_DIR_GLFW}) + MESSAGE(STATUS "Found!") + SET(GLFW_DIR ${DEF_DIR_GLFW}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +OPTION(GLFW_BUILD_EXAMPLES "GLFW_BUILD_EXAMPLES" OFF) +OPTION(GLFW_BUILD_TESTS "GLFW_BUILD_TESTS" OFF) +OPTION(GLFW_BUILD_DOCS "GLFW_BUILD_DOCS" OFF) +IF(CMAKE_BUILD_TYPE MATCHES Release) + ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/release) +ELSE() + ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/debug) +ENDIF() +INCLUDE_DIRECTORIES(${GLFW_DIR}/include) +TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} glfw ${GLFW_LIBRARIES}) + +# Get the GLEW environment variable. +SET(GLEW_DIR "$ENV{GLEW_DIR}") +IF(NOT GLEW_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLEW_DIR to the root directory of your GLEW installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLEW in ${DEF_DIR_GLEW}") + IF(IS_DIRECTORY ${DEF_DIR_GLEW}) + MESSAGE(STATUS "Found!") + SET(GLEW_DIR ${DEF_DIR_GLEW}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +INCLUDE_DIRECTORIES(${GLEW_DIR}/include) +IF(WIN32) + # With prebuilt binaries + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/Release/Win32/glew32s.lib) +ELSE() + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/libGLEW.a) +ENDIF() + +# OS specific options and libraries +IF(WIN32) + # c++11 is enabled by default. + # -Wall produces way too many warnings. + # -pedantic is not supported. + # Disable warning 4996. + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996") + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} opengl32.lib) +ELSE() + # Enable all pedantic warnings. + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -pedantic") + IF(APPLE) + # Add required frameworks for GLFW. + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "-framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo") + ELSE() + #Link the Linux OpenGL library + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "GL") + ENDIF() +ENDIF() diff --git a/L12/resources/bunny.obj b/L12/resources/bunny.obj new file mode 100644 index 0000000..75b86ab --- /dev/null +++ b/L12/resources/bunny.obj @@ -0,0 +1,11051 @@ +# Blender v2.72 (sub 0) OBJ File: '' +# www.blender.org +v -0.895657 1.401570 0.131285 +v -0.286440 1.236670 0.214338 +v -0.613602 0.429403 0.424102 +v -0.847526 0.786737 0.165979 +v 0.580982 0.702857 0.185105 +v 0.587008 0.669067 0.212898 +v -0.337233 1.777470 -0.088265 +v -0.836267 0.762669 0.107156 +v -0.727535 1.696150 -0.272413 +v -0.651819 1.592570 -0.133369 +v -0.515041 0.362276 -0.121946 +v -0.482494 0.350733 -0.149472 +v -0.684940 1.614080 -0.116388 +v -0.726565 1.654860 -0.179937 +v -0.290611 0.934227 -0.254565 +v -0.158699 1.272720 0.223825 +v -0.138868 1.287040 0.056848 +v -0.036415 1.306940 0.056580 +v -0.929715 1.217080 0.284744 +v -0.106154 1.299180 0.106247 +v -0.360055 0.480376 -0.166778 +v -0.888346 1.009480 0.136267 +v -0.872659 1.049910 0.103351 +v -0.661821 1.714400 -0.419936 +v -0.640468 1.681980 -0.403692 +v -0.638641 1.566650 -0.125820 +v 0.035783 1.313140 0.064334 +v -0.813969 0.731331 0.120279 +v -0.812178 0.730960 0.075399 +v -0.095614 1.293170 0.218695 +v -0.749833 1.568870 -0.045734 +v -0.752878 1.679200 -0.254898 +v -0.499079 1.534520 0.113348 +v -0.807253 1.264810 0.522094 +v -0.899091 1.316230 0.057415 +v -0.532627 0.719749 -0.159947 +v -0.710276 1.299420 -0.085497 +v -0.788116 1.276120 0.529014 +v -0.778259 1.404070 0.476154 +v -0.895491 0.962140 0.138464 +v -0.891585 0.920523 0.100843 +v -0.066033 1.265050 0.301088 +v -0.747732 1.211860 0.531516 +v -0.385781 0.538838 -0.107522 +v -0.381549 0.586378 -0.115305 +v -0.370190 0.894083 -0.234438 +v -0.769495 1.320050 0.522792 +v -0.722533 1.479600 0.412478 +v -0.754472 1.259680 0.531999 +v -0.738767 1.358120 0.501711 +v -0.727150 1.402930 0.474254 +v -0.620755 1.711820 -0.615791 +v -0.030853 1.304540 0.214275 +v -0.047493 1.288860 0.260931 +v -0.759241 1.381130 0.493522 +v 0.530998 0.519366 -0.003194 +v 0.514041 0.489442 0.003863 +v -0.346649 1.611920 -0.135156 +v -0.708221 1.228560 0.531178 +v 0.504117 0.523179 -0.031753 +v -0.508873 1.338190 -0.006407 +v -0.730923 1.180320 0.528743 +v -0.694004 1.438630 0.438692 +v 0.470704 0.426358 0.066338 +v -0.844950 1.098710 0.030685 +v -0.701495 0.957808 0.415432 +v -0.692724 1.084140 0.382138 +v -0.011895 0.897548 0.565436 +v 0.087387 0.905888 0.543332 +v 0.026315 0.596942 0.552763 +v -0.677994 1.233980 0.517209 +v 0.461097 0.795288 0.070910 +v -0.920652 1.270490 0.351131 +v 0.015740 1.295790 0.254493 +v -0.680325 1.059230 0.385503 +v -0.702094 1.007860 0.398532 +v -0.943421 1.223380 0.173388 +v 0.450107 0.935835 0.066690 +v -0.265862 1.251850 0.174200 +v 0.055464 1.298700 0.005015 +v -0.648321 1.030130 0.406245 +v -0.171534 0.388848 0.375407 +v 0.601503 0.655413 0.084489 +v -0.638960 1.588570 -0.532969 +v -0.010981 1.312780 0.164900 +v -0.674540 0.887818 0.434958 +v -0.649571 0.914758 0.441400 +v -0.682084 0.927216 0.426947 +v 0.166355 1.033560 0.450700 +v 0.078647 0.553374 0.527948 +v 0.047555 0.533147 0.530805 +v 0.440967 0.847571 -0.024020 +v -0.217992 1.265670 0.168979 +v 0.006582 1.303760 0.019751 +v 0.195027 1.273780 0.115079 +v -0.642152 0.971897 0.428772 +v -0.674787 0.982633 0.417055 +v 0.042523 0.918908 0.548902 +v 0.064890 0.763054 0.561086 +v -0.315257 1.256440 0.166162 +v -0.477073 1.329760 0.221768 +v -0.791680 1.204460 -0.057224 +v -0.653004 0.856418 0.440485 +v -0.636860 1.615210 -0.575311 +v -0.617801 1.649860 -0.584798 +v -0.619592 1.639990 -0.554456 +v -0.603586 0.947190 0.443967 +v -0.603089 1.051650 0.402654 +v -0.529159 1.408260 -0.004279 +v -0.907610 1.350790 0.216985 +v -0.615558 0.835716 0.441342 +v 0.032716 0.953297 0.532725 +v 0.082600 0.870160 0.556411 +v -0.252613 1.223130 0.258040 +v -0.685271 1.645550 -0.541654 +v -0.578191 0.845510 0.446060 +v -0.621179 0.905624 0.450361 +v -0.595830 0.916960 0.451644 +v -0.572596 1.089900 0.381750 +v -0.749152 1.498390 -0.254898 +v 0.384311 0.560091 0.316860 +v 0.042158 1.054200 0.428332 +v 0.086495 0.447579 0.458414 +v -0.310180 1.220230 0.253449 +v -0.558270 0.399041 -0.098328 +v 0.019693 1.089750 0.424266 +v -0.622677 1.485780 -0.048764 +v -0.697539 1.551740 -0.497259 +v -0.596406 0.811017 0.437786 +v 0.000037 0.603785 0.556578 +v 0.015542 0.625268 0.562738 +v 0.608292 0.651821 0.143992 +v -0.536893 0.418350 0.460049 +v -0.563804 0.453228 0.431887 +v -0.575082 0.411878 0.459199 +v -0.650982 1.395440 -0.078114 +v -0.667333 1.434730 -0.125527 +v -0.595604 0.741481 0.410499 +v -0.542964 0.749316 0.421329 +v -0.562696 0.882473 0.449867 +v -0.598111 0.882321 0.450862 +v -0.593920 1.002190 0.426570 +v -0.549974 0.992634 0.430426 +v 0.408144 0.544856 0.319566 +v 0.425271 0.396429 0.103518 +v -0.525588 0.779259 0.435566 +v -0.542503 0.790102 0.439741 +v -0.570404 0.919210 0.449741 +v -0.065243 0.504607 0.512168 +v -0.040237 0.544179 0.537971 +v 0.427854 0.600019 0.304762 +v 0.180736 0.901012 0.493882 +v 0.430534 0.635502 0.286144 +v 0.459446 0.659105 0.272752 +v 0.567666 0.519849 0.064943 +v 0.566162 0.504859 0.104324 +v -0.478155 1.306200 0.255357 +v -0.299440 0.370289 0.521946 +v -0.555791 0.816306 0.445863 +v -0.533566 0.857507 0.451771 +v -0.561576 0.958015 0.440046 +v -0.521895 0.956567 0.439522 +v 0.208765 1.076750 0.400347 +v 0.197815 1.137380 0.369134 +v 0.144174 1.148920 0.377191 +v -0.022057 0.511920 0.527717 +v 0.170531 0.954068 0.482603 +v 0.342124 1.134930 0.240237 +v -0.515795 1.045280 0.407541 +v -0.540485 1.068420 0.396112 +v 0.101517 1.011890 0.469436 +v -0.529675 0.481621 0.390512 +v -0.510061 0.765056 0.430439 +v -0.503148 0.811224 0.443489 +v -0.532954 0.910265 0.447665 +v -0.556125 1.037470 0.412852 +v -0.518082 1.000970 0.427027 +v 0.111194 1.121740 0.393956 +v 0.036665 1.127170 0.411962 +v -0.618807 1.537080 -0.196205 +v -0.678131 1.461470 -0.237809 +v -0.663795 1.487690 -0.315212 +v -0.509387 0.885939 0.450906 +v 0.367974 0.508707 0.317109 +v 0.477448 0.524460 0.307426 +v -0.749986 1.521790 0.347991 +v 0.014648 1.316120 0.114805 +v -0.716960 0.355497 0.077808 +v -0.489097 0.965509 0.436583 +v -0.477282 1.012250 0.421769 +v -0.493945 1.051500 0.404248 +v -0.050457 0.695815 0.569851 +v 0.128535 1.037280 0.452797 +v -0.072990 0.446724 0.480649 +v -0.506911 0.742543 0.419627 +v -0.489752 0.864808 0.449856 +v -0.510176 1.088450 0.383486 +v -0.046469 1.310070 0.119313 +v -0.486366 0.913271 0.443990 +v -0.910456 1.456480 0.151590 +v -0.466733 1.627780 0.060949 +v -0.496159 0.427788 0.445970 +v -0.500866 0.464216 0.415587 +v -0.454649 0.815784 0.432316 +v -0.462576 0.849067 0.440327 +v -0.458718 0.879699 0.439315 +v -0.453142 0.903620 0.434782 +v -0.449246 0.947402 0.430838 +v -0.495030 1.180370 0.319891 +v -0.126829 1.809100 -0.288803 +v 0.000298 0.933609 0.551944 +v -0.469112 1.581430 0.080771 +v -0.465816 0.478762 0.399725 +v -0.438887 0.512959 0.390368 +v -0.448308 0.730446 0.419417 +v -0.446436 0.777314 0.425729 +v -0.476309 1.058350 0.403184 +v -0.431415 1.180130 0.308515 +v -0.457034 1.209380 0.281553 +v -0.321984 1.541820 -0.074399 +v 0.148218 1.076050 0.417373 +v -0.873722 1.347880 0.031035 +v -0.444949 0.995672 0.423060 +v -0.408796 1.159990 0.328823 +v -0.478083 1.139980 0.344873 +v -0.426959 0.760467 0.425309 +v -0.446230 1.037960 0.411793 +v -0.458757 1.089310 0.385782 +v -0.424657 1.658730 0.040910 +v -0.926236 1.271600 0.288044 +v -0.623289 1.628490 -0.492605 +v -0.419129 0.424001 0.425106 +v -0.388736 0.635021 0.410878 +v -0.428220 0.873208 0.429745 +v -0.414512 0.982828 0.420768 +v -0.070528 1.056390 0.437318 +v -0.434903 0.466572 0.406734 +v -0.415002 0.573974 0.398187 +v -0.423006 0.809510 0.427669 +v -0.388485 0.902082 0.432645 +v -0.386167 1.024190 0.407437 +v -0.495033 1.416040 0.103278 +v -0.101799 1.698240 -0.251240 +v -0.400018 0.466802 0.403985 +v -0.372433 0.739809 0.421196 +v -0.414018 1.068020 0.392359 +v -0.419849 1.125250 0.356416 +v -0.433183 1.680300 0.026742 +v -0.896378 0.919887 0.160986 +v -0.891888 0.892266 0.112935 +v -0.382397 0.516545 0.391892 +v 0.597597 0.638965 0.064406 +v -0.395956 1.687070 0.022438 +v -0.398185 0.777746 0.428196 +v -0.393992 0.837563 0.432298 +v -0.363529 0.806494 0.428080 +v -0.365917 0.855528 0.432977 +v -0.356899 0.885284 0.434327 +v -0.360608 0.962113 0.433399 +v -0.358709 1.059490 0.391288 +v -0.383659 1.068860 0.385658 +v -0.001056 0.741266 0.576743 +v 0.194913 0.348860 -0.028178 +v -0.378697 0.576704 0.397104 +v -0.349446 0.619768 0.397344 +v -0.374769 1.179450 0.311972 +v -0.016404 0.556220 0.543801 +v -0.043364 0.752238 0.584153 +v -0.031036 0.720712 0.578600 +v -0.383017 0.689131 0.417916 +v -0.327428 0.888206 0.437117 +v -0.387817 1.148570 0.336855 +v -0.365515 1.117500 0.357245 +v 0.080760 0.516300 0.515707 +v 0.057583 0.473938 0.490619 +v -0.335833 0.814296 0.420720 +v -0.018693 0.963860 0.535430 +v -0.061739 0.978539 0.519508 +v -0.333716 0.852623 0.427280 +v -0.349702 0.834588 0.427461 +v 0.052958 1.245060 0.331281 +v 0.050704 1.014300 0.459093 +v 0.005209 0.451828 0.471381 +v -0.020914 1.120400 0.421294 +v 0.082663 0.952595 0.516341 +v 0.125942 0.969106 0.491392 +v -0.336230 0.512250 0.383704 +v -0.306598 0.555249 0.369552 +v -0.356160 0.686051 0.411920 +v -0.347203 0.917162 0.440371 +v -0.346972 1.010340 0.420060 +v -0.304093 0.797999 0.424198 +v -0.306734 0.940295 0.444829 +v -0.316340 0.978793 0.437982 +v -0.296063 1.024500 0.422787 +v -0.332203 1.043980 0.405563 +v 0.492501 0.617532 0.301635 +v -0.050400 0.929948 0.559121 +v 0.231801 0.368076 -0.021618 +v -0.313788 0.618243 0.380366 +v -0.345030 0.557949 0.382134 +v -0.298570 0.685518 0.392396 +v -0.327438 0.674974 0.398527 +v -0.330593 0.752990 0.411320 +v 0.449773 0.935049 0.122180 +v 0.449902 0.910559 0.171433 +v -0.062419 0.845416 0.574797 +v -0.315160 1.773460 -0.046873 +v -0.318983 0.912257 0.442678 +v -0.295732 0.901905 0.446813 +v -0.013519 0.775639 0.580426 +v 0.093842 1.046670 0.438777 +v 0.078511 0.987585 0.486963 +v 0.122280 1.289700 0.014156 +v 0.037710 0.730967 0.565414 +v -0.206625 1.652820 -0.179447 +v -0.201739 1.700340 -0.209084 +v -0.210519 1.249150 0.232181 +v -0.279110 0.498731 0.436310 +v -0.302831 0.469941 0.469745 +v -0.253982 1.120540 0.375935 +v -0.316080 1.087570 0.382853 +v 0.023217 0.506492 0.524332 +v -0.008105 1.231830 0.348144 +v -0.253037 1.052580 0.418242 +v -0.260395 1.165380 0.335483 +v -0.271748 1.191500 0.302123 +v -0.311578 1.163030 0.326454 +v 0.150465 1.002020 0.472377 +v 0.058191 1.095940 0.413686 +v 0.026036 0.534678 0.534909 +v -0.052464 1.070200 0.436210 +v -0.443416 1.514090 -0.057701 +v 0.049601 1.277880 0.288599 +v 0.135955 1.298270 0.084231 +v -0.280208 0.972384 0.440300 +v -0.254934 0.999450 0.437289 +v 0.044794 0.567596 0.538674 +v 0.031147 1.202850 0.370294 +v 0.050937 0.684648 0.559903 +v -0.003562 0.695839 0.568634 +v 0.013878 0.659729 0.564835 +v 0.091612 1.080210 0.412879 +v -0.224928 0.497051 0.468840 +v -0.700920 1.688430 -0.260086 +v -0.683825 1.697820 -0.311940 +v -0.637276 1.452920 0.389460 +v -0.264037 1.806320 -0.082866 +v -0.242347 1.807020 -0.100690 +v -0.246300 1.831430 -0.108555 +v -0.274327 0.446599 0.514991 +v -0.264027 0.476794 0.490553 +v 0.075195 1.314280 0.108152 +v -0.877708 0.972629 0.050425 +v -0.147900 1.837220 -0.215839 +v 0.028642 0.787852 0.569692 +v -0.704674 1.802950 -0.521091 +v -0.680264 1.775250 -0.497027 +v -0.671210 1.805830 -0.558314 +v -0.520035 0.511678 0.243121 +v 0.016666 1.162510 0.399302 +v 0.176551 0.840295 0.514476 +v 0.404508 0.621448 0.303537 +v -0.237111 0.510527 0.441580 +v -0.215220 0.566675 0.449639 +v 0.086440 1.307830 0.056572 +v -0.387107 0.725658 -0.173397 +v -0.205326 1.013600 0.438287 +v -0.223218 1.030320 0.432582 +v -0.224228 0.481875 0.494665 +v -0.912777 1.483160 0.172116 +v -0.906078 1.491610 0.217146 +v -0.008745 1.270840 0.300674 +v -0.204624 1.094920 0.407169 +v -0.210631 1.142130 0.375974 +v -0.399214 0.393656 -0.275768 +v 0.082093 0.807933 0.555796 +v 0.032706 0.983188 0.501735 +v -0.272467 1.258250 0.076943 +v 0.110016 1.307310 0.147559 +v 0.055051 1.314670 0.162013 +v 0.093927 1.304180 0.205627 +v -0.658343 1.424200 -0.097426 +v -0.023215 1.187430 0.385684 +v -0.076567 1.167910 0.394855 +v -0.067207 0.721628 0.576019 +v -0.579468 1.558880 0.131356 +v -0.192757 0.830651 0.568779 +v 0.077232 1.292340 0.255156 +v -0.212555 1.189760 0.332480 +v -0.381184 1.745290 -0.084474 +v -0.168844 0.525502 0.484870 +v -0.208214 0.519236 0.455355 +v -0.163539 0.864570 0.570212 +v 0.155195 1.292180 0.139868 +v -0.163676 0.558814 0.503958 +v -0.179590 0.688868 0.533502 +v -0.157359 0.910167 0.559290 +v -0.188291 0.921017 0.540781 +v 0.131176 1.282070 0.248482 +v -0.111333 0.337239 -0.214625 +v -0.182897 1.040140 0.430107 +v -0.136118 1.197290 0.360056 +v 0.394343 0.510871 0.320437 +v 0.062134 0.645006 0.556504 +v -0.182202 0.499249 0.474505 +v -0.140340 0.547874 0.510751 +v -0.137616 0.761332 0.565444 +v -0.171541 0.824578 0.571704 +v 0.141139 1.293000 0.192768 +v 0.430312 0.701971 -0.025536 +v -0.154619 0.717659 0.551229 +v -0.149920 0.818131 0.571737 +v -0.159220 1.002300 0.448652 +v -0.175528 1.153870 0.379820 +v 0.456619 0.575388 0.317534 +v -0.158544 0.455582 0.504207 +v -0.134613 0.480924 0.483957 +v -0.187068 0.480345 0.490723 +v -0.106581 0.731430 0.566357 +v -0.125816 0.852912 0.573216 +v -0.153285 1.084100 0.420666 +v -0.105773 1.238480 0.326539 +v 0.246544 1.104750 0.368756 +v 0.465888 0.624864 0.298545 +v -0.131770 0.711258 0.553058 +v -0.108725 0.920578 0.561915 +v -0.057841 0.800275 0.579808 +v -0.107950 1.270050 0.273822 +v -0.000396 0.542534 0.541620 +v -0.048944 0.653144 0.562979 +v -0.013324 0.808490 0.576642 +v -0.116266 0.505652 0.498241 +v -0.094996 0.545254 0.525704 +v 0.035031 1.308240 0.211345 +v -0.133494 0.891060 0.568137 +v -0.068954 1.037720 0.438043 +v -0.119156 1.053550 0.432733 +v -0.914316 1.451950 0.222895 +v -0.084523 0.955099 0.543659 +v -0.115448 1.095570 0.424010 +v -0.130225 1.142470 0.399745 +v -0.007651 0.577932 0.546973 +v -0.033141 0.608642 0.556245 +v -0.011535 0.480302 0.499671 +v 0.014562 0.831535 0.572791 +v 0.035528 0.870046 0.566886 +v 0.107054 1.215080 0.348799 +v -0.067157 0.473307 0.484777 +v -0.559862 0.479226 0.386686 +v -0.088235 0.844802 0.575452 +v -0.105684 0.883233 0.570434 +v -0.087245 1.070690 0.434242 +v 0.058729 0.836217 0.564791 +v -0.122513 0.580213 0.531023 +v -0.077588 0.741988 0.578118 +v -0.111049 0.804881 0.575715 +v -0.079236 1.114460 0.422005 +v -0.067462 1.215470 0.360693 +v -0.051400 1.245950 0.330522 +v 0.513852 0.611500 0.297019 +v 0.524012 0.643018 0.283156 +v -0.066717 0.888358 0.570313 +v -0.563871 1.411480 -0.027535 +v -0.085893 0.602129 0.548977 +v -0.097782 0.688692 0.557557 +v -0.716476 1.498910 -0.397120 +v -0.052807 0.575823 0.543694 +v -0.092529 0.764144 0.576557 +v -0.028394 0.848652 0.573802 +v -0.874356 1.052670 0.143785 +v -0.374990 1.726200 -0.006046 +v 0.201582 0.999627 0.459571 +v -0.630500 1.439480 -0.079704 +v 0.397267 0.654828 0.319890 +v 0.548697 0.587044 0.272640 +v 0.524441 0.534637 0.275549 +v 0.191305 0.521295 0.453477 +v -0.402884 1.643130 0.031595 +v -0.440348 1.620230 0.057504 +v 0.269297 0.601076 -0.220792 +v 0.313109 0.613005 -0.178715 +v 0.448597 0.810284 0.005197 +v 0.448651 0.842093 0.004941 +v 0.157870 0.671878 0.515799 +v -0.503257 1.405330 0.166942 +v 0.076951 1.126320 0.400883 +v 0.154113 0.566594 0.495841 +v -0.266523 0.365656 0.534074 +v -0.690881 1.341230 0.479774 +v 0.202219 1.184380 0.339847 +v 0.334371 0.984850 0.375028 +v 0.190389 0.556262 0.476220 +v 0.178784 0.591412 0.488937 +v -0.297948 1.645640 -0.055442 +v 0.518032 0.487206 0.240641 +v -0.680157 1.276710 0.500522 +v 0.434068 0.662780 0.272865 +v -0.302459 1.673300 -0.068383 +v -0.654305 1.170490 0.480601 +v -0.665691 1.200500 0.509809 +v -0.673405 1.405880 0.437391 +v -0.660723 1.238530 0.500250 +v 0.366458 0.670350 0.368673 +v -0.383601 0.995891 -0.220079 +v -0.333920 0.952871 -0.235474 +v -0.641786 1.156690 0.434108 +v 0.593479 0.602321 0.056269 +v 0.566060 0.669778 0.242291 +v 0.355948 0.734285 0.382719 +v 0.537394 0.615905 0.283749 +v -0.671267 1.142500 0.471083 +v -0.661820 1.330210 0.447741 +v 0.248462 0.639455 0.450922 +v -0.641106 1.226730 0.476306 +v -0.647406 1.392540 0.403797 +v -0.226819 1.059590 -0.223702 +v 0.189564 0.756350 0.518380 +v -0.136526 1.780740 -0.210883 +v 0.505229 0.574754 0.302770 +v -0.629284 1.195310 0.450503 +v -0.630036 1.297670 0.421263 +v -0.639694 1.092160 0.380888 +v -0.646426 1.266530 0.466035 +v -0.663186 1.131430 0.427255 +v -0.639427 1.132180 0.392126 +v 0.259732 0.516155 0.398872 +v 0.236265 0.484026 -0.202602 +v 0.226991 0.452821 -0.175605 +v -0.637057 1.346520 0.397710 +v -0.609036 1.358070 0.362029 +v 0.246570 0.544994 0.426230 +v 0.380083 0.652277 0.349104 +v 0.379407 0.620339 0.338367 +v 0.306115 0.521831 0.369588 +v -0.607033 1.453210 0.363102 +v 0.260905 1.010270 0.417135 +v 0.196864 0.966982 0.472867 +v 0.236817 0.948133 0.463512 +v -0.574052 1.236160 0.399473 +v -0.614393 1.241180 0.432597 +v -0.774530 1.454110 0.432536 +v -0.749567 1.494180 0.392379 +v 0.203951 0.596431 0.478545 +v -0.218338 1.587760 -0.042487 +v -0.612141 1.165750 0.397729 +v -0.220075 1.744940 -0.140396 +v -0.248134 1.764640 -0.109288 +v 0.164812 1.193850 0.346410 +v -0.599848 1.434240 0.351416 +v -0.619505 1.418910 0.368642 +v -0.424614 1.488440 -0.026850 +v -0.406588 1.503310 0.038085 +v -0.169893 1.632520 -0.091026 +v -0.588417 1.198610 0.401122 +v -0.592348 1.279880 0.399872 +v -0.609549 1.323440 0.384916 +v -0.621490 1.383250 0.365839 +v -0.596012 1.380870 0.342646 +v 0.581730 0.639140 0.032299 +v -0.378708 1.530210 -0.074359 +v -0.280202 1.576020 -0.110508 +v -0.565380 1.261950 0.388879 +v -0.584110 1.458710 0.337354 +v -0.457605 0.443549 0.424799 +v -0.582176 1.321620 0.369228 +v -0.609168 1.529000 0.327543 +v 0.188096 0.439069 0.427566 +v -0.722350 1.307260 0.514844 +v -0.195805 1.688710 -0.131440 +v 0.219418 0.541900 0.448169 +v 0.221477 0.614260 0.469142 +v -0.554546 1.294750 0.364960 +v -0.462509 0.399326 0.447512 +v 0.152740 0.761956 0.535774 +v 0.288235 0.432648 0.323860 +v 0.337265 1.065520 0.321611 +v 0.332206 1.113960 0.289566 +v 0.333190 0.672923 0.397674 +v 0.200699 0.704003 0.498246 +v 0.204008 0.643741 0.480344 +v -0.558942 1.184920 0.371865 +v -0.571420 1.164730 0.368614 +v -0.547602 1.206800 0.372507 +v 0.386286 0.866533 0.349716 +v 0.418901 0.782830 0.297004 +v 0.235742 0.583252 0.454657 +v -0.541284 1.242470 0.371551 +v -0.547657 1.462480 0.281432 +v -0.565001 1.451160 0.311290 +v -0.336376 1.660830 -0.038537 +v 0.121615 0.930994 0.517375 +v -0.301002 1.729080 -0.058053 +v 0.171516 0.491809 0.442450 +v 0.213976 0.804943 0.504784 +v -0.171839 1.743410 -0.172399 +v -0.216039 1.836170 -0.128437 +v -0.508434 1.215440 0.333344 +v -0.566839 1.364350 0.330630 +v -0.586682 1.413030 0.332394 +v 0.294554 0.700480 0.421689 +v 0.151653 0.926431 0.502851 +v 0.259566 0.888700 0.463468 +v -0.539019 1.140040 0.352962 +v 0.397146 1.072270 0.137989 +v 0.170543 0.723196 0.520725 +v 0.214695 0.912417 0.480240 +v 0.241001 0.847584 0.481791 +v -0.184116 1.795680 -0.171029 +v -0.492336 1.249710 0.309648 +v -0.495544 1.293020 0.298785 +v -0.516999 1.266200 0.339425 +v -0.526947 1.324720 0.319774 +v -0.309402 1.575010 0.014702 +v 0.261429 0.748287 0.461060 +v -0.532322 1.179470 0.348104 +v -0.192730 1.612450 -0.061289 +v 0.355648 0.622454 0.372314 +v 0.325639 0.612949 0.397346 +v 0.283924 0.873738 0.447007 +v 0.205944 1.034470 0.433982 +v -0.561221 1.488230 0.304529 +v -0.699880 1.182020 0.526585 +v -0.164970 1.238940 0.293274 +v -0.665650 1.524780 -0.447219 +v -0.668394 1.533850 -0.480048 +v -0.910231 1.413120 0.216856 +v 0.256002 0.697466 0.448387 +v 0.288314 0.656274 0.425247 +v -0.482788 1.221240 0.298134 +v 0.373437 1.063870 0.268646 +v 0.157230 0.882481 0.513378 +v 0.288850 0.921218 0.438343 +v 0.301421 0.990545 0.401282 +v -0.184985 1.844090 -0.166255 +v 0.279012 0.836380 0.454456 +v -0.653515 1.511270 -0.360100 +v -0.298817 1.702560 -0.073142 +v 0.099608 0.594054 0.528571 +v 0.147937 0.609529 0.506414 +v 0.124750 0.635088 0.525813 +v 0.410664 0.909452 0.300063 +v 0.292262 0.740237 0.432992 +v -0.754021 1.001600 -0.117424 +v 0.297143 0.380280 -0.007602 +v 0.043851 0.419360 0.460348 +v -0.253684 1.697060 -0.107545 +v 0.453032 0.447603 0.257665 +v -0.859315 0.803740 0.111846 +v -0.865036 0.820302 0.144352 +v -0.871511 0.842367 0.132206 +v 0.294431 1.064070 0.363709 +v 0.290312 1.121410 0.331090 +v 0.303151 0.623066 0.414244 +v -0.529277 0.677013 -0.127514 +v 0.273032 0.611067 0.432859 +v -0.264780 1.574130 -0.013470 +v -0.198582 1.593070 -0.115298 +v 0.338010 0.511469 0.330048 +v 0.320606 0.944447 0.409127 +v -0.689894 1.436540 -0.137423 +v -0.657439 1.454050 -0.178649 +v -0.190986 1.763770 -0.164837 +v 0.461922 0.792631 0.134788 +v 0.468057 0.752742 0.087712 +v -0.257975 0.423606 0.534303 +v 0.223368 0.410617 -0.099862 +v -0.320186 1.595150 0.013400 +v 0.120823 0.708438 0.541637 +v 0.080526 0.720413 0.556725 +v -0.655677 1.529700 0.341306 +v 0.561989 0.535262 0.229563 +v 0.592633 0.628143 0.213335 +v 0.576131 0.602648 0.241537 +v 0.293858 0.967886 0.418841 +v 0.588969 0.554520 0.182856 +v -0.358152 1.672150 -0.009794 +v 0.603269 0.673147 0.113412 +v -0.490459 1.495680 0.112518 +v -0.522674 1.536460 0.131800 +v -0.521815 1.503320 0.169100 +v 0.306133 0.789152 0.433788 +v -0.141866 1.665650 -0.136767 +v 0.067374 1.210310 0.360146 +v 0.073182 1.167630 0.385329 +v -0.224174 0.374094 0.538512 +v -0.176270 0.388361 0.527466 +v 0.147884 0.800653 0.535130 +v 0.424537 0.698453 0.278033 +v 0.309495 0.756262 0.425430 +v 0.575400 0.557670 0.040823 +v -0.135802 0.419128 0.510519 +v 0.330493 0.896888 0.414704 +v -0.505697 1.375730 0.019336 +v 0.591694 0.557843 0.093657 +v 0.568999 0.634513 0.252441 +v -0.819602 0.747101 0.165171 +v 0.383981 0.757903 0.351642 +v 0.479787 0.450937 0.016087 +v 0.468897 0.548422 0.317417 +v -0.623236 1.718250 -0.525504 +v -0.461641 1.538660 0.087323 +v 0.130534 0.837332 0.535497 +v 0.394488 0.703127 0.332958 +v 0.288275 0.569814 0.408936 +v 0.104673 0.668701 0.543263 +v 0.095276 0.629102 0.540984 +v 0.300879 0.851745 0.436687 +v 0.151324 0.458570 0.439926 +v 0.114798 0.475580 0.466622 +v -0.596248 1.132190 0.369364 +v 0.117772 0.561116 0.514112 +v -0.510280 1.451770 0.150617 +v 0.144250 0.723877 0.533284 +v 0.359056 0.845099 0.386376 +v 0.330834 0.848268 0.415515 +v -0.878195 0.941928 0.243149 +v -0.267162 1.595910 -0.007278 +v -0.220750 1.626570 -0.059512 +v -0.286309 1.616500 -0.023729 +v -0.232664 1.610030 -0.034535 +v -0.211060 1.814880 -0.136297 +v 0.110674 0.765505 0.549026 +v -0.452003 1.472450 0.053570 +v 0.426497 0.981467 0.002039 +v 0.325363 0.739846 0.409431 +v 0.430535 0.935199 -0.027352 +v -0.624315 1.648360 -0.595102 +v -0.318951 0.470859 -0.248862 +v 0.360730 0.797979 0.382754 +v 0.364351 0.999632 0.330332 +v 0.549424 0.516301 0.026226 +v 0.530710 0.476800 0.054155 +v 0.126426 0.429507 0.446812 +v 0.352056 0.872376 0.395410 +v 0.430422 1.004700 0.107245 +v 0.404742 1.059740 0.075012 +v -0.444671 1.507050 0.073015 +v -0.437913 1.582680 0.062176 +v 0.398211 0.769793 -0.097012 +v 0.255326 1.058830 0.389675 +v 0.355785 0.919737 0.382714 +v 0.387437 0.945105 0.327252 +v 0.483726 0.491888 0.282236 +v 0.437610 0.479678 0.305170 +v -0.834467 1.525020 0.077304 +v -0.392882 1.540190 0.049522 +v -0.703383 1.254200 -0.087343 +v 0.211114 0.480861 0.414487 +v 0.097515 0.492283 0.491971 +v -0.366415 1.574430 0.037896 +v -0.419465 1.554480 0.063064 +v -0.407079 1.579960 0.045188 +v -0.362345 1.600800 0.013746 +v 0.140272 0.520943 0.484972 +v -0.037075 0.423094 0.476447 +v 0.099256 0.851193 0.550451 +v 0.123880 0.890551 0.533378 +v -0.208054 1.649560 -0.092911 +v 0.222255 0.514918 0.423691 +v 0.227402 0.750775 0.491796 +v 0.231069 0.707068 0.474422 +v 0.241691 0.984656 0.445871 +v -0.226381 1.613690 -0.145479 +v -0.351172 1.543790 0.024192 +v -0.090090 1.761230 -0.271562 +v -0.101627 1.787060 -0.289401 +v -0.371365 1.691490 0.009437 +v -0.170761 0.362175 0.518285 +v -0.142368 1.618550 -0.137869 +v 0.062172 0.607620 0.548736 +v -0.482747 1.456810 0.083452 +v -0.475771 1.446900 0.044225 +v -0.405084 1.602640 0.032142 +v -0.367804 1.629150 -0.003539 +v 0.549804 0.650657 0.266122 +v -0.203732 0.437248 0.528214 +v -0.224544 0.462871 0.515622 +v -0.356322 0.532320 -0.104439 +v -0.776583 1.626100 -0.213270 +v 0.360060 0.574556 0.342341 +v -0.138412 1.630800 -0.120153 +v 0.563633 0.567700 0.247787 +v -0.120193 1.716940 -0.190210 +v 0.176509 0.793537 0.526053 +v 0.270215 0.676226 0.435310 +v 0.331312 0.580110 0.380046 +v -0.869790 1.087210 0.132694 +v 0.256512 0.793316 0.475188 +v 0.367202 0.708048 0.368888 +v 0.088155 1.106010 0.402796 +v -0.517895 0.856139 -0.217230 +v -0.497247 0.899879 -0.219948 +v 0.291277 1.026590 0.386223 +v 0.189798 0.406457 0.427805 +v 0.226733 0.433217 0.406365 +v -0.514143 0.388392 0.464448 +v -0.008276 1.020230 0.444359 +v 0.249329 0.471182 0.392961 +v -0.623805 1.530830 -0.284469 +v -0.214360 1.576730 -0.072624 +v -0.903951 1.360330 0.138990 +v -0.892059 1.355520 0.078125 +v -0.628452 0.393344 0.429073 +v -0.854923 1.108330 0.246475 +v -0.884498 0.996813 0.088484 +v -0.862926 1.077770 0.190571 +v -0.935606 1.243070 0.260903 +v 0.382301 0.384580 0.043007 +v -0.929529 1.292910 0.243875 +v 0.557878 0.631565 0.003852 +v -0.410867 0.341324 0.336029 +v -0.937945 1.184900 0.186283 +v -0.090388 1.696240 -0.231905 +v -0.542960 0.462876 0.235313 +v -0.623102 1.560850 -0.340780 +v 0.186410 0.383951 -0.169775 +v -0.690718 1.376470 -0.079107 +v -0.703121 1.415640 -0.090700 +v -0.620206 1.598110 -0.253569 +v -0.437849 1.471760 0.017857 +v -0.087323 1.725640 -0.259912 +v -0.622863 1.515820 -0.140030 +v 0.262820 0.543591 -0.212261 +v -0.871330 0.859279 0.207994 +v -0.644757 1.537470 -0.400978 +v 0.411638 0.884338 -0.094819 +v -0.631127 1.646750 -0.331961 +v 0.530124 0.464760 0.112096 +v -0.602871 0.335154 -0.079336 +v 0.215545 0.418979 -0.146614 +v 0.304139 0.761933 -0.207792 +v 0.367603 1.009350 -0.095240 +v -0.504415 0.532606 0.174936 +v 0.351151 0.435609 0.292876 +v -0.904371 1.212510 0.048218 +v -0.902208 1.135000 0.107035 +v 0.363956 0.763984 -0.140933 +v -0.886218 0.952019 0.078204 +v -0.913294 1.238630 0.067851 +v -0.927390 1.176800 0.118919 +v -0.897470 1.164290 0.054991 +v -0.837439 1.072490 0.255993 +v -0.119762 1.764420 -0.288304 +v 0.380509 0.800457 -0.131526 +v -0.107210 0.973322 0.518020 +v 0.219540 0.402086 0.403007 +v -0.115684 1.647030 -0.155474 +v 0.453243 0.868147 0.027112 +v 0.391552 0.849073 -0.129895 +v 0.421381 0.856348 -0.077525 +v 0.294044 0.523457 -0.162854 +v -0.904965 1.417410 0.258638 +v -0.898142 1.424320 0.305653 +v -0.623592 1.561740 -0.171447 +v -0.641319 0.790097 0.422193 +v 0.267871 0.447936 0.369401 +v -0.885104 1.386140 0.098432 +v -0.796767 1.037220 -0.064741 +v 0.395202 0.680075 -0.096994 +v 0.406374 0.657948 -0.063016 +v -0.919749 1.267560 0.086503 +v 0.276827 0.475491 -0.126455 +v 0.293624 0.498798 -0.133479 +v -0.862793 0.824484 0.178290 +v -0.092678 1.733290 -0.235461 +v -0.623140 1.517400 -0.228970 +v -0.616480 1.561830 -0.270011 +v -0.879616 0.877399 0.056440 +v 0.350109 0.595092 -0.124875 +v 0.283577 0.539245 -0.187004 +v 0.248593 0.446806 -0.119547 +v -0.258024 1.562230 -0.077287 +v -0.876639 0.859160 0.164750 +v 0.346086 0.634527 -0.150344 +v -0.914952 1.428830 0.182443 +v -0.867108 1.423920 0.076307 +v -0.887418 1.464110 0.104619 +v -0.194278 0.927982 -0.346487 +v -0.180218 0.901929 -0.368959 +v 0.405588 0.980447 -0.050241 +v -0.276703 0.989897 -0.237534 +v -0.784449 1.190490 0.509582 +v -0.147672 1.022590 -0.234258 +v 0.259044 0.385094 0.296426 +v -0.488067 1.369270 0.067694 +v -0.490238 1.363870 0.197032 +v 0.373386 1.036960 -0.066751 +v -0.523156 0.460753 0.174295 +v -0.528025 0.473216 0.147836 +v 0.300854 0.567872 -0.174465 +v 0.523420 0.651918 -0.005219 +v 0.293510 0.719923 -0.214233 +v 0.407344 1.041420 0.023617 +v 0.252754 0.427450 -0.074083 +v 0.200034 0.382917 -0.119083 +v -0.625581 0.450605 0.341634 +v 0.436134 0.889400 -0.037169 +v -0.439120 0.456641 -0.121671 +v 0.333395 0.730367 -0.174148 +v 0.109250 0.362848 -0.219722 +v 0.061712 0.340967 -0.202907 +v 0.419776 0.813808 -0.071551 +v 0.444298 0.931027 0.016251 +v -0.876630 1.129660 0.058632 +v -0.423757 0.343956 -0.262511 +v -0.867651 1.096350 0.084493 +v 0.298373 0.681028 -0.201941 +v -0.901445 1.487960 0.132623 +v -0.611187 1.678230 -0.574996 +v -0.732977 1.531470 -0.350721 +v -0.735648 1.501380 -0.340154 +v -0.623672 1.641680 -0.416399 +v -0.519810 0.483439 0.218191 +v -0.908068 1.421540 0.153250 +v -0.895135 1.434240 0.123705 +v 0.428984 0.755036 -0.043247 +v -0.860208 1.472850 0.069078 +v -0.618599 1.602830 -0.339035 +v -0.169217 1.602290 -0.090722 +v -0.627791 1.589030 -0.426825 +v 0.266871 0.480859 -0.162011 +v -0.920968 1.164730 0.361659 +v -0.641064 1.489470 -0.255648 +v 0.391254 1.001310 0.287825 +v 0.377838 0.642287 -0.110216 +v 0.355932 0.681604 -0.148558 +v -0.551993 1.421480 0.294142 +v 0.371709 0.733655 -0.130122 +v 0.399321 0.722216 -0.095794 +v 0.015025 0.367108 -0.146412 +v -0.877011 0.917517 0.046035 +v 0.409477 0.954791 0.282522 +v 0.218961 0.383412 -0.061966 +v 0.206668 0.361554 -0.045747 +v -0.336886 1.573490 -0.112943 +v -0.280535 1.621560 -0.149009 +v -0.060845 0.919116 -0.352800 +v 0.321510 0.535009 -0.117516 +v -0.617686 1.679420 -0.524052 +v -0.908660 1.393050 0.177441 +v -0.628319 1.685180 -0.466822 +v -0.097144 1.741620 -0.281716 +v 0.425424 0.862105 0.282720 +v 0.426088 0.923804 0.261883 +v 0.415717 0.992984 0.236437 +v 0.560608 0.495167 0.148787 +v -0.354736 0.805957 -0.227708 +v -0.510568 1.383180 0.226312 +v -0.532516 1.441870 0.241985 +v -0.529901 1.383330 0.274402 +v -0.361914 1.518240 0.008349 +v 0.319048 0.648319 -0.180971 +v -0.815697 0.779181 0.265329 +v -0.524434 1.468440 0.199224 +v 0.415936 0.702475 -0.063418 +v -0.848289 0.812910 0.221487 +v -0.502188 1.343790 0.264777 +v -0.853028 0.846218 0.252094 +v 0.441949 0.905257 0.223306 +v 0.437022 0.968982 0.171925 +v 0.416422 1.025980 0.170099 +v -0.382602 0.839389 -0.217540 +v -0.370739 0.852320 -0.227155 +v 0.602461 0.652089 0.181209 +v -0.135351 1.838320 -0.272343 +v 0.207174 0.861940 0.495335 +v -0.110831 1.664750 -0.212725 +v -0.108668 1.796070 -0.251829 +v 0.432575 0.993394 0.048628 +v 0.560902 0.506412 0.194972 +v 0.587732 0.582538 0.212001 +v 0.454137 0.832449 0.192831 +v -0.357713 0.765192 -0.200484 +v -0.519883 1.417330 0.208917 +v 0.605235 0.611042 0.164885 +v 0.431369 0.418010 0.019083 +v 0.583235 0.529988 0.146767 +v 0.457212 0.869147 0.137580 +v 0.459029 0.867702 0.085681 +v 0.390149 1.070210 0.206351 +v 0.607490 0.620083 0.104988 +v 0.600077 0.572831 0.137668 +v -0.678475 1.740150 -0.444538 +v -0.667334 1.577160 -0.080315 +v -0.464624 0.349697 0.429488 +v -0.724297 1.782670 -0.474533 +v -0.648323 1.780260 -0.543786 +v -0.645389 1.733900 -0.488908 +v 0.545067 0.680137 0.251228 +v 0.568686 0.691876 0.220835 +v -0.636044 1.636790 -0.266271 +v -0.468113 1.331170 0.084337 +v 0.587401 0.680180 0.064909 +v -0.660409 1.491270 0.387734 +v 0.542198 0.711262 0.217409 +v 0.583272 0.711498 0.128986 +v 0.392016 0.443846 0.293565 +v 0.547263 0.731599 0.149470 +v 0.563465 0.722191 0.173364 +v 0.506092 0.719856 0.204606 +v 0.569004 0.712043 0.081018 +v 0.515815 0.731959 0.168019 +v 0.536904 0.728548 0.183804 +v 0.515465 0.728611 0.096416 +v 0.550225 0.727501 0.107544 +v 0.515482 0.733389 0.133692 +v 0.495473 0.696847 0.240931 +v 0.462648 0.697456 0.237184 +v 0.483559 0.727560 0.178172 +v -0.851337 1.534060 0.214334 +v -0.884716 1.112460 0.129647 +v 0.481243 0.739781 0.124920 +v -0.287862 1.768460 -0.059401 +v -0.934361 1.271560 0.142552 +v -0.385142 1.075160 -0.197899 +v 0.461468 0.755135 0.181861 +v -0.565772 1.525710 0.287524 +v -0.595864 1.494880 0.347642 +v -0.341438 1.756930 -0.031889 +v -0.546238 1.530210 0.216771 +v -0.630422 1.776910 -0.602506 +v -0.723285 1.589550 -0.059365 +v -0.793481 1.514610 0.339600 +v -0.789152 1.489660 0.383027 +v -0.629394 0.397451 0.250165 +v -0.508762 1.609500 0.069390 +v -0.552613 1.587000 0.076449 +v -0.540561 1.557980 0.120083 +v -0.781425 1.556090 0.165241 +v -0.578700 1.551690 0.201516 +v -0.598387 1.548970 0.265831 +v -0.731925 1.545960 0.294673 +v -0.839761 1.536800 0.125336 +v -0.821957 1.546130 0.194115 +v -0.854003 1.520860 0.262462 +v -0.154005 1.286890 0.161266 +v -0.305039 1.250450 0.010019 +v -0.744380 1.734290 -0.375869 +v -0.750782 1.706190 -0.314488 +v -0.662726 1.553410 0.064832 +v -0.685851 1.719480 -0.380923 +v -0.641287 1.792730 -0.579200 +v -0.639551 1.612270 -0.196125 +v -0.667564 1.616840 -0.144427 +v -0.693444 1.650920 -0.178434 +v -0.356329 1.247430 0.221334 +v -0.939955 1.215430 0.234316 +v -0.114154 1.820790 -0.277682 +v -0.605614 0.459269 0.391578 +v -0.511284 0.590707 0.310758 +v -0.359074 1.274820 0.097875 +v -0.346331 1.267010 0.032588 +v -0.624125 1.760920 -0.566381 +v -0.503317 1.574060 0.095096 +v -0.446974 1.269040 0.216690 +v -0.468293 1.260390 0.264147 +v 0.237662 1.158670 0.339907 +v -0.778608 1.535860 0.301542 +v -0.689762 1.557530 0.011828 +v -0.458066 1.295390 0.213064 +v -0.077755 1.304060 0.165771 +v -0.587938 1.568330 0.079688 +v -0.679945 1.548200 0.297279 +v -0.860891 0.807519 0.150593 +v -0.700670 1.533830 0.333693 +v -0.654852 1.557570 0.256247 +v -0.672445 1.561080 0.131854 +v -0.710301 1.557920 0.075904 +v -0.414916 1.288900 0.089395 +v -0.940320 1.261410 0.227230 +v -0.633047 1.544950 0.302084 +v -0.060006 1.012260 0.449971 +v -0.930337 1.302200 0.202223 +v -0.330207 1.249750 0.200750 +v -0.310007 1.262100 0.097039 +v -0.357024 1.217000 0.272767 +v -0.404716 1.222930 0.263857 +v -0.536594 1.532120 0.162144 +v -0.567217 1.541950 0.246141 +v -0.630845 1.541830 0.029521 +v -0.621447 1.558450 0.099514 +v -0.464473 1.328350 0.162774 +v -0.430612 1.281820 0.170601 +v -0.816597 1.523740 0.300751 +v -0.011202 1.058270 0.434113 +v -0.372717 1.270030 0.160869 +v -0.651318 0.417514 0.353372 +v -0.727513 1.561900 0.146451 +v -0.722565 1.560420 0.228377 +v -0.941310 1.264640 0.186249 +v -0.397246 1.255970 0.209180 +v -0.434744 1.248160 0.230365 +v -0.261750 0.845912 -0.366417 +v 0.442263 0.827037 0.246118 +v -0.771603 1.551480 0.088694 +v -0.554865 1.545170 0.166115 +v -0.129207 1.839430 -0.255187 +v -0.864847 1.008720 0.246440 +v 0.369085 1.108210 0.033820 +v 0.364192 1.124860 0.105939 +v -0.378957 1.240160 0.241462 +v -0.687381 1.572500 -0.041033 +v -0.787295 1.726600 -0.416819 +v -0.674876 1.563420 0.198318 +v -0.622584 1.559040 0.221470 +v -0.623362 1.560450 0.169973 +v 0.365886 1.117900 0.180330 +v 0.339743 1.150090 0.202073 +v -0.484421 1.371980 0.129834 +v -0.872180 1.504750 0.098511 +v -0.863450 1.531990 0.173529 +v -0.521549 0.555926 0.156914 +v -0.514492 0.520180 0.138614 +v -0.774651 1.551970 0.241599 +v -0.816295 1.538840 0.254452 +v -0.711257 1.749200 -0.420697 +v -0.493734 1.415150 0.053905 +v -0.495473 1.438120 0.012203 +v 0.375561 1.077740 -0.010227 +v 0.301224 1.158100 0.284406 +v -0.630375 0.413891 0.143674 +v 0.336434 1.159460 0.159611 +v -0.599885 0.418367 0.237845 +v -0.289396 1.802490 -0.077109 +v -0.656901 1.674150 -0.304203 +v 0.328269 1.165140 0.050520 +v 0.332060 1.166080 0.108565 +v 0.311840 1.182200 0.201892 +v 0.296480 1.185960 0.243994 +v 0.300865 1.184780 0.018360 +v 0.347850 1.117030 -0.015217 +v -0.711195 1.716420 -0.333619 +v -0.861591 1.047360 0.054274 +v -0.852237 1.018150 0.007841 +v -0.412213 1.282490 0.021976 +v -0.384886 1.279670 0.047397 +v -0.155980 1.270780 0.005573 +v -0.617489 0.440383 0.288037 +v -0.690547 1.790630 -0.583331 +v 0.285021 1.207950 0.056704 +v 0.264697 1.172270 0.309218 +v 0.264672 1.201330 0.270063 +v -0.254342 0.390826 0.542210 +v -0.450741 1.294680 0.023443 +v -0.482780 1.325610 0.025114 +v -0.240918 1.249560 0.001900 +v 0.009493 1.002170 0.471313 +v -0.021520 0.991975 0.497461 +v 0.295627 1.204110 0.127663 +v 0.235239 1.231660 0.251698 +v 0.266466 1.221680 0.208571 +v 0.185893 1.213970 0.321271 +v -0.704357 1.512690 0.371151 +v 0.308468 1.155910 -0.029051 +v 0.238014 1.248360 0.155432 +v -0.678402 1.673020 -0.248379 +v -0.664711 1.646690 -0.208209 +v 0.246482 1.241790 0.093885 +v 0.218023 1.253390 0.213374 +v 0.203705 1.246340 0.258591 +v 0.165561 1.223160 0.319969 +v -0.930540 1.198890 0.379018 +v -0.028365 1.005160 0.464901 +v -0.753335 1.792670 -0.517599 +v -0.703047 1.612810 -0.101666 +v -0.648595 1.556790 -0.482065 +v -0.736323 1.800050 -0.507623 +v 0.242533 1.237460 0.044661 +v -0.446900 1.307410 0.106697 +v -0.077393 0.996296 0.481846 +v 0.174742 1.270180 0.230447 +v 0.106928 1.261930 0.300102 +v 0.142152 1.231410 0.322670 +v -0.628922 1.522080 -0.103192 +v -0.373959 0.757377 -0.187319 +v -0.382099 1.039050 -0.208819 +v 0.168005 1.247080 0.288449 +v -0.113708 1.012660 0.447399 +v -0.355336 1.762350 -0.050992 +v 0.192119 1.269320 0.051748 +v -0.216381 1.271400 0.105993 +v -0.230792 1.262950 0.052133 +v -0.773184 1.735310 -0.402771 +v 0.188249 1.274990 0.175088 +v -0.887007 0.877563 0.152171 +v -0.543785 0.552739 0.108869 +v -0.855513 1.384100 0.029529 +v 0.215085 1.246310 0.012174 +v -0.648716 0.404113 0.388496 +v -0.785093 1.738260 -0.457979 +v -0.358455 0.468285 0.410017 +v -0.318634 0.496868 0.403453 +v -0.147474 1.038330 0.432207 +v -0.468946 0.517322 -0.097927 +v -0.140171 0.664244 0.542453 +v -0.104546 0.644807 0.551380 +v -0.580886 0.657501 -0.094429 +v -0.296215 0.853581 0.446412 +v -0.240364 0.721356 0.481360 +v -0.482873 0.609109 0.360017 +v -0.743367 1.634420 -0.153024 +v -0.760820 1.638580 -0.187996 +v -0.641739 1.283850 -0.083677 +v -0.215766 0.383496 0.046913 +v -0.311400 0.379168 -0.003284 +v -0.300988 0.884996 -0.287438 +v -0.471010 0.550799 0.369709 +v -0.445624 0.610592 0.392787 +v -0.538045 1.493120 0.246907 +v -0.691978 1.007660 -0.150494 +v -0.500641 0.555765 0.330081 +v -0.769282 1.661860 -0.251399 +v -0.245090 0.866214 0.525834 +v -0.271060 0.882505 0.476098 +v -0.486534 1.666910 -0.024721 +v -0.425820 1.717400 -0.041033 +v -0.773206 1.579080 -0.143681 +v -0.272573 0.800881 0.476552 +v -0.308003 1.660020 -0.161637 +v -0.324968 1.703550 -0.158696 +v -0.528821 0.591211 -0.079896 +v -0.250850 0.573945 0.398320 +v -0.243733 0.623037 0.419320 +v -0.239780 0.678367 0.452159 +v -0.550825 0.597164 0.241838 +v -0.561613 0.613721 0.268631 +v -0.601759 0.390752 0.453133 +v -0.158713 0.605657 0.521599 +v -0.124868 0.617596 0.541580 +v -0.463582 1.678210 0.010182 +v -0.184598 0.971993 0.473834 +v -0.194211 0.992443 0.448076 +v -0.249343 0.906987 0.491606 +v -0.211591 0.793644 0.555364 +v -0.226246 0.830914 0.552708 +v -0.242037 0.790655 0.528272 +v 0.243349 0.398253 0.357482 +v -0.224771 0.987605 0.445789 +v -0.645692 1.444300 -0.122109 +v -0.629778 1.477680 -0.143845 +v -0.599959 0.416306 0.444484 +v -0.253845 0.823684 0.522904 +v -0.201990 0.879659 0.555791 +v -0.842569 1.398040 0.442167 +v -0.825664 1.450300 0.406069 +v -0.707618 0.873735 0.419395 +v -0.709929 0.822706 0.406159 +v -0.714657 1.473860 -0.282118 +v 0.261365 1.210800 0.001082 +v -0.755337 1.601160 -0.113254 +v -0.859814 1.223070 0.486651 +v -0.735929 0.955197 0.398776 +v -0.924577 1.213920 0.414731 +v -0.367104 0.434626 0.430404 +v -0.669628 0.912906 -0.176831 +v -0.650950 0.938836 -0.179156 +v -0.663574 0.382233 0.300545 +v -0.183646 0.574296 0.492552 +v -0.417857 0.693624 0.417364 +v -0.824843 1.209790 0.497074 +v -0.841490 1.338480 0.485895 +v -0.571402 0.479603 0.367942 +v -0.362869 0.365840 0.456068 +v -0.341057 0.757665 -0.229746 +v -0.761710 0.770725 0.339299 +v -0.352860 0.393857 0.472062 +v -0.264622 1.744080 -0.189346 +v 0.347163 0.412206 -0.027669 +v -0.841927 1.195140 0.489098 +v -0.177884 0.773276 0.561435 +v -0.859059 1.279720 0.488044 +v -0.840010 1.293470 0.503856 +v -0.717264 0.920310 0.414887 +v 0.503831 0.669219 0.270688 +v -0.214045 0.688282 0.501141 +v -0.217925 0.743632 0.527501 +v -0.309048 0.444103 0.494215 +v -0.341994 0.444300 0.455756 +v -0.253114 0.761167 0.489787 +v -0.641098 0.408059 0.274820 +v 0.241243 0.928362 -0.222969 +v -0.507082 0.938555 -0.220471 +v -0.442398 0.926246 -0.223872 +v -0.541648 0.517883 0.103745 +v -0.713630 0.398393 0.062380 +v -0.767942 0.814674 0.361704 +v -0.144776 0.946720 0.538067 +v -0.704532 0.398888 0.085794 +v -0.885054 1.260810 0.464048 +v -0.344717 0.564675 -0.108386 +v -0.872582 1.313520 0.462482 +v -0.112147 1.673840 -0.167297 +v -0.874345 1.016150 0.218385 +v -0.270202 0.843436 0.491173 +v -0.666187 0.365273 0.341473 +v -0.663852 0.391253 0.338896 +v -0.650999 0.363431 0.393096 +v -0.323497 0.479845 0.429285 +v -0.692629 0.423833 0.068979 +v -0.814499 1.300830 0.519147 +v -0.292898 0.737084 0.409433 +v -0.395205 1.496560 0.012799 +v -0.247195 0.529660 0.412559 +v -0.600486 1.559880 0.044246 +v -0.714987 0.375885 0.084915 +v -0.333878 0.419567 0.486890 +v -0.857555 0.970904 0.274274 +v -0.637367 0.434584 0.373438 +v -0.516312 0.543685 0.288040 +v -0.532922 0.600785 0.273467 +v -0.783833 0.947435 0.361432 +v -0.754612 0.905896 0.391604 +v -0.268921 0.739164 0.439719 +v -0.865889 0.880786 0.250280 +v -0.667411 0.641008 -0.026633 +v -0.645898 0.619577 -0.002641 +v -0.277619 0.612013 0.378602 +v -0.750594 0.996915 0.374997 +v -0.768809 1.037050 0.350641 +v -0.677450 0.412618 0.105586 +v -0.694243 0.386060 0.108516 +v -0.860875 0.916651 0.272121 +v -0.829004 0.939926 0.315274 +v -0.388210 0.353726 0.427982 +v -0.805370 0.898530 0.342945 +v -0.204965 0.628999 0.483553 +v -0.806098 0.988119 0.330645 +v -0.879785 1.498030 0.272242 +v -0.690803 0.359649 0.120874 +v -0.175614 1.865660 -0.200346 +v -0.541570 0.492247 0.116633 +v -0.858337 1.426470 0.397948 +v -0.895142 1.466420 0.285029 +v -0.636698 1.520580 -0.326519 +v -0.608675 0.442569 0.121693 +v -0.617344 0.460401 0.084894 +v -0.655765 0.367573 -0.072915 +v -0.658712 0.400726 -0.053919 +v -0.838063 0.863692 0.294266 +v -0.803710 1.025250 0.320072 +v -0.784177 1.071950 0.336442 +v -0.777903 1.410300 -0.047006 +v -0.223369 0.910966 0.521247 +v -0.192929 0.945801 0.511179 +v -0.104562 1.031260 -0.234225 +v -0.390444 0.386248 0.436196 +v -0.370738 0.412040 0.442095 +v -0.386216 0.427992 0.420600 +v -0.919743 1.258240 0.401335 +v -0.448462 0.982497 -0.219898 +v -0.313179 0.475229 0.449361 +v -0.832089 1.223280 -0.039528 +v -0.832503 1.276120 -0.039715 +v 0.040664 0.340612 -0.179826 +v -0.864143 1.466000 0.344593 +v -0.699196 0.417783 0.033031 +v 0.266501 0.696011 -0.233794 +v 0.259308 0.663551 -0.232457 +v -0.638826 0.385197 0.164341 +v -0.603032 1.084860 -0.166234 +v -0.803489 0.848707 0.338567 +v -0.873526 1.372720 0.423601 +v -0.892289 1.380510 0.370794 +v -0.881409 1.429030 0.356979 +v -0.146266 0.976687 0.491941 +v -0.292381 0.519757 0.385698 +v -0.274091 0.552714 0.376692 +v -0.266395 0.930705 0.455369 +v -0.225964 0.948443 0.473604 +v -0.248960 0.964014 0.447416 +v -0.571736 0.462836 0.117196 +v -0.797907 1.354880 0.503891 +v -0.811422 1.398420 0.466596 +v -0.013579 1.169820 -0.164880 +v -0.909121 1.241840 0.438302 +v -0.832145 1.256360 0.507409 +v -0.320693 1.011840 -0.225469 +v -0.764428 0.858092 0.379295 +v -0.623647 0.385956 0.234563 +v -0.834461 1.497720 0.334332 +v -0.895116 1.201870 0.458901 +v -0.897756 1.299780 0.427547 +v -0.030525 1.292780 -0.007913 +v -0.745795 1.144910 0.505685 +v 0.560881 0.700020 0.050310 +v 0.065420 0.975343 -0.253766 +v -0.519532 0.560449 0.257521 +v -0.609488 0.399618 -0.081188 +v -0.258110 0.531531 -0.269674 +v -0.723094 1.734840 -0.519790 +v -0.701428 1.595720 -0.489283 +v -0.713562 1.629000 -0.444529 +v -0.706854 1.686860 -0.503563 +v -0.772054 1.767380 -0.498348 +v -0.747627 1.726440 -0.485578 +v -0.929380 1.230140 0.375284 +v -0.765541 1.772440 -0.463248 +v -0.769048 1.740400 -0.485379 +v -0.904075 1.322310 0.369106 +v -0.712825 1.549870 -0.454538 +v -0.740499 1.688280 -0.447807 +v -0.772195 1.706470 -0.441591 +v -0.738226 1.643710 -0.394549 +v -0.351868 0.665916 -0.157045 +v -0.772064 1.662150 -0.375693 +v -0.789631 1.684270 -0.368185 +v -0.787953 1.702270 -0.412185 +v -0.579481 0.487620 0.072873 +v -0.595258 0.436541 -0.059914 +v -0.718158 1.570320 -0.410599 +v -0.334360 1.127070 -0.171918 +v -0.725329 1.524150 -0.405101 +v -0.313550 0.808537 -0.317292 +v 0.364686 0.941050 -0.126725 +v 0.354934 0.913111 -0.153373 +v -0.288530 0.686800 -0.309996 +v -0.292823 0.720950 -0.325340 +v -0.779211 1.688040 -0.326633 +v 0.066976 1.180230 -0.161099 +v -0.300623 0.682153 -0.285081 +v -0.330665 0.774635 -0.276174 +v -0.310926 0.766147 -0.319534 +v -0.310347 0.845219 -0.306709 +v -0.292709 0.854339 -0.332695 +v -0.783098 1.641930 -0.314161 +v -0.784350 1.642300 -0.274830 +v 0.107471 1.004150 -0.222040 +v -0.019772 1.224890 -0.111910 +v -0.271631 0.663482 -0.319023 +v -0.586408 0.474554 0.349160 +v -0.578480 0.472147 0.309419 +v -0.916935 1.171970 0.303134 +v -0.927020 1.189120 0.262045 +v 0.108336 0.980581 -0.235539 +v -0.887817 0.971751 0.209140 +v -0.736435 1.609410 -0.348472 +v 0.009883 1.201790 -0.138287 +v -0.283819 0.624304 -0.277965 +v -0.507220 0.501687 0.198914 +v -0.650727 0.416336 0.315429 +v 0.005264 0.990460 -0.248897 +v -0.314145 0.733493 -0.295603 +v -0.728695 1.580830 -0.342145 +v -0.435676 0.373001 -0.249126 +v -0.835269 1.026140 0.282169 +v -0.296423 0.581594 -0.212535 +v -0.287079 0.594148 -0.249395 +v -0.325458 0.830265 -0.282675 +v -0.326216 0.886738 -0.254369 +v -0.858486 1.044430 0.229530 +v -0.816205 1.087810 0.295748 +v -0.324626 0.719082 -0.252541 +v -0.337879 0.808692 -0.260052 +v -0.437014 1.692700 -0.074910 +v -0.778892 1.601340 -0.233779 +v -0.293054 0.515548 -0.220532 +v -0.626102 1.483500 -0.095534 +v -0.041747 0.347521 -0.239465 +v -0.746340 1.513700 -0.279265 +v 0.082921 1.270780 -0.049363 +v 0.090281 1.242910 -0.089777 +v -0.058891 1.117130 -0.204035 +v -0.446077 0.393623 -0.213499 +v -0.280305 0.553858 -0.243130 +v -0.738948 1.475080 -0.202238 +v -0.742456 1.569030 -0.266062 +v -0.310520 0.650338 -0.227606 +v -0.336326 0.715837 -0.209561 +v -0.750170 1.529730 -0.200228 +v -0.736598 1.545020 -0.291482 +v -0.758332 1.602260 -0.288072 +v -0.655715 0.440565 0.090738 +v -0.173901 0.336722 -0.245564 +v -0.760066 1.573370 -0.229156 +v -0.420612 0.430960 -0.213881 +v -0.146061 1.681850 -0.223902 +v -0.159876 1.632480 -0.170804 +v -0.573510 0.459135 0.270018 +v -0.530716 0.502133 0.293342 +v -0.441281 0.418333 -0.185343 +v -0.354523 0.717241 -0.181509 +v -0.319937 0.610948 -0.163261 +v -0.332568 0.671431 -0.184589 +v -0.277506 1.039910 -0.226227 +v -0.895931 1.361950 0.304233 +v -0.897687 1.357070 0.267717 +v -0.463661 0.379598 -0.172228 +v 0.260131 1.156560 -0.085292 +v 0.257990 1.119810 -0.117384 +v 0.212269 1.151980 -0.123731 +v -0.413222 0.344057 0.395086 +v -0.468708 0.343305 0.380091 +v -0.840130 1.110620 0.292643 +v -0.752955 1.518300 -0.213330 +v -0.722096 0.377302 0.043995 +v -0.928890 1.214760 0.333618 +v -0.930973 1.178710 0.223824 +v -0.893803 1.511830 0.157336 +v -0.883298 1.518220 0.210084 +v -0.304168 0.527359 -0.174362 +v 0.059559 1.001760 -0.225901 +v -0.505971 0.490076 0.170086 +v -0.519972 0.465893 0.196639 +v -0.561254 0.433314 0.179466 +v -0.756360 1.526070 -0.163465 +v -0.766624 1.559450 -0.186668 +v -0.750111 1.546140 -0.207668 +v -0.802564 1.055840 0.310435 +v -0.303006 0.560059 -0.181368 +v 0.537866 0.717875 0.068662 +v 0.211649 1.100330 -0.152936 +v -0.529950 0.572426 0.210082 +v -0.511421 0.536794 0.212383 +v -0.775478 1.572150 -0.175100 +v -0.314653 0.521971 -0.141406 +v -0.320714 0.497103 -0.179252 +v -0.321775 0.567187 -0.125330 +v -0.309702 0.556911 -0.151654 +v 0.250926 1.085250 -0.143597 +v 0.235997 1.035520 -0.180781 +v -0.739018 0.796480 -0.130731 +v -0.740139 0.844672 -0.147101 +v -0.117790 0.977555 -0.280072 +v -0.918381 1.314960 0.251333 +v -0.434446 0.373413 0.440246 +v -0.466577 0.391255 -0.143895 +v -0.906563 1.323550 0.299126 +v 0.031429 0.376499 -0.020501 +v -0.004380 0.371779 0.050151 +v -0.920835 1.321230 0.159351 +v -0.915225 1.316970 0.108189 +v 0.453848 0.722505 0.221966 +v 0.444929 0.764334 0.235761 +v -0.898728 1.384790 0.251607 +v -0.905643 1.385870 0.213704 +v -0.736796 1.437740 0.451863 +v -0.759707 0.901026 -0.135708 +v -0.285446 1.141460 -0.162042 +v -0.707472 1.446000 -0.166918 +v -0.834813 1.503550 0.049288 +v -0.897309 1.396130 0.292124 +v -0.780177 0.870885 -0.114279 +v 0.293786 1.025850 -0.153948 +v -0.881820 0.864031 0.097136 +v -0.885974 0.908108 0.215220 +v -0.806192 0.978415 -0.078333 +v -0.928945 1.221540 0.105544 +v -0.879862 1.026690 0.182157 +v -0.755463 1.497570 -0.176746 +v -0.767035 1.543450 -0.138618 +v -0.892086 0.991157 0.167859 +v -0.210582 0.351564 -0.277510 +v 0.134049 1.180550 -0.142317 +v -0.727111 1.442880 -0.115934 +v -0.760901 1.479580 -0.092221 +v -0.340613 1.744880 -0.134591 +v 0.346717 0.984860 -0.126433 +v 0.297060 0.984738 -0.167977 +v -0.285603 1.108800 -0.184786 +v -0.332597 1.091140 -0.191525 +v 0.529502 0.695479 0.032400 +v -0.120350 0.906597 -0.366788 +v -0.761880 1.514080 -0.111135 +v -0.768082 1.540810 -0.101775 +v -0.268298 1.076490 -0.210139 +v -0.826714 0.893233 -0.062731 +v -0.800612 0.909018 -0.095454 +v -0.195671 0.387426 -0.053014 +v -0.078425 0.891643 -0.367658 +v 0.080898 1.122330 -0.190535 +v -0.558477 0.568485 -0.028167 +v -0.725951 0.709691 -0.064554 +v -0.238859 0.963802 -0.255399 +v -0.171550 0.986825 -0.250528 +v -0.126285 1.146080 -0.173682 +v -0.115570 1.109250 -0.201272 +v -0.345665 0.842655 -0.246489 +v -0.609157 0.455193 -0.023168 +v -0.829098 0.847855 -0.045640 +v -0.806379 0.866531 -0.080717 +v -0.824336 0.935156 -0.067265 +v 0.384156 0.968539 -0.090771 +v -0.752315 1.420450 -0.064478 +v -0.769872 1.519580 -0.066958 +v -0.765103 1.560680 -0.080966 +v -0.830086 1.036000 -0.023951 +v -0.762741 1.110570 -0.061156 +v -0.772588 1.451520 -0.050723 +v -0.781765 1.490340 -0.035217 +v -0.521942 1.622640 -0.021860 +v -0.636579 0.452201 0.001977 +v -0.570840 0.497267 -0.017915 +v -0.543076 0.532358 -0.049918 +v -0.565846 0.615353 -0.055721 +v -0.713837 0.668374 -0.015314 +v -0.679133 0.679179 -0.069104 +v -0.754276 0.701713 -0.012344 +v -0.772655 0.741588 -0.051014 +v -0.808501 0.771297 -0.023857 +v -0.838050 0.980351 -0.036811 +v -0.850180 0.904004 -0.027343 +v -0.813450 1.081460 -0.021050 +v 0.125843 1.270880 -0.029039 +v -0.224125 0.993753 -0.241593 +v -0.797727 1.367970 -0.039157 +v 0.342474 1.091720 -0.062580 +v -0.344003 0.477423 -0.211060 +v -0.249805 0.390404 -0.092796 +v -0.861503 0.963591 0.005468 +v -0.692209 0.412962 0.001390 +v -0.699776 0.382075 -0.019565 +v -0.825439 0.809935 -0.025574 +v -0.858784 1.244790 -0.022448 +v 0.262204 0.887105 -0.224810 +v -0.803963 1.497970 0.006851 +v -0.711769 0.390721 0.012394 +v -0.836882 0.798396 0.014863 +v -0.864444 0.921505 0.009684 +v -0.812066 1.123790 -0.015154 +v 0.328168 1.032200 -0.126016 +v 0.285599 1.076270 -0.130845 +v -0.803203 1.439660 -0.016900 +v -0.522261 1.634700 0.018466 +v -0.896550 1.379130 0.332897 +v -0.771667 1.535030 -0.021365 +v -0.741689 1.556230 0.016687 +v -0.790789 0.733316 -0.002718 +v -0.806804 0.735767 0.034763 +v -0.837189 0.772583 0.054373 +v -0.866089 0.886944 0.012891 +v -0.873505 0.947054 0.036743 +v -0.839716 1.060460 0.009562 +v -0.896370 1.271570 0.038110 +v -0.865452 1.281380 -0.008845 +v -0.831976 1.407290 0.010651 +v -0.795048 1.532970 0.041767 +v -0.568657 0.536706 0.022234 +v -0.833786 1.461240 0.031100 +v -0.320195 1.782510 -0.119309 +v -0.649611 0.454810 0.045146 +v -0.670733 0.437336 0.010990 +v -0.334868 0.523207 -0.112291 +v -0.818040 0.760641 0.014001 +v -0.853121 0.844276 0.003194 +v -0.869396 1.000340 0.040406 +v -0.881447 1.243520 0.006467 +v -0.872790 1.381920 0.058744 +v -0.767982 1.175480 0.514541 +v -0.787605 1.226700 0.519425 +v -0.566851 1.591280 0.040420 +v -0.598825 0.476085 0.014436 +v -0.575766 0.506542 0.034690 +v -0.561186 0.530521 0.067999 +v -0.346114 0.611219 -0.128755 +v -0.363597 0.555199 -0.105965 +v -0.777264 0.700524 0.049309 +v -0.863439 0.827548 0.063442 +v -0.857827 1.146220 0.018073 +v 0.124801 0.909913 -0.294205 +v 0.299412 1.118380 -0.088345 +v -0.040412 1.266190 -0.062560 +v -0.079397 1.223360 -0.110742 +v -0.680322 1.498450 -0.388412 +v 0.022440 0.970671 -0.280076 +v 0.246522 1.192670 -0.053775 +v 0.216182 1.182650 -0.094314 +v -0.642338 1.712570 -0.611939 +v -0.628154 1.746520 -0.615673 +v -0.082337 1.001090 -0.246142 +v 0.426729 0.599137 -0.040983 +v -0.154677 1.856490 -0.244453 +v -0.611475 1.718580 -0.572583 +v -0.613155 1.742560 -0.603277 +v 0.194006 1.211570 -0.075179 +v -0.160445 1.108810 -0.198208 +v 0.444471 0.688580 0.001058 +v 0.165155 0.344965 0.014513 +v 0.173772 0.355717 0.050955 +v 0.384658 0.899942 -0.128119 +v 0.029623 0.390113 -0.072154 +v 0.281720 0.640319 -0.210869 +v 0.240097 0.631509 -0.246303 +v -0.210028 1.214950 -0.087379 +v -0.085011 1.283380 -0.011076 +v 0.220134 0.872904 -0.251566 +v 0.163337 1.194990 -0.115831 +v 0.280483 0.905784 -0.209516 +v 0.147931 1.109370 -0.173921 +v 0.075356 0.947749 -0.290244 +v 0.194528 0.924013 -0.245208 +v 0.166784 0.907696 -0.268274 +v -0.365282 1.213570 -0.101182 +v 0.463679 0.647198 -0.012615 +v 0.419974 0.639414 -0.031513 +v -0.657132 1.798890 -0.593617 +v -0.539441 0.490843 0.346691 +v -0.504811 0.519468 0.341893 +v -0.502750 0.485148 -0.084647 +v -0.268471 0.679130 0.405673 +v 0.346207 1.050960 -0.097032 +v 0.341179 0.788424 -0.174416 +v 0.319563 1.077200 -0.105006 +v -0.314862 0.344323 0.157915 +v -0.344549 0.347104 0.300732 +v -0.358212 0.344051 0.219199 +v -0.177780 1.065520 -0.219974 +v -0.195955 0.961306 -0.283344 +v 0.207350 1.230910 -0.032115 +v 0.167743 1.264200 -0.006978 +v -0.305401 0.383986 -0.302900 +v 0.570087 0.596921 0.014439 +v -0.657410 1.545080 0.021078 +v -0.650381 1.536500 -0.020161 +v -0.177489 1.142990 -0.173529 +v -0.230096 1.154680 -0.155374 +v 0.561449 0.671906 0.024663 +v -0.543682 1.613340 0.007700 +v 0.128553 0.936410 -0.271639 +v 0.139102 1.242560 -0.068795 +v -0.307360 0.450972 -0.274995 +v -0.526173 0.388916 -0.109897 +v -0.218425 1.106130 -0.197158 +v -0.355850 0.344833 0.129261 +v -0.619467 1.511570 -0.011407 +v -0.009318 0.947566 -0.321875 +v -0.568159 1.573620 0.005463 +v -0.602581 1.530900 0.006310 +v -0.573820 1.526410 -0.010316 +v -0.600277 1.438360 -0.039486 +v -0.404614 0.457624 -0.177750 +v -0.333429 0.415747 -0.293016 +v -0.603546 1.394890 -0.057211 +v -0.273805 1.232440 -0.041258 +v 0.362562 0.826680 -0.162544 +v -0.330428 1.056500 -0.208151 +v -0.069359 1.174140 -0.155567 +v -0.081389 1.133820 -0.187083 +v 0.374741 0.403830 -0.006147 +v 0.394314 0.447955 -0.041170 +v -0.589457 1.479260 -0.018279 +v -0.574426 1.441430 -0.023000 +v -0.062045 1.029110 -0.233016 +v -0.144167 1.182060 -0.141502 +v -0.185578 1.202690 -0.107314 +v -0.633678 1.590070 -0.490117 +v 0.454180 0.741808 0.025417 +v 0.465303 0.696756 0.022612 +v -0.090086 1.253060 -0.072441 +v 0.045263 1.202870 -0.141249 +v 0.024935 1.172460 -0.168763 +v -0.561955 1.373200 -0.039804 +v -0.469502 1.118930 -0.174558 +v -0.021722 1.125660 -0.194538 +v -0.317852 1.533060 -0.044500 +v 0.496336 0.614712 -0.032837 +v 0.463080 0.599797 -0.042425 +v 0.165235 1.147810 -0.149968 +v 0.111535 1.157540 -0.165241 +v -0.576472 1.252530 -0.075018 +v -0.620615 1.239520 -0.085096 +v 0.386143 0.609155 -0.073630 +v 0.361009 0.563372 -0.083718 +v -0.278428 1.175500 -0.131591 +v 0.175553 1.039590 -0.198004 +v -0.252451 0.372659 -0.294901 +v -0.250820 0.408914 -0.292324 +v 0.045335 1.237700 -0.101126 +v -0.493209 0.499073 0.375430 +v -0.138464 0.354462 -0.260163 +v 0.171439 1.066920 -0.182207 +v -0.164598 0.954685 -0.317548 +v -0.641588 1.534920 -0.068724 +v -0.356285 1.256710 -0.025302 +v 0.106973 0.959319 -0.258674 +v -0.534957 1.337490 -0.032287 +v -0.516477 1.271070 -0.054745 +v -0.376647 0.451710 -0.238835 +v 0.151213 0.951181 -0.246995 +v -0.533227 1.372450 -0.016885 +v -0.495014 1.301490 -0.018380 +v -0.533278 1.304580 -0.043169 +v 0.244418 0.976231 -0.205432 +v -0.484062 1.246080 -0.084487 +v -0.538352 1.239190 -0.081393 +v -0.089816 0.941165 -0.341286 +v 0.489984 0.718994 0.060256 +v -0.525756 1.208860 -0.113593 +v -0.126262 1.224300 -0.096902 +v -0.451654 1.217570 -0.118108 +v -0.378177 0.426319 -0.268735 +v -0.414051 0.413734 -0.244884 +v -0.127474 1.253940 -0.052452 +v -0.500682 1.180220 -0.142137 +v 0.002266 1.288510 -0.023006 +v 0.352795 0.874575 -0.169746 +v -0.458804 1.270670 -0.047995 +v -0.481206 1.200410 -0.130646 +v -0.455448 1.180170 -0.144902 +v -0.145050 0.937394 -0.344983 +v -0.179129 1.243310 -0.045619 +v 0.317644 1.004750 -0.145372 +v -0.419769 1.258850 -0.064671 +v -0.723867 1.052660 0.376484 +v 0.023630 1.270710 -0.055727 +v 0.019258 1.082350 -0.208353 +v 0.039462 1.106450 -0.200145 +v 0.194971 0.963872 -0.229286 +v 0.024925 1.137550 -0.191157 +v -0.402735 1.221430 -0.108772 +v -0.400765 1.186760 -0.134338 +v -0.039892 0.979661 -0.280003 +v -0.091338 0.963512 -0.314130 +v -0.382023 1.243390 -0.074470 +v 0.141900 1.021460 -0.214808 +v 0.310904 0.927925 -0.182668 +v -0.364931 0.354027 0.201815 +v -0.281632 1.208930 -0.087436 +v -0.345000 0.445812 -0.269706 +v -0.241865 1.827840 -0.178517 +v -0.274852 1.820560 -0.124190 +v -0.214735 1.856760 -0.153490 +v 0.062212 1.152480 -0.181134 +v 0.097846 1.210440 -0.127816 +v -0.429520 1.245070 -0.088683 +v -0.430208 1.141160 -0.163814 +v -0.390518 1.116700 -0.178600 +v -0.231308 1.227140 -0.061908 +v -0.460776 1.630430 -0.080027 +v 0.276451 0.791524 -0.228803 +v -0.410790 1.270060 -0.030947 +v -0.380159 1.272600 0.004552 +v -0.337387 1.184800 -0.122539 +v 0.492858 0.684178 0.017941 +v -0.589031 0.365978 -0.099226 +v -0.258921 1.559810 -0.042249 +v -0.201946 1.860990 -0.192721 +v -0.329888 1.228510 -0.064618 +v -0.357956 1.228340 -0.080771 +v -0.190337 1.850400 -0.224172 +v -0.165313 1.824520 -0.261588 +v 0.164935 0.861558 -0.286824 +v -0.375875 1.152280 -0.155893 +v -0.371053 0.368360 -0.299046 +v -0.785509 0.946888 -0.108323 +v -0.736908 0.938756 -0.145693 +v -0.742421 1.074960 -0.093934 +v -0.601099 1.171070 -0.118157 +v -0.633416 1.119840 -0.135528 +v -0.767409 1.174840 -0.060523 +v -0.523569 0.443882 0.441458 +v -0.312909 0.355463 -0.304921 +v -0.348404 0.342799 -0.299259 +v 0.547600 0.552134 -0.002043 +v -0.745151 1.265270 -0.080303 +v 0.528627 0.588005 -0.027799 +v -0.497952 1.102880 -0.181566 +v 0.482310 0.541696 -0.051498 +v 0.447445 0.537277 -0.061330 +v 0.483391 0.575015 -0.050486 +v -0.541803 0.482324 -0.062137 +v -0.484950 0.722035 -0.161769 +v -0.395196 1.604770 -0.118326 +v -0.398301 1.565110 -0.100257 +v -0.670009 1.550920 -0.513631 +v -0.647444 0.978798 -0.174206 +v -0.611623 0.932382 -0.193639 +v -0.691532 0.719196 -0.109566 +v 0.432667 0.438722 -0.012029 +v 0.463444 0.474756 -0.028691 +v 0.436656 0.500703 -0.057133 +v -0.740557 0.751158 -0.098192 +v -0.870767 1.198200 -0.000249 +v -0.259549 0.334219 -0.265916 +v -0.269662 0.346444 -0.291647 +v -0.085609 1.114720 -0.203663 +v 0.436350 0.562508 -0.057294 +v 0.388524 0.554360 -0.061994 +v 0.393869 0.588869 -0.055060 +v -0.763399 1.313720 -0.069424 +v -0.819401 1.169000 -0.028898 +v -0.648094 0.904192 -0.184872 +v -0.654317 1.348370 -0.079200 +v -0.230291 0.930506 -0.324431 +v -0.273617 0.902025 -0.317479 +v -0.790746 1.256380 -0.062896 +v -0.508243 0.729860 -0.164481 +v -0.806243 1.309970 -0.047773 +v -0.715427 1.462470 -0.226793 +v -0.543386 0.974357 -0.214191 +v -0.549320 1.018510 -0.201825 +v -0.613924 1.341710 -0.070494 +v -0.569344 1.340250 -0.053256 +v -0.578985 0.917037 -0.209486 +v -0.549044 0.594288 -0.058857 +v 0.391381 0.516881 -0.065488 +v 0.345278 0.487730 -0.065345 +v -0.657625 1.759940 -0.606258 +v -0.682785 0.804056 -0.170251 +v -0.489417 0.780241 -0.191956 +v 0.309480 0.361413 0.038378 +v -0.551135 0.821965 -0.210765 +v 0.303105 0.454276 -0.062785 +v 0.364767 0.471867 -0.059651 +v -0.533907 1.571130 -0.029576 +v -0.503100 0.820287 -0.210274 +v 0.335463 0.834304 -0.185597 +v -0.532221 0.884104 -0.218633 +v -0.726415 1.161290 -0.074876 +v -0.746404 1.441570 -0.079567 +v -0.798445 1.174620 0.495212 +v -0.545581 0.918348 -0.218586 +v 0.306240 0.815141 -0.204935 +v 0.303553 0.868884 -0.203649 +v -0.434385 0.340045 0.253712 +v -0.607727 0.802909 -0.194821 +v -0.590788 0.741988 -0.173520 +v -0.492488 1.561580 -0.058569 +v -0.665526 1.228120 -0.088246 +v 0.263895 0.402456 -0.042268 +v 0.323744 0.425875 -0.043375 +v -0.447966 0.720725 -0.169573 +v -0.031871 1.096110 -0.213044 +v -0.513539 0.527667 -0.077224 +v 0.162131 0.387269 -0.207377 +v -0.735524 1.211200 -0.078863 +v 0.267483 0.841282 -0.229680 +v -0.494831 0.967454 -0.220556 +v 0.210702 0.729718 -0.274839 +v -0.425765 1.029210 -0.211192 +v 0.264340 0.513227 -0.199375 +v -0.261805 0.889105 -0.345627 +v 0.026344 0.893611 -0.339066 +v -0.484585 0.570688 -0.103806 +v -0.452017 0.678585 -0.152111 +v 0.242952 0.561736 -0.239661 +v 0.260283 0.739227 -0.243920 +v -0.695937 0.757125 -0.141611 +v -0.540451 1.502520 -0.024372 +v 0.214250 0.518120 -0.243394 +v 0.193613 0.673949 -0.282881 +v 0.231532 0.676755 -0.259516 +v 0.159693 0.738315 -0.297763 +v -0.433336 0.565296 -0.114123 +v -0.339846 0.346997 0.376161 +v -0.450993 0.623568 -0.131035 +v -0.617851 0.631248 -0.045865 +v -0.557749 1.150750 -0.148383 +v 0.234033 0.801095 -0.256377 +v -0.734960 1.484530 -0.274294 +v -0.511136 0.747957 -0.175941 +v -0.657465 0.426966 -0.024593 +v -0.577130 0.949538 -0.207388 +v 0.210797 0.552175 -0.261790 +v 0.215757 0.587554 -0.262885 +v -0.421762 0.503685 -0.108885 +v 0.190508 1.003520 -0.216942 +v -0.228642 0.896331 -0.360481 +v -0.398189 0.808697 -0.202528 +v -0.883272 1.131640 0.240056 +v 0.153125 0.504081 -0.264482 +v -0.455199 0.813108 -0.203060 +v 0.167466 0.429748 -0.225320 +v 0.137624 0.454459 -0.246519 +v 0.192532 0.468550 -0.224358 +v 0.196347 0.630797 -0.275094 +v -0.258049 0.933223 -0.285648 +v 0.109803 0.877855 -0.311961 +v 0.148563 0.989201 -0.228458 +v -0.770616 0.831172 -0.114995 +v 0.003766 0.354690 0.082800 +v -0.395605 1.681940 -0.118015 +v -0.586615 0.695228 -0.137098 +v 0.148069 0.594432 -0.289967 +v 0.174477 0.550465 -0.276772 +v 0.115992 0.745022 -0.316901 +v -0.515177 0.434581 -0.095724 +v -0.384786 0.943247 -0.230078 +v -0.774871 1.145130 -0.048158 +v 0.119218 0.699150 -0.314338 +v 0.169997 0.697911 -0.295367 +v 0.177159 0.792901 -0.286521 +v 0.128684 0.835615 -0.307154 +v -0.424633 1.621750 -0.105892 +v -0.516514 1.061170 -0.195141 +v 0.113985 0.542590 -0.292347 +v -0.478336 0.372007 -0.139925 +v 0.121836 0.479152 -0.262435 +v 0.096742 0.577130 -0.301512 +v 0.142338 0.650200 -0.299987 +v 0.144374 0.767410 -0.302596 +v -0.451286 1.092580 -0.187315 +v -0.498299 1.012420 -0.213458 +v -0.371543 1.506050 -0.013382 +v -0.308839 1.545430 -0.009159 +v 0.099999 0.432557 -0.245573 +v 0.098760 0.665462 -0.315289 +v -0.418457 0.629415 -0.134433 +v -0.487944 1.642560 -0.051084 +v 0.078952 0.458133 -0.258820 +v 0.053533 0.419589 -0.245268 +v 0.050790 0.679620 -0.330237 +v 0.054609 0.640389 -0.324649 +v 0.113353 0.793602 -0.317448 +v -0.415746 0.959842 -0.224631 +v 0.094105 1.083340 -0.196143 +v 0.105522 0.497866 -0.276357 +v 0.076638 0.848985 -0.328709 +v -0.368923 1.646830 -0.137118 +v -0.406352 0.870806 -0.220543 +v -0.117997 1.642970 -0.176938 +v -0.719101 1.343700 -0.078544 +v 0.116455 0.401168 -0.233644 +v 0.079448 0.552075 -0.301212 +v 0.079762 0.757640 -0.335234 +v 0.070033 0.802157 -0.337240 +v -0.655427 1.064630 -0.149781 +v -0.492778 1.142890 -0.163336 +v 0.097673 0.643494 -0.312219 +v -0.464703 0.599300 -0.120046 +v -0.693967 1.472200 -0.290416 +v 0.056072 0.513331 -0.293324 +v 0.087424 0.615047 -0.309121 +v 0.045149 0.783570 -0.346873 +v 0.041131 0.599422 -0.319808 +v 0.069408 0.717027 -0.333491 +v 0.035242 0.744261 -0.347748 +v 0.023969 0.836201 -0.349961 +v -0.677882 1.574620 -0.538943 +v 0.028544 0.561210 -0.313270 +v 0.060569 0.573262 -0.307989 +v 0.090148 1.022330 -0.213704 +v 0.121447 1.046490 -0.201694 +v -0.666810 1.613010 -0.569358 +v -0.002060 0.790985 -0.360245 +v -0.016715 0.456222 -0.276859 +v 0.033124 0.465136 -0.272938 +v -0.001037 0.436410 -0.256251 +v -0.466258 0.476985 -0.100364 +v 0.034000 0.391186 -0.244488 +v -0.026798 0.479260 -0.298680 +v 0.019383 0.480729 -0.290224 +v 0.007529 0.703293 -0.345418 +v -0.009447 1.016920 -0.229455 +v -0.744595 1.377850 -0.067070 +v 0.036547 0.362851 -0.238466 +v -0.064011 0.358556 -0.249530 +v -0.035719 0.381479 -0.252724 +v -0.029390 0.670738 -0.348559 +v -0.009600 0.643310 -0.342275 +v 0.048033 1.042160 -0.213135 +v -0.542414 1.448670 -0.013263 +v -0.044049 0.523530 -0.318324 +v -0.013191 0.831907 -0.363979 +v -0.647213 0.762434 -0.170251 +v -0.440763 1.579300 -0.091051 +v -0.288345 0.786961 -0.350950 +v -0.005298 0.347380 -0.234723 +v 0.007733 0.504011 -0.303077 +v 0.008370 0.535304 -0.310570 +v -0.055305 0.569716 -0.334036 +v -0.047941 0.779543 -0.371649 +v -0.051339 0.823642 -0.375328 +v -0.457048 0.862593 -0.216243 +v -0.592704 0.991833 -0.193308 +v -0.022452 0.741869 -0.360096 +v -0.682609 1.335300 -0.082966 +v -0.094602 0.482713 -0.304374 +v -0.006264 0.587187 -0.329663 +v -0.032651 0.873174 -0.363404 +v -0.113258 0.381204 -0.154066 +v -0.489027 0.641829 -0.125182 +v -0.073363 0.457523 -0.285422 +v -0.090879 0.511840 -0.319546 +v -0.457541 1.053770 -0.203437 +v -0.085666 0.791510 -0.379983 +v -0.077885 1.053980 -0.229191 +v -0.075964 1.090460 -0.218887 +v -0.791937 0.802943 -0.074793 +v -0.491262 1.512830 -0.044746 +v -0.544710 1.100850 -0.177057 +v -0.681267 0.376198 -0.049993 +v -0.050996 0.605197 -0.343973 +v -0.101593 0.687837 -0.369332 +v -0.079171 0.744124 -0.372880 +v -0.053675 0.696643 -0.358795 +v -0.632122 1.028680 -0.172219 +v -0.111753 0.824677 -0.385673 +v -0.643292 0.693462 -0.113740 +v -0.536835 0.640077 -0.096777 +v -0.018721 0.913474 -0.346195 +v -0.120224 0.586710 -0.350231 +v -0.078998 0.639664 -0.356581 +v -0.458476 0.351763 -0.204944 +v -0.560857 0.342944 -0.106133 +v -0.611101 1.689720 -0.602167 +v -0.637570 1.660260 -0.602862 +v -0.082713 0.591575 -0.344997 +v -0.137419 0.697768 -0.380179 +v -0.118056 0.727923 -0.379646 +v 0.197851 0.426208 -0.196501 +v -0.196180 0.377529 -0.170958 +v -0.414611 0.367821 -0.276033 +v -0.156754 1.741160 -0.254488 +v -0.108062 0.381113 -0.262299 +v -0.175262 0.389485 -0.277917 +v -0.071313 0.410864 -0.258715 +v -0.083593 0.438037 -0.268357 +v -0.083494 0.559337 -0.336004 +v -0.140189 0.647579 -0.370693 +v -0.150770 0.863093 -0.385195 +v -0.091608 0.863020 -0.378784 +v 0.374043 1.058670 -0.040221 +v 0.398651 1.027850 -0.021785 +v -0.493041 0.363815 0.456170 +v -0.698802 1.071840 -0.123118 +v -0.298031 0.359707 0.216139 +v -0.172779 0.431216 -0.277720 +v -0.148656 0.822889 -0.389743 +v -0.634543 0.659834 -0.077181 +v -0.673569 0.339251 -0.050990 +v -0.637154 0.342725 -0.077416 +v -0.120378 1.721750 -0.267049 +v -0.147410 1.786740 -0.276025 +v -0.140133 0.457211 -0.284544 +v -0.096910 0.538325 -0.331388 +v -0.629029 0.865361 -0.193288 +v -0.573721 0.869739 -0.211309 +v -0.689746 0.942147 -0.165289 +v -0.721382 0.971594 -0.146408 +v -0.719682 0.365291 0.012748 +v -0.687423 1.594920 -0.534082 +v -0.184748 0.706023 -0.384386 +v -0.576495 1.046820 -0.186503 +v -0.666032 1.676440 -0.585565 +v 0.087346 0.353158 0.063762 +v -0.187837 0.575095 -0.337342 +v -0.136786 0.529429 -0.327241 +v -0.182037 0.823228 -0.390529 +v -0.692010 0.872814 -0.172909 +v -0.650857 0.830474 -0.186222 +v -0.178364 0.655282 -0.372683 +v -0.209561 0.862025 -0.380897 +v -0.875660 1.311500 0.016196 +v -0.840826 1.337650 -0.012778 +v -0.616302 0.384033 0.200210 +v -0.215877 0.541734 -0.307031 +v -0.644425 0.726693 -0.147855 +v -0.382540 0.650376 -0.141486 +v -0.167271 0.495655 -0.303282 +v -0.154625 0.736915 -0.387299 +v -0.138305 0.779571 -0.386832 +v -0.191850 0.771667 -0.390836 +v -0.260175 0.444035 -0.282794 +v -0.695076 0.342887 0.096014 +v 0.290003 0.477422 -0.095187 +v 0.337944 0.511506 -0.075490 +v -0.806969 0.810435 0.316240 +v -0.167714 0.613065 -0.359362 +v -0.543133 0.776116 -0.194211 +v -0.648079 0.378937 0.261783 +v -0.180308 1.781440 -0.248422 +v 0.071386 0.885122 -0.326062 +v 0.070468 0.914196 -0.317936 +v -0.197585 1.023970 -0.233946 +v -0.714549 1.808710 -0.551233 +v -0.739555 1.770010 -0.535823 +v -0.570571 1.293970 -0.062721 +v -0.271173 0.478742 -0.262924 +v -0.213420 0.476340 -0.282607 +v -0.251554 0.598647 -0.307945 +v -0.219615 0.654770 -0.358286 +v 0.185530 1.025760 -0.206862 +v -0.264014 1.702850 -0.186491 +v -0.828898 1.170140 0.484599 +v -0.341165 0.495938 -0.138838 +v -0.377431 0.494021 -0.121443 +v -0.478104 0.402866 -0.122598 +v -0.450010 0.419852 -0.150736 +v -0.262804 0.716950 -0.355121 +v -0.258551 0.759334 -0.370281 +v -0.232358 0.722224 -0.376112 +v -0.230183 0.763772 -0.384092 +v -0.228566 0.814076 -0.384864 +v -0.727966 1.459030 -0.178352 +v -0.741141 1.465890 -0.148947 +v -0.680811 1.143210 -0.098786 +v -0.679994 1.189510 -0.087822 +v -0.215186 0.406528 0.538096 +v -0.790029 0.844207 -0.095503 +v -0.188286 0.389852 -0.128300 +v -0.249025 1.670110 -0.179812 +v -0.264705 1.781570 -0.181110 +v -0.213770 1.745500 -0.219085 +v -0.217315 1.797010 -0.218690 +v -0.260477 0.797473 -0.372837 +v -0.456057 1.544000 -0.071800 +v -0.607120 1.208130 -0.093497 +v -0.419558 0.696750 -0.162730 +v -0.439524 0.762031 -0.184469 +v 0.062525 0.361763 -0.131694 +v -0.391261 0.357458 0.212424 +v -0.026764 1.057670 -0.223199 +v -0.239499 1.021820 -0.235132 +v 0.146820 0.345964 0.355577 +v 0.121539 0.349248 0.300796 +v 0.107001 0.347853 0.416075 +v 0.200630 0.360495 0.154922 +v -0.332023 0.349235 0.459366 +v -0.097464 0.386586 0.048487 +v 0.210853 0.354741 0.181716 +v 0.091597 0.368239 0.303480 +v 0.194340 0.351110 0.208817 +v 0.233257 0.350755 0.184982 +v -0.712149 1.521860 -0.445262 +v -0.690009 1.516230 -0.454806 +v -0.633352 0.345407 0.384388 +v 0.173339 0.357791 -0.142067 +v 0.394902 0.417433 0.257460 +v -0.713779 1.482960 -0.335494 +v 0.031529 0.381928 -0.121569 +v 0.241078 0.349429 0.035210 +v 0.528809 0.476199 0.206140 +v -0.658086 1.582670 -0.552130 +v -0.103704 0.362998 0.497188 +v -0.082238 0.391803 -0.113068 +v 0.039211 0.344387 0.180607 +v -0.029982 0.348664 0.457959 +v -0.007118 0.365123 0.167904 +v -0.004522 0.378101 0.206969 +v -0.574621 0.575177 0.102453 +v 0.205056 0.350896 0.059195 +v 0.124985 0.392657 0.448105 +v -0.283242 0.390423 0.534841 +v -0.901018 1.126610 0.149776 +v -0.919919 1.149230 0.173603 +v -0.884545 1.117610 0.186488 +v 0.099274 0.361020 0.446046 +v 0.156854 0.346993 0.234451 +v -0.909587 1.154970 0.242444 +v 0.242130 0.349233 0.110701 +v 0.243281 0.359187 0.248451 +v 0.191306 0.360310 0.089442 +v 0.188909 0.353941 0.353471 +v -0.369996 0.360600 0.168930 +v 0.420878 0.446271 0.283033 +v -0.079878 0.387921 0.493975 +v 0.048788 0.344065 0.052673 +v 0.027280 0.356338 0.024058 +v 0.089164 0.356790 -0.095754 +v 0.064694 0.376302 -0.101396 +v -0.880354 1.135770 0.287307 +v 0.033907 0.347675 0.439704 +v -0.896538 1.137640 0.337307 +v -0.877469 1.119530 0.373591 +v -0.900417 1.135590 0.377659 +v 0.196231 0.350006 0.278564 +v -0.036839 0.392553 -0.038396 +v 0.599692 0.681936 0.161923 +v -0.017642 0.393350 -0.099419 +v -0.908184 1.148340 0.400794 +v 0.354639 0.412585 0.270333 +v -0.090960 0.390668 -0.059697 +v -0.037197 0.390908 0.247056 +v -0.096112 0.384734 0.145738 +v 0.139551 0.357658 0.056679 +v -0.847157 1.115240 0.312574 +v -0.494520 1.476800 -0.023104 +v -0.336661 1.720860 -0.018533 +v -0.328634 1.751460 -0.028541 +v -0.021692 0.338764 -0.196276 +v -0.330448 0.366274 0.492487 +v -0.169444 0.384412 0.199274 +v -0.854661 1.113450 0.343724 +v -0.886048 1.158720 0.450493 +v 0.070156 0.385549 0.299380 +v 0.334687 0.361764 0.067806 +v 0.409702 0.926539 -0.077736 +v -0.133360 0.344892 -0.191910 +v -0.043057 0.361815 -0.161770 +v -0.876450 1.127220 0.419950 +v -0.818878 1.117620 0.446622 +v -0.708302 1.379070 0.478046 +v -0.683318 1.160950 0.507904 +v -0.029214 0.383145 -0.138740 +v -0.810496 1.095830 0.334755 +v -0.918119 1.175700 0.415240 +v -0.900321 1.150730 0.424271 +v -0.841736 1.106800 0.396456 +v -0.847072 1.142320 0.463700 +v -0.858668 1.176960 0.478972 +v 0.293076 0.365916 0.215496 +v 0.062685 0.346801 0.070344 +v -0.830332 0.806589 0.269603 +v -0.633748 1.484260 -0.199596 +v -0.202447 0.390077 0.278961 +v -0.024826 0.386838 0.025407 +v -0.787532 0.699512 0.114500 +v -0.796089 0.713161 0.158744 +v -0.817220 0.765879 0.233423 +v -0.282512 0.348409 0.501063 +v -0.766502 1.079730 0.370366 +v -0.810728 1.097340 0.374496 +v 0.220858 1.211620 0.302926 +v -0.755126 0.673716 0.175007 +v -0.228992 0.352713 0.521001 +v 0.203776 0.370520 0.386984 +v 0.165941 0.353870 0.398215 +v -0.779649 0.711344 0.216799 +v -0.795186 0.766056 0.289211 +v -0.787536 1.098890 0.413236 +v -0.813486 1.143390 0.473731 +v -0.782743 1.139270 0.484168 +v -0.093021 0.348770 0.473843 +v 0.223100 0.367467 0.325709 +v -0.731766 0.645121 0.114772 +v -0.750528 0.663534 0.105066 +v -0.756148 1.114640 0.461026 +v -0.720269 0.636518 0.090707 +v -0.739065 0.664046 0.042226 +v -0.691456 1.736020 -0.567436 +v 0.071688 0.370829 0.269120 +v 0.102439 0.344810 0.015200 +v 0.071194 0.351795 -0.026276 +v 0.409555 0.402360 0.204933 +v 0.488748 0.432829 0.137770 +v 0.488020 0.443506 0.201985 +v 0.443784 0.408906 0.159709 +v -0.716360 1.111440 0.443561 +v -0.666572 0.386148 0.138004 +v -0.706157 0.346455 -0.012370 +v -0.691736 0.629770 0.033759 +v -0.704670 0.636680 0.198230 +v -0.729985 0.649941 0.176278 +v -0.744837 0.699874 0.271618 +v -0.776464 0.728535 0.265923 +v -0.585008 0.594606 -0.001153 +v -0.689241 0.358106 -0.046441 +v -0.724252 0.639544 0.144586 +v 0.015966 0.348445 -0.164346 +v -0.733547 1.093090 0.402030 +v -0.712360 0.343720 0.043090 +v 0.065813 0.372187 -0.067066 +v -0.711215 1.131010 0.488636 +v -0.715659 1.156460 0.517524 +v 0.087344 0.349717 0.235442 +v -0.640378 0.330504 -0.036927 +v -0.635021 0.605456 0.034936 +v -0.679184 0.610657 0.099309 +v -0.685694 0.613925 0.153159 +v -0.725817 0.672033 0.243621 +v -0.142835 0.387438 -0.034368 +v 0.054158 0.356388 0.232988 +v 0.038657 0.371008 0.240069 +v -0.634995 0.332605 0.041724 +v -0.097987 1.677760 -0.194856 +v -0.613655 0.590030 0.082529 +v -0.744074 0.724836 0.313151 +v -0.710348 0.736418 0.357058 +v -0.689375 1.122240 0.449239 +v -0.684345 1.108620 0.402818 +v 0.052667 0.386040 0.460691 +v -0.016176 0.393650 0.475199 +v -0.311509 0.405444 0.513532 +v -0.680800 0.332114 0.005713 +v 0.165160 0.370868 0.427784 +v 0.131575 0.349851 0.209161 +v -0.607109 0.612126 -0.016326 +v -0.676361 0.648076 0.262239 +v 0.305220 0.400124 0.273309 +v 0.331507 0.459030 0.308389 +v -0.246419 0.383587 0.203192 +v -0.279148 0.367796 0.169614 +v -0.655500 0.740142 0.390132 +v -0.712187 0.776804 0.383046 +v -0.125296 1.066690 -0.222128 +v -0.681475 1.808370 -0.577652 +v 0.338356 0.365584 0.164474 +v 0.279762 0.351085 0.162217 +v -0.661404 0.343903 0.136351 +v -0.599045 0.591422 0.038639 +v -0.705286 0.711005 0.336033 +v -0.659292 0.699111 0.353096 +v -0.618994 0.363142 0.436926 +v -0.669171 0.335315 0.083668 +v -0.573509 0.569062 0.047581 +v -0.597041 0.582920 0.130027 +v -0.643156 0.595329 0.135119 +v -0.659658 0.607579 0.180961 +v -0.629402 0.606570 0.209600 +v -0.699337 0.685264 0.305557 +v -0.662439 0.622402 0.221466 +v 0.023275 0.343156 0.118336 +v -0.005184 0.357414 0.131437 +v 0.533710 0.470150 0.170922 +v -0.631613 0.626171 0.255230 +v -0.516908 0.337244 -0.111191 +v 0.058786 0.343593 0.109049 +v 0.360021 0.367424 0.100733 +v 0.299578 0.350526 0.097007 +v -0.556128 0.330973 -0.073802 +v -0.129081 0.382493 0.510274 +v -0.593419 0.631384 0.288535 +v -0.640586 0.657573 0.308997 +v -0.057118 0.340434 -0.229361 +v -0.473354 0.335523 -0.128693 +v -0.645649 0.361287 0.171448 +v -0.656352 0.353959 0.287763 +v 0.432473 0.522020 0.322897 +v 0.384854 0.478605 0.313892 +v -0.650284 0.345865 0.336424 +v -0.030296 0.376200 0.128961 +v -0.440199 0.333967 -0.198655 +v -0.583307 0.330517 0.001391 +v -0.511081 0.342429 0.132837 +v -0.568826 0.335310 0.139154 +v -0.618186 0.340452 0.173938 +v -0.553776 0.339838 0.276734 +v -0.600762 0.704663 0.381719 +v -0.586213 0.663687 0.342512 +v -0.331108 0.331572 -0.261414 +v -0.380819 0.337218 -0.282012 +v -0.441945 0.334370 -0.139103 +v -0.616475 0.340358 0.314770 +v -0.310894 0.337026 -0.291528 +v -0.516823 0.332054 -0.010471 +v -0.447061 0.340896 0.065369 +v -0.500538 0.338989 0.065868 +v -0.555361 0.631558 0.306434 +v -0.394993 0.331463 -0.227413 +v -0.403949 0.348635 -0.031069 +v -0.410796 0.341401 -0.120418 +v 0.392093 0.382810 0.146104 +v -0.139262 0.351537 0.495644 +v -0.395352 0.357497 -0.085975 +v -0.573895 0.340371 0.357974 +v -0.550959 0.678868 0.368455 +v -0.042467 0.364180 0.479313 +v 0.345537 0.387420 0.230481 +v -0.344896 0.340783 -0.201837 +v -0.516033 0.682686 0.377987 +v -0.507355 0.715423 0.402086 +v -0.550673 0.708345 0.392770 +v -0.366614 0.361822 -0.143745 +v -0.309376 0.362002 -0.183954 +v -0.328048 0.379310 -0.152682 +v -0.456930 0.333437 0.023381 +v 0.030667 0.363029 0.461591 +v -0.519862 0.642808 0.342680 +v 0.085885 0.343466 -0.145724 +v -0.134883 0.353740 0.431131 +v 0.187195 0.356317 -0.086360 +v -0.638115 0.364428 0.242631 +v -0.631062 0.349908 0.240275 +v -0.467662 0.351999 0.097759 +v -0.540756 0.347400 0.444816 +v -0.596617 0.343010 0.414119 +v -0.583849 0.354575 0.451602 +v -0.545411 0.361808 0.463571 +v -0.569417 0.380289 0.466540 +v 0.159444 0.341992 -0.042632 +v 0.141354 0.342759 -0.127041 +v -0.472448 0.678010 0.394177 +v -0.477723 0.753825 0.423769 +v -0.183078 0.346201 0.489850 +v -0.233474 0.335854 -0.229346 +v -0.314057 0.391152 -0.114259 +v -0.457988 0.334860 -0.029785 +v -0.530221 0.342119 0.406664 +v 0.076287 0.378859 0.326227 +v -0.353763 0.372847 -0.023420 +v -0.376476 0.342657 0.044538 +v -0.581977 0.780267 0.432282 +v 0.009822 0.350986 0.161152 +v 0.019180 0.359930 0.203851 +v 0.120357 0.341854 -0.061065 +v -0.520203 0.342255 0.348715 +v 0.032401 0.388544 0.266379 +v -0.142007 0.392892 0.299154 +v -0.267508 0.384493 -0.160299 +v -0.393814 0.344620 0.087809 +v -0.152824 0.362827 -0.178312 +v -0.266289 0.347778 0.435162 +v 0.141263 0.351999 -0.183291 +v -0.156226 0.383599 0.092358 +v -0.271931 0.344560 -0.207861 +v -0.241640 0.361169 -0.190516 +v -0.477564 0.341303 0.310809 +v -0.611205 0.591074 0.171967 +v -0.559283 0.576754 0.159944 +v -0.582448 0.600721 0.225815 +v -0.367150 0.379958 -0.082322 +v -0.281774 0.372269 0.087205 +v -0.302845 0.349978 0.194512 +v -0.406324 0.360216 0.116726 +v 0.042941 0.389996 0.324919 +v -0.523220 0.336037 0.169981 +v -0.298018 0.374630 0.303709 +v 0.071131 0.357625 0.362183 +v -0.053049 0.389787 0.356478 +v -0.116164 0.387350 0.377264 +v -0.234613 0.383158 0.368266 +v 0.102897 0.354030 0.155746 +v -0.713450 1.675120 -0.221138 +v -0.672671 1.699690 -0.345404 +v -0.090250 1.297140 0.052180 +v -0.661385 1.697180 -0.370576 +v -0.739516 1.762320 -0.432954 +v -0.647076 1.677040 -0.355051 +v -0.748861 1.656000 -0.201053 +v -0.180610 1.279800 0.082200 +v -0.190760 1.273740 0.054960 +v 0.457820 0.831729 0.049029 +v -0.202528 1.264520 0.025529 +v -0.161284 0.395426 0.341771 +v -0.191993 0.393907 0.335157 +v -0.665278 1.452460 0.412949 +v -0.163215 1.285740 0.106261 +v -0.308140 1.240540 0.209947 +v -0.209550 1.227240 0.280058 +v -0.685261 1.689090 -0.554276 +v -0.568936 0.416640 -0.086534 +v 0.175021 1.109600 0.390530 +v -0.080431 0.425541 0.488737 +v -0.474467 1.648860 0.043689 +v -0.468467 1.175530 0.312179 +v -0.437211 1.151900 0.335341 +v -0.417866 0.626895 0.407009 +v -0.419194 0.925651 0.427280 +v -0.278850 1.070620 0.402032 +v -0.625129 1.502290 -0.188521 +v -0.255385 1.260730 0.129381 +v -0.187822 0.339203 -0.211176 +v -0.168874 0.336771 -0.218972 +v -0.013369 0.435613 0.468759 +v -0.166675 1.122220 0.401882 +v -0.418299 1.706300 0.002126 +v 0.314372 1.026810 0.368994 +v -0.333226 1.620670 -0.017285 +v -0.154157 1.702730 -0.159799 +v 0.406907 0.829289 0.319210 +v 0.391883 0.808310 0.342767 +v -0.591824 1.343140 0.360186 +v -0.331509 1.552360 -0.092459 +v 0.314130 0.470304 0.325903 +v 0.304605 0.478789 0.343771 +v -0.209515 1.719600 -0.141772 +v -0.365182 1.517240 -0.051412 +v -0.242511 1.664860 -0.095083 +v 0.362906 0.959098 0.356155 +v 0.369230 1.034200 0.300485 +v -0.250589 1.647240 -0.076746 +v -0.252275 1.634650 -0.061343 +v 0.460992 0.830303 0.109275 +v -0.333230 1.682530 -0.039303 +v -0.327851 1.700140 -0.037401 +v -0.297185 1.748450 -0.167139 +v 0.332159 1.027670 0.351541 +v -0.313645 0.358195 0.259632 +v -0.316846 0.349246 0.236895 +v -0.154466 0.384906 0.030783 +v -0.123853 0.386303 0.008870 +v -0.072606 0.410252 0.489547 +v -0.442702 0.560355 0.388698 +v -0.257769 1.726940 -0.109295 +v 0.271054 0.569767 -0.211984 +v -0.111614 1.758030 -0.225267 +v -0.871093 0.848282 0.172807 +v -0.785546 1.709100 -0.380209 +v -0.001872 0.339280 -0.216756 +v -0.134174 0.390285 -0.120920 +v -0.622340 1.659250 -0.473030 +v -0.687868 1.482960 -0.336486 +v -0.522746 1.444950 0.197293 +v -0.755592 1.755110 -0.422970 +v -0.310376 1.794920 -0.104495 +v -0.311790 1.794530 -0.088645 +v -0.295664 1.767680 -0.160873 +v -0.278317 1.258340 0.121823 +v -0.726229 1.623420 -0.119891 +v -0.812313 1.537340 0.081785 +v -0.733719 1.715250 -0.324622 +v -0.649451 1.646780 -0.245686 +v -0.661776 1.660840 -0.249919 +v -0.736932 1.614750 -0.111293 +v 0.339907 1.138400 0.007408 +v -0.195131 1.258810 0.000315 +v -0.702200 1.465330 0.422729 +v -0.893654 1.343140 0.401573 +v -0.264920 0.384141 0.009964 +v -0.758297 1.660300 -0.224496 +v -0.768048 1.611950 -0.161433 +v -0.407506 1.722720 -0.018087 +v -0.369412 1.509620 -0.035423 +v -0.835436 0.906449 0.306684 +v -0.779016 1.655910 -0.269759 +v -0.539911 1.611720 0.045124 +v -0.514016 1.628390 0.044338 +v -0.491230 1.642080 0.042596 +v -0.698833 1.640830 -0.498661 +v -0.728328 1.714020 -0.489743 +v -0.723112 1.663560 -0.447357 +v -0.722614 1.603210 -0.391061 +v -0.726644 1.621470 -0.394047 +v -0.727074 1.556960 -0.352776 +v -0.767743 1.631180 -0.327115 +v -0.753657 1.627010 -0.340930 +v -0.739964 1.590260 -0.307750 +v -0.274515 0.564229 -0.259974 +v -0.271441 0.580571 -0.274177 +v 0.004273 0.396693 0.297759 +v -0.747687 1.490100 -0.230351 +v -0.753068 1.498290 -0.228541 +v -0.753864 1.505990 -0.231671 +v -0.746263 1.527850 -0.252196 +v -0.741831 1.547310 -0.245110 +v -0.745256 1.534690 -0.232775 +v -0.116578 0.339692 -0.238584 +v -0.097250 0.346285 -0.245326 +v -0.778810 1.593830 -0.190216 +v -0.289822 1.787050 -0.154721 +v -0.332605 0.345032 0.424822 +v -0.282677 1.804670 -0.145166 +v -0.391840 1.718760 -0.103932 +v 0.331382 0.958945 -0.150344 +v -0.273432 0.387808 -0.043774 +v -0.236115 0.386393 -0.028104 +v -0.328689 0.343280 0.231052 +v -0.510430 1.612200 -0.040702 +v -0.520258 1.637100 -0.005361 +v -0.233044 1.182510 -0.126301 +v -0.231769 1.196570 -0.110479 +v 0.005325 0.389670 -0.027677 +v -0.246756 1.205110 -0.097640 +v -0.002142 0.392206 0.335489 +v -0.041907 0.396382 0.309700 +v -0.363764 0.341554 0.265435 +v -0.344650 0.343271 0.174327 +v -0.329175 0.346515 0.096295 +v -0.151423 1.231420 -0.076861 +v -0.355690 0.349885 0.181261 +v 0.201939 0.832082 -0.270773 +v 0.338064 0.378714 0.013965 +v -0.386287 0.340723 0.295028 +v -0.610998 0.675872 -0.108268 +v -0.122548 0.390511 -0.087622 +v -0.158451 0.389593 -0.088741 +v -0.499022 1.603200 -0.053441 +v 0.079761 0.376483 -0.235075 +v -0.458945 1.595820 -0.083285 +v -0.016202 0.362315 -0.246157 +v 0.003954 0.674538 -0.340782 +v -0.018917 0.399665 -0.250994 +v -0.002582 0.412297 -0.249113 +v -0.663258 1.720330 -0.597046 +v -0.261431 0.378009 0.141372 +v -0.284336 0.375363 0.230654 +v -0.300344 0.367429 0.250163 +v -0.154007 0.573411 -0.345081 +v -0.179732 0.532067 -0.319260 +v -0.220921 0.595015 -0.330325 +v 0.155686 0.344910 0.294165 +v 0.139874 0.345104 0.271577 +v 0.004622 0.348454 0.416525 +v -0.026785 0.358438 0.399315 +v 0.080411 0.372752 0.455138 +v -0.235767 0.344333 0.488661 +v -0.100123 0.360220 -0.171758 +v 0.216290 0.350546 0.230473 +v 0.127269 0.346084 0.253084 +v -0.210705 0.345337 0.461140 +v 0.174093 0.347687 0.321217 +v -0.056588 0.393037 -0.079370 +v -0.074574 0.346161 0.448699 +v -0.043963 0.384202 0.186396 +v 0.262702 0.354172 0.202033 +v -0.063152 0.389399 0.006421 +v 0.148732 0.342302 -0.076734 +v -0.056166 0.384821 0.088120 +v -0.029634 0.380888 0.076391 +v -0.134727 0.395885 0.348376 +v -0.094420 0.388211 -0.011989 +v -0.106315 0.386895 0.228302 +v -0.069902 0.386016 0.199814 +v -0.052697 0.345816 -0.178601 +v -0.077636 0.340667 -0.193303 +v -0.159132 0.383077 0.141739 +v -0.200300 0.382258 0.133019 +v -0.079039 0.351992 -0.174813 +v -0.181310 0.385131 0.000461 +v 0.273104 0.374607 0.255632 +v -0.221236 0.392286 0.322305 +v -0.249288 0.390133 0.293114 +v -0.240015 0.380870 0.122675 +v -0.273379 0.384394 0.259554 +v -0.087065 0.392888 0.280411 +v -0.138502 0.346698 0.476293 +v 0.067541 0.343801 0.171277 +v -0.626829 0.335680 0.105440 +v -0.035168 0.346172 0.438122 +v -0.607092 0.334683 0.087603 +v -0.589306 0.333965 0.069439 +v -0.522862 0.330938 -0.072867 +v -0.495936 0.332303 -0.071527 +v -0.641102 0.344347 0.293881 +v -0.420095 0.334198 -0.174627 +v -0.558139 0.335064 0.075763 +v -0.535943 0.335547 0.053520 +v -0.605682 0.341268 0.244731 +v -0.471700 0.334237 -0.074793 +v -0.556154 0.337148 0.209941 +v -0.586075 0.339504 0.223461 +v -0.450771 0.335517 -0.086912 +v -0.394852 0.337294 -0.177535 +v -0.486022 0.334638 0.035875 +v -0.493668 0.337145 0.194612 +v -0.511966 0.336168 0.205751 +v -0.502489 0.338173 0.253222 +v -0.610503 0.340907 0.370677 +v -0.381003 0.343745 -0.163455 +v -0.430671 0.339335 -0.064909 +v -0.412667 0.345317 -0.070860 +v -0.349523 0.381847 -0.126046 +v -0.424267 0.336414 0.007757 +v -0.294641 0.336366 -0.228117 +v -0.282961 0.333694 -0.246315 +v 0.168321 0.345283 -0.073749 +v -0.329648 0.388830 -0.060362 +v -0.094288 0.395836 0.329625 +v -0.299001 0.390222 -0.067318 +v -0.197180 0.362999 -0.184692 +v -0.212716 0.344208 -0.204187 +v -0.192254 0.353240 -0.191345 +v -0.448759 0.361657 0.137419 +v -0.323567 0.358909 0.058228 +v -0.405305 0.367572 0.167589 +v -0.443831 0.355817 0.189215 +v -0.472379 0.342520 0.197136 +v -0.284886 0.365841 0.373650 +v -0.073234 0.372260 0.392603 +v -0.001558 0.375449 0.367627 +v 0.153109 0.364290 0.119776 +v 0.115803 0.360551 0.098174 +v 0.089818 0.354894 0.104124 +v 0.153048 0.360511 0.163473 +v 0.163808 0.355890 0.187335 +v 0.177709 0.354600 0.193015 +v -0.643326 1.703660 -0.445224 +v -0.729384 1.677570 -0.229179 +v -0.207396 0.385126 -0.007086 +v -0.129866 0.405201 -0.268563 +v -0.119912 0.421009 -0.267894 +v -0.058018 0.349892 0.424167 +v -0.072439 0.356958 0.413034 +v 0.107930 0.340518 -0.168924 +v -0.156028 0.387875 0.251598 +v -0.645187 0.338399 0.126429 +v -0.075266 0.347730 0.435246 +v -0.192847 0.370819 0.403157 +v -0.208563 0.356061 0.426698 +v 0.054547 0.347005 0.414246 +v 0.016653 0.358216 0.386117 +v 0.428222 0.403924 0.054311 +vn -0.862500 0.125900 -0.490100 +vn -0.928400 0.014900 -0.371300 +vn -0.883500 -0.082000 -0.461000 +vn -0.980200 -0.198100 -0.003400 +vn -0.931000 -0.261300 -0.254900 +vn -0.975000 0.178400 -0.132100 +vn -0.119800 0.963000 0.241200 +vn 0.002900 0.933300 0.359000 +vn -0.208300 0.871100 0.444700 +vn 0.142000 0.873400 0.465800 +vn 0.333200 0.850500 0.407000 +vn 0.511800 0.723800 0.462800 +vn 0.057300 0.862200 0.503200 +vn -0.195800 0.786600 0.585500 +vn -0.621100 0.555600 0.552700 +vn -0.203300 0.733600 0.648400 +vn -0.537300 0.777000 0.327800 +vn -0.076900 0.993700 0.082000 +vn -0.178600 0.980900 0.077300 +vn -0.101700 0.973600 0.204300 +vn 0.512600 0.835900 0.196000 +vn 0.683800 0.604300 0.408800 +vn 0.749600 0.634800 0.187300 +vn -0.845100 -0.534400 -0.008900 +vn -0.850000 -0.508600 0.137200 +vn -0.916700 -0.397700 -0.038600 +vn 0.364200 -0.893500 -0.262800 +vn -0.029300 -0.900700 -0.433300 +vn 0.604400 -0.762300 -0.231500 +vn -0.940500 -0.331000 0.076300 +vn -0.994200 -0.083000 0.067800 +vn -0.980800 -0.178600 -0.077500 +vn 0.721200 0.619900 0.309100 +vn 0.613300 0.604100 0.508900 +vn 0.848900 0.298800 0.435800 +vn -0.583400 0.809800 -0.061600 +vn -0.624100 0.736000 -0.262200 +vn -0.447500 0.851200 0.274300 +vn -0.219500 0.947800 0.231200 +vn -0.773500 -0.624400 -0.108800 +vn -0.860700 -0.476200 -0.180200 +vn 0.274100 0.901400 0.335100 +vn -0.102500 0.924400 0.367300 +vn 0.089100 0.909600 0.405700 +vn 0.813300 0.516300 0.268100 +vn 0.749700 0.560700 0.351500 +vn 0.849800 0.431800 0.302200 +vn 0.758400 0.535400 0.371500 +vn 0.686300 0.667100 0.289600 +vn 0.818100 0.510600 0.264500 +vn -0.436200 0.059400 -0.897900 +vn -0.770300 -0.288400 -0.568700 +vn -0.214200 -0.826700 -0.520200 +vn 0.491500 0.829900 0.264000 +vn 0.239400 0.919000 0.313100 +vn 0.699600 0.683600 0.207800 +vn 0.602600 0.766500 0.222100 +vn 0.445900 0.765900 0.463100 +vn 0.211800 0.842900 0.494700 +vn 0.651300 0.667900 0.360000 +vn 0.308100 0.852800 0.421600 +vn -0.139900 0.884500 0.444900 +vn -0.414700 0.451100 -0.790200 +vn -0.211400 0.208300 -0.954900 +vn -0.162100 0.275600 -0.947500 +vn -0.312400 0.904400 0.290500 +vn -0.322100 0.881100 0.346100 +vn -0.323300 0.808600 0.491600 +vn -0.937900 0.346300 0.019300 +vn -0.966800 0.238800 0.090600 +vn -0.934800 0.348300 -0.068500 +vn -0.184800 0.927000 -0.326400 +vn -0.225200 0.961400 -0.158000 +vn -0.188700 0.968600 -0.161700 +vn -0.781800 -0.524300 -0.337300 +vn -0.806800 0.332700 -0.488300 +vn -0.767700 -0.111200 -0.631100 +vn -0.883900 -0.466800 -0.026700 +vn -0.998300 -0.051200 -0.026000 +vn -0.986500 -0.106400 0.124600 +vn -0.871500 -0.430300 0.235000 +vn -0.922600 -0.358300 0.142900 +vn -0.203400 0.978300 -0.038600 +vn -0.136600 0.990400 -0.020300 +vn -0.125600 0.981500 -0.144000 +vn -0.375500 0.884900 -0.275300 +vn -0.263100 0.638900 -0.722900 +vn -0.457400 0.784200 -0.419200 +vn -0.231800 0.967100 -0.104300 +vn -0.187200 0.982100 -0.017600 +vn -0.069200 0.996900 -0.035400 +vn -0.391400 0.330300 -0.858900 +vn -0.384000 -0.005700 -0.923300 +vn -0.183800 0.102600 -0.977600 +vn -0.970500 0.236500 -0.045500 +vn -0.970300 0.239600 0.031900 +vn -0.106400 0.939400 -0.325900 +vn -0.670100 0.655300 0.348600 +vn -0.483600 0.747000 0.456100 +vn -0.470000 0.830700 0.298400 +vn 0.086200 0.673200 0.734400 +vn 0.221900 0.591800 0.774900 +vn 0.122600 0.767500 0.629100 +vn 0.680000 0.704600 0.202700 +vn -0.273500 0.960800 0.045800 +vn -0.180900 0.970800 0.157600 +vn -0.983000 0.178200 -0.044400 +vn -0.967500 0.180800 -0.176700 +vn -0.040400 0.999000 -0.020600 +vn 0.019700 0.893900 0.447800 +vn -0.277600 0.944900 0.173600 +vn -0.302000 0.927100 0.222000 +vn -0.365700 0.859900 0.356200 +vn -0.039500 0.967600 -0.249400 +vn 0.010200 0.990600 -0.136500 +vn -0.803900 -0.577200 0.143500 +vn -0.799300 -0.599900 0.035200 +vn 0.615200 0.694300 0.373500 +vn 0.896700 0.428100 0.112200 +vn 0.849800 0.497400 0.174000 +vn 0.774700 0.607800 0.174500 +vn -0.883600 0.243500 -0.399800 +vn -0.883800 0.358100 -0.301200 +vn -0.794800 0.324100 -0.513100 +vn 0.085400 0.940900 -0.327600 +vn 0.138200 0.601600 -0.786700 +vn 0.285600 0.513700 -0.809000 +vn 0.287500 0.716500 -0.635500 +vn 0.429000 0.836700 0.340400 +vn -0.149500 0.883400 0.444100 +vn -0.256100 0.872600 0.415900 +vn -0.654100 0.710300 0.259900 +vn -0.294600 0.951800 0.085200 +vn -0.012900 0.930800 0.365300 +vn -0.124300 0.918400 0.375700 +vn -0.027200 0.836200 0.547700 +vn -0.973300 0.038100 -0.226100 +vn -0.996800 0.066500 -0.044100 +vn -0.963900 0.177000 -0.199100 +vn -0.501000 0.790000 0.353300 +vn -0.224200 0.887400 0.402600 +vn -0.783900 -0.619300 -0.043500 +vn -0.717100 -0.697000 0.002500 +vn -0.814600 -0.540000 -0.211700 +vn -0.148000 0.842800 0.517400 +vn -0.085500 0.767600 0.635100 +vn 0.611900 0.313000 0.726300 +vn 0.261200 0.511500 0.818600 +vn 0.542800 0.623000 0.563100 +vn -0.885800 -0.434200 0.163500 +vn -0.982600 -0.128800 0.133500 +vn -0.952000 -0.306000 0.002000 +vn -0.380600 -0.131200 0.915300 +vn -0.178700 0.015100 0.983800 +vn -0.394500 0.188500 0.899300 +vn 0.015900 0.294800 0.955400 +vn -0.287300 0.448200 0.846500 +vn -0.438200 0.831400 -0.341500 +vn -0.203800 0.943800 0.260000 +vn 0.213800 0.912200 0.349500 +vn -0.322500 0.768700 0.552400 +vn -0.305800 0.839400 0.449400 +vn 0.051400 0.496700 0.866400 +vn -0.178100 0.678600 0.712500 +vn 0.327700 0.939500 0.099200 +vn -0.815500 -0.577700 0.034000 +vn -0.351700 -0.217200 0.910600 +vn -0.178100 0.602300 0.778100 +vn -0.228700 0.694900 0.681800 +vn -0.425600 0.568800 0.703800 +vn 0.261900 0.935100 0.238700 +vn 0.365800 0.760200 0.536900 +vn -0.475300 0.787700 0.391900 +vn -0.541000 0.538500 0.646000 +vn -0.604800 0.190300 0.773300 +vn -0.359000 0.543400 0.758800 +vn -0.930300 0.291800 -0.222200 +vn -0.009900 -0.564100 -0.825600 +vn -0.024800 -0.422400 -0.906000 +vn 0.032800 -0.495900 -0.867700 +vn 0.133900 0.094200 -0.986500 +vn -0.112500 0.074800 -0.990800 +vn 0.009500 0.089100 -0.996000 +vn -0.362000 0.826200 0.431600 +vn 0.039700 0.978500 0.202500 +vn 0.225700 0.791200 0.568400 +vn -0.011200 0.059500 0.998100 +vn 0.029500 0.505400 0.862300 +vn 0.910400 0.234400 -0.341000 +vn 0.834100 0.266000 -0.483200 +vn 0.847600 0.316400 -0.426000 +vn -0.915300 -0.366000 -0.168300 +vn -0.934500 -0.355500 0.019000 +vn -0.246400 0.956400 -0.156800 +vn -0.255300 0.962700 -0.089000 +vn -0.985800 -0.013200 -0.167400 +vn -0.995500 -0.041800 -0.084400 +vn 0.868000 0.457600 0.192400 +vn 0.129600 0.991000 -0.033300 +vn 0.061600 0.994600 0.083000 +vn 0.063300 0.627800 0.775800 +vn -0.663000 0.559800 0.497000 +vn -0.939400 0.291100 0.181000 +vn -0.878300 -0.021700 0.477500 +vn 0.169800 0.971500 -0.165300 +vn -0.390300 -0.363300 0.846000 +vn -0.174700 -0.118000 0.977500 +vn 0.362500 0.284600 0.887400 +vn 0.261400 0.393000 0.881600 +vn 0.022900 0.246900 -0.968700 +vn 0.050800 0.461000 -0.885900 +vn 0.149800 0.207200 -0.966700 +vn 0.523400 -0.797100 0.301000 +vn 0.455600 -0.889400 0.036800 +vn 0.547600 -0.726600 0.414900 +vn -0.933700 0.122600 -0.336400 +vn -0.910900 0.266700 -0.314900 +vn -0.855200 0.334000 -0.396400 +vn 0.069200 0.030800 -0.997100 +vn 0.029800 -0.309200 -0.950500 +vn 0.054000 -0.152100 -0.986900 +vn -0.575800 0.262500 -0.774300 +vn -0.303800 -0.010800 -0.952600 +vn -0.096900 -0.288800 0.952500 +vn -0.139800 0.793800 0.591800 +vn 0.022700 0.728700 0.684400 +vn -0.795700 0.228900 -0.560700 +vn -0.874500 0.109800 -0.472300 +vn -0.954500 -0.177500 -0.239600 +vn 0.304100 0.118100 -0.945300 +vn 0.266600 -0.174700 -0.947800 +vn 0.501200 0.155300 -0.851300 +vn 0.249700 0.084200 0.964700 +vn 0.256000 0.501600 0.826300 +vn -0.181800 -0.655200 0.733200 +vn 0.102800 -0.583500 0.805500 +vn 0.375700 -0.079200 -0.923300 +vn 0.908400 0.253000 -0.332900 +vn 0.845900 -0.188100 -0.499100 +vn -0.956200 0.001300 -0.292700 +vn -0.282600 -0.254100 -0.924900 +vn -0.229800 -0.397800 -0.888200 +vn -0.093200 -0.535800 -0.839100 +vn 0.908000 0.317800 -0.273100 +vn 0.873600 0.442200 -0.203200 +vn 0.935500 0.334500 -0.113900 +vn 0.566700 -0.352500 -0.744700 +vn 0.689300 -0.422500 -0.588500 +vn 0.626000 -0.589000 -0.511100 +vn -0.199500 -0.389100 -0.899300 +vn 0.464300 -0.855600 -0.228900 +vn 0.833400 -0.536100 -0.134300 +vn 0.917100 -0.376100 -0.131700 +vn 0.187800 0.317000 0.929600 +vn 0.195600 0.451900 0.870400 +vn 0.095200 0.477600 0.873300 +vn 0.461800 -0.562300 -0.685900 +vn 0.876800 0.477500 -0.056000 +vn 0.935400 0.352900 0.021000 +vn 0.745000 -0.248900 -0.618900 +vn 0.667900 0.255500 -0.699000 +vn 0.861200 0.140600 -0.488300 +vn 0.722300 0.371000 -0.583700 +vn -0.263000 0.959400 0.101700 +vn 0.018700 0.977700 0.209000 +vn -0.355900 0.219500 0.908400 +vn -0.358800 0.301900 0.883200 +vn -0.530200 0.198200 0.824400 +vn 0.302600 -0.237400 0.923100 +vn 0.156100 -0.291300 0.943800 +vn 0.092800 -0.542700 0.834700 +vn 0.202300 -0.298800 0.932600 +vn 0.403400 0.458800 0.791700 +vn 0.554300 -0.831400 0.037300 +vn 0.452400 -0.891100 -0.035400 +vn 0.547900 -0.818200 -0.173800 +vn 0.803800 -0.079100 -0.589600 +vn 0.869200 -0.297900 -0.394600 +vn 0.962600 -0.018500 -0.270300 +vn 0.982900 0.064900 -0.172000 +vn 0.989600 0.019300 -0.142200 +vn -0.636800 0.667200 -0.386400 +vn -0.568700 0.808800 0.149400 +vn -0.772500 0.622000 0.127900 +vn -0.931500 0.181100 -0.315500 +vn -0.850600 -0.107800 -0.514600 +vn -0.859200 0.231400 -0.456400 +vn -0.701600 -0.711100 -0.045300 +vn -0.698000 -0.690000 -0.191500 +vn -0.650800 -0.723300 -0.230800 +vn -0.272300 0.287400 0.918300 +vn -0.185600 0.251700 0.949800 +vn -0.306600 -0.089900 0.947600 +vn 0.089300 -0.357100 0.929800 +vn 0.016900 0.183200 0.982900 +vn 0.096800 0.239400 0.966100 +vn 0.037200 0.403000 0.914400 +vn 0.286900 0.381400 0.878800 +vn 0.367500 0.444000 0.817200 +vn 0.234000 0.574900 0.784100 +vn 0.285200 -0.273800 0.918500 +vn 0.072500 -0.174500 0.982000 +vn 0.120800 -0.329100 0.936500 +vn 0.600100 0.326500 0.730200 +vn 0.508600 0.177600 0.842500 +vn 0.910500 0.384600 -0.151800 +vn 0.992400 0.053200 -0.110800 +vn 0.987600 0.147300 0.053400 +vn -0.969300 0.239100 0.057100 +vn -0.964000 0.241800 0.110700 +vn -0.946800 0.310300 0.084700 +vn -0.845100 0.054600 -0.531800 +vn -0.793500 0.149100 -0.589900 +vn -0.008500 0.911400 -0.411300 +vn 0.062000 0.849800 0.523400 +vn -0.196700 0.369700 0.908100 +vn 0.826500 -0.532000 -0.184000 +vn 0.805900 -0.553500 -0.210100 +vn 0.967500 -0.235300 -0.092100 +vn 0.060400 -0.477600 0.876500 +vn -0.052800 -0.696200 0.715900 +vn -0.051700 -0.433400 0.899700 +vn 0.129700 0.592900 0.794700 +vn 0.085000 0.731200 0.676800 +vn 0.089800 0.598000 0.796400 +vn 0.977300 -0.191600 -0.090200 +vn 0.728700 -0.681800 0.064800 +vn 0.860600 -0.343700 0.375700 +vn -0.984600 0.140600 0.103300 +vn -0.017900 -0.562200 -0.826800 +vn -0.088200 -0.628200 -0.773000 +vn 0.234200 -0.853700 -0.465000 +vn 0.978700 0.200700 0.043500 +vn 0.978900 0.195600 -0.059800 +vn 0.995800 0.085800 -0.031200 +vn -0.227400 0.960400 -0.161100 +vn -0.228800 0.945800 -0.230400 +vn -0.933000 -0.353100 -0.069800 +vn 0.272400 0.920500 -0.280000 +vn 0.045800 -0.997700 -0.050200 +vn 0.056300 -0.930700 -0.361500 +vn 0.070700 -0.995700 -0.059100 +vn 0.316800 -0.432400 0.844100 +vn 0.233000 -0.390700 0.890500 +vn 0.159200 -0.667300 0.727500 +vn 0.170900 -0.038200 0.984500 +vn 0.990400 -0.070400 -0.119100 +vn 0.954100 0.178100 -0.240800 +vn 0.938500 0.323900 -0.119100 +vn 0.772500 -0.477300 -0.418700 +vn 0.803000 -0.544900 -0.241200 +vn 0.446300 -0.618500 -0.646700 +vn 0.953500 -0.299800 -0.031100 +vn -0.335300 0.146300 0.930700 +vn -0.365900 0.013700 0.930500 +vn -0.288600 0.141300 0.946900 +vn 0.209100 0.579500 0.787700 +vn 0.363800 0.558100 0.745800 +vn 0.109600 0.570100 0.814200 +vn 0.156700 0.189300 0.969300 +vn 0.217200 0.396100 0.892100 +vn 0.295600 -0.219400 0.929700 +vn 0.198300 -0.251500 0.947300 +vn 0.689700 0.242100 0.682400 +vn 0.551200 0.363400 0.751000 +vn 0.951500 -0.021300 -0.306800 +vn 0.972600 0.011500 -0.232200 +vn 0.891900 -0.095500 -0.442000 +vn -0.248900 0.968500 -0.004700 +vn -0.240600 0.970200 -0.026700 +vn 0.152900 0.967100 0.203200 +vn 0.325100 0.941000 -0.093600 +vn 0.462500 0.886100 -0.029600 +vn 0.445200 0.880600 -0.162200 +vn -0.286100 -0.367000 0.885100 +vn -0.269400 -0.173000 0.947400 +vn -0.461900 -0.297500 0.835500 +vn -0.463100 -0.097100 0.880900 +vn -0.220000 0.283000 0.933500 +vn 0.911700 -0.055700 -0.407000 +vn 0.903600 0.143400 -0.403600 +vn 0.001200 -0.257900 0.966200 +vn -0.006500 -0.307300 0.951600 +vn -0.076400 -0.250600 0.965100 +vn -0.028800 0.578300 0.815300 +vn -0.068600 0.695900 0.714800 +vn 0.096400 0.652600 0.751500 +vn 0.204400 -0.069400 0.976400 +vn 0.258300 -0.065400 0.963800 +vn 0.230100 -0.008100 0.973100 +vn 0.509000 0.291800 0.809800 +vn 0.555300 0.252400 0.792400 +vn 0.364300 0.588500 0.721800 +vn 0.150300 0.915000 0.374300 +vn -0.115100 -0.290600 0.949900 +vn -0.162700 -0.311000 0.936300 +vn 0.728000 -0.193700 0.657600 +vn 0.751900 -0.251600 0.609300 +vn 0.703000 -0.108100 0.702900 +vn -0.717800 -0.645200 0.261500 +vn -0.780500 -0.504700 0.368800 +vn 0.842600 0.426600 0.328600 +vn 0.844700 0.523300 0.112400 +vn 0.848000 0.460800 0.261900 +vn -0.537000 -0.151800 -0.829800 +vn -0.421400 -0.188000 -0.887200 +vn -0.556700 -0.309200 -0.771000 +vn -0.132000 -0.224600 0.965500 +vn -0.176100 0.061100 0.982500 +vn -0.080900 0.353200 0.932000 +vn 0.122200 -0.138800 0.982700 +vn 0.340700 -0.508100 0.791000 +vn 0.469900 -0.331900 0.817900 +vn -0.366200 -0.399400 -0.840400 +vn -0.511200 -0.340900 -0.788900 +vn -0.263900 -0.615300 -0.742700 +vn -0.110000 -0.151400 0.982300 +vn 0.895800 -0.374500 -0.239200 +vn 0.779900 0.561200 0.277100 +vn 0.725000 0.494200 0.479800 +vn 0.820900 0.426500 0.379700 +vn -0.094700 0.264800 0.959600 +vn -0.067900 0.442300 0.894300 +vn 0.109300 0.066300 0.991800 +vn 0.046300 -0.331000 0.942500 +vn -0.077800 -0.065700 0.994800 +vn 0.120400 -0.152400 0.981000 +vn 0.496500 0.226000 -0.838100 +vn 0.591500 0.017900 -0.806100 +vn -0.988700 -0.072500 0.131100 +vn -0.991100 -0.048800 0.123500 +vn -0.954600 0.245200 -0.169300 +vn -0.304100 0.711000 0.633900 +vn 0.380000 -0.644900 -0.663100 +vn 0.224400 -0.804300 -0.550200 +vn 0.431000 -0.798100 -0.421100 +vn -0.320700 -0.798200 -0.509800 +vn -0.349400 -0.850900 -0.392300 +vn -0.354600 -0.874200 -0.331600 +vn -0.152000 -0.356800 0.921700 +vn -0.164500 -0.235100 0.957900 +vn -0.040000 -0.088200 0.995300 +vn -0.011900 0.118800 0.992800 +vn -0.085600 0.632500 0.769800 +vn 0.020800 0.448700 0.893400 +vn 0.309100 0.165100 0.936600 +vn -0.338400 0.814100 0.471800 +vn -0.753500 -0.245800 -0.609700 +vn -0.735800 -0.172900 -0.654700 +vn -0.885700 -0.186400 -0.425200 +vn -0.090200 -0.128600 0.987600 +vn 0.024300 0.246800 0.968700 +vn 0.323500 -0.069800 0.943600 +vn 0.041800 -0.272600 0.961200 +vn 0.048200 0.117500 0.991900 +vn -0.912800 -0.355900 -0.200000 +vn -0.986400 -0.033300 -0.161000 +vn -0.716900 -0.672300 -0.184400 +vn 0.014900 0.341600 0.939700 +vn 0.600700 0.086900 0.794700 +vn 0.337300 -0.026600 0.941000 +vn 0.034100 0.424600 0.904700 +vn -0.509100 0.083300 -0.856700 +vn -0.683200 0.336800 -0.647800 +vn -0.533400 0.537800 -0.652900 +vn -0.001200 -0.009800 0.999900 +vn 0.385600 -0.547300 0.742700 +vn -0.375900 -0.342700 0.860900 +vn -0.705000 -0.198500 0.680800 +vn -0.482100 -0.149100 0.863300 +vn 0.246800 0.962700 0.110600 +vn 0.214100 0.919400 0.329800 +vn -0.267400 0.336000 -0.903100 +vn -0.358500 0.429500 -0.828800 +vn -0.307900 0.495700 -0.812000 +vn -0.184100 -0.514900 0.837200 +vn -0.074800 -0.483000 0.872400 +vn 0.063200 0.129800 0.989500 +vn -0.012900 0.432300 0.901600 +vn 0.199800 -0.058800 0.978100 +vn 0.215300 0.260200 0.941200 +vn 0.150000 0.224100 0.963000 +vn 0.997800 -0.052600 -0.040800 +vn 0.883400 0.337200 -0.325300 +vn 0.826200 -0.197700 -0.527500 +vn -0.003300 0.615800 0.787900 +vn -0.107500 -0.527000 0.843000 +vn -0.012700 0.851100 0.524800 +vn -0.738900 -0.523100 -0.424700 +vn -0.738300 -0.443300 -0.508300 +vn -0.043700 0.044800 -0.998000 +vn 0.094100 0.190300 -0.977200 +vn -0.078800 -0.183800 0.979800 +vn -0.003400 0.501600 0.865000 +vn 0.152700 0.048700 0.987100 +vn 0.101900 0.079900 0.991500 +vn -0.023600 0.070600 0.997200 +vn 0.982000 -0.112000 0.152100 +vn 0.994000 0.100400 0.043900 +vn 0.959300 0.118900 0.256000 +vn 0.038500 0.399300 0.916000 +vn -0.243500 0.381800 0.891500 +vn 0.080400 0.785700 0.613300 +vn -0.083800 0.682500 0.726000 +vn 0.136700 0.064800 -0.988500 +vn 0.249900 -0.901500 -0.353300 +vn -0.060700 -0.942600 -0.328300 +vn -0.107100 -0.593400 0.797700 +vn -0.029000 -0.312300 0.949500 +vn -0.014800 -0.052800 0.998500 +vn 0.004200 0.309800 0.950800 +vn 0.260700 0.294900 0.919200 +vn 0.059800 0.213000 0.975200 +vn -0.057700 0.133600 0.989300 +vn 0.351800 0.210500 0.912100 +vn 0.280200 0.276800 0.919100 +vn 0.292500 0.296800 0.909000 +vn 0.096300 0.652600 0.751500 +vn 0.386000 -0.916000 0.109600 +vn 0.343000 -0.939100 -0.019900 +vn -0.226100 0.915100 0.333800 +vn -0.346400 0.005000 -0.938000 +vn 0.008100 -0.340300 0.940300 +vn 0.041300 0.129900 0.990700 +vn -0.196200 -0.558200 0.806100 +vn 0.231500 0.477500 0.847600 +vn 0.160900 0.432800 0.887000 +vn -0.092900 0.486400 0.868700 +vn -0.033600 0.605900 0.794800 +vn 0.396400 0.222600 0.890700 +vn 0.391500 0.256100 0.883800 +vn 0.444700 0.315600 0.838200 +vn 0.206600 0.423300 0.882100 +vn 0.318600 0.676100 0.664300 +vn 0.684000 -0.682000 -0.259000 +vn 0.836500 -0.486000 -0.252800 +vn 0.813000 -0.572200 -0.107500 +vn 0.340000 0.425600 0.838600 +vn -0.544600 0.783000 -0.300400 +vn -0.469500 0.767800 -0.435900 +vn -0.672700 0.647500 -0.358000 +vn 0.800500 0.448900 0.397100 +vn 0.853900 0.354000 0.381300 +vn -0.185800 -0.252700 0.949500 +vn -0.350600 -0.200100 0.914900 +vn -0.339200 -0.314100 0.886700 +vn -0.410400 0.035300 0.911200 +vn -0.514600 -0.435400 0.738600 +vn 0.126600 -0.205300 0.970500 +vn 0.032700 0.206700 0.977800 +vn 0.023500 0.333600 0.942400 +vn -0.003500 0.530400 0.847700 +vn 0.062200 0.608900 0.790800 +vn -0.106300 -0.144400 0.983800 +vn 0.102000 -0.150000 0.983400 +vn -0.092200 -0.248100 0.964300 +vn 0.304600 0.511700 0.803300 +vn 0.280000 0.479200 0.831800 +vn 0.231100 0.478600 0.847000 +vn 0.870700 0.452100 0.193500 +vn 0.830100 0.548300 0.101700 +vn 0.023400 -0.362000 0.931900 +vn 0.022600 0.441300 0.897000 +vn 0.223200 -0.006600 0.974700 +vn 0.041000 0.471500 0.880900 +vn -0.134200 0.883100 0.449400 +vn 0.059100 0.721900 0.689400 +vn -0.383000 0.638700 0.667300 +vn 0.187000 -0.033000 0.981800 +vn 0.055800 0.093100 0.994100 +vn 0.178100 0.127500 0.975700 +vn 0.198600 0.459500 0.865700 +vn 0.116400 0.386700 0.914800 +vn 0.148600 0.426200 0.892300 +vn 0.040900 0.348200 0.936500 +vn 0.998400 -0.041000 0.038300 +vn 0.952500 0.247900 0.177100 +vn 0.997500 -0.024000 0.066700 +vn 0.230400 0.477800 0.847700 +vn 0.917400 0.006100 0.397800 +vn 0.218200 -0.948400 -0.230000 +vn 0.056100 -0.974900 -0.215500 +vn 0.531200 -0.818200 -0.219800 +vn -0.049300 0.431000 0.901000 +vn 0.307400 -0.067700 0.949200 +vn -0.220300 0.919900 0.324200 +vn -0.156600 0.875500 0.457100 +vn 0.248900 -0.121500 -0.960800 +vn 0.596800 -0.560500 -0.574100 +vn -0.880200 -0.392900 0.266300 +vn -0.993200 0.115600 -0.014600 +vn -0.693400 -0.720300 0.021000 +vn 0.123200 0.216300 0.968500 +vn 0.050500 0.310000 0.949400 +vn 0.106500 -0.582600 0.805700 +vn 0.312400 -0.459200 0.831500 +vn 0.050600 -0.226500 0.972700 +vn -0.173400 -0.250600 0.952400 +vn 0.245000 0.169800 0.954500 +vn 0.189500 0.074500 0.979000 +vn 0.313300 0.226400 0.922200 +vn -0.074600 0.565100 0.821600 +vn -0.645100 0.094700 0.758200 +vn -0.750300 0.480900 0.453500 +vn 0.027500 -0.300800 0.953300 +vn 0.011100 -0.499000 0.866500 +vn -0.033400 0.440000 0.897300 +vn 0.031200 0.547800 0.836000 +vn 0.366400 -0.711900 -0.599100 +vn 0.624900 -0.711300 -0.321700 +vn -0.199600 0.190300 0.961200 +vn 0.195700 -0.139000 0.970800 +vn 0.304300 -0.107300 0.946500 +vn 0.191700 0.119500 0.974200 +vn 0.286800 0.080800 0.954600 +vn -0.989600 0.065300 0.128500 +vn -0.960800 -0.002600 -0.277000 +vn -0.996300 -0.060800 -0.060400 +vn 0.363700 -0.581300 0.727900 +vn -0.179700 0.669500 0.720800 +vn -0.243900 0.689600 0.681800 +vn 0.183000 0.516100 0.836700 +vn 0.303300 0.059000 0.951000 +vn 0.160700 0.637600 0.753400 +vn 0.498300 0.320900 0.805400 +vn 0.722100 0.571900 -0.389100 +vn 0.660500 0.234100 -0.713400 +vn -0.128200 0.253600 -0.958700 +vn 0.079400 0.214700 0.973400 +vn 0.165700 -0.827500 -0.536300 +vn 0.482700 -0.795600 -0.366000 +vn 0.394800 0.293000 0.870800 +vn -0.872100 0.303000 -0.384300 +vn -0.714500 0.530400 -0.456300 +vn 0.064700 0.427200 0.901800 +vn 0.499400 0.810400 0.306100 +vn 0.704500 -0.112700 -0.700700 +vn 0.593600 0.017200 -0.804600 +vn 0.594900 -0.013200 -0.803700 +vn -0.130100 -0.233100 0.963700 +vn 0.021000 -0.119400 0.992600 +vn 0.113200 0.204100 0.972400 +vn 0.126300 0.355700 0.926000 +vn -0.012500 0.696600 0.717300 +vn 0.348900 0.570400 0.743600 +vn -0.181000 -0.571300 -0.800500 +vn 0.013500 -0.797400 -0.603300 +vn 0.237300 -0.860700 -0.450400 +vn 0.116000 -0.760300 -0.639100 +vn 0.287700 -0.916800 -0.276900 +vn 0.494400 0.220200 0.840900 +vn 0.375300 0.237600 0.895900 +vn -0.057300 -0.101500 0.993200 +vn 0.045000 0.588800 0.807000 +vn -0.001400 0.651800 0.758400 +vn -0.015400 0.657500 0.753300 +vn 0.989700 0.057500 0.130500 +vn 0.945500 0.087500 0.313600 +vn 0.663200 -0.745500 -0.065200 +vn 0.149500 0.323000 0.934500 +vn -0.150000 -0.160400 0.975600 +vn -0.003300 -0.062100 0.998000 +vn 0.136000 0.446400 0.884400 +vn 0.736200 -0.651100 -0.184600 +vn 0.261500 -0.104200 0.959500 +vn 0.078300 -0.060000 0.995100 +vn 0.235600 0.367100 0.899800 +vn -0.963900 -0.253700 0.081200 +vn -0.133600 -0.123100 0.983300 +vn -0.237000 -0.158500 0.958500 +vn 0.101700 0.007100 0.994800 +vn 0.036500 0.221000 0.974600 +vn -0.966000 0.211300 0.149000 +vn 0.985000 -0.172000 -0.009700 +vn -0.025400 0.591900 0.805600 +vn 0.144400 0.365500 0.919500 +vn 0.187000 -0.163600 0.968600 +vn 0.083500 -0.171500 0.981600 +vn 0.010100 -0.091000 0.995800 +vn 0.025400 0.076500 0.996700 +vn 0.990600 0.025200 0.134000 +vn -0.649400 0.757700 -0.064300 +vn -0.436100 0.899400 -0.027700 +vn 0.024700 0.168200 0.985400 +vn -0.094400 0.185700 0.978000 +vn -0.065700 0.066000 0.995600 +vn -0.033800 0.339400 0.940000 +vn 0.076800 0.129100 0.988600 +vn 0.084000 -0.109600 0.990400 +vn -0.037400 -0.049100 0.998100 +vn -0.119800 0.023500 0.992500 +vn -0.051200 0.382100 0.922700 +vn 0.948500 0.264000 -0.174700 +vn 0.928300 0.368800 0.047500 +vn 0.932600 -0.339600 -0.122400 +vn 0.391300 -0.776100 -0.494400 +vn 0.285600 -0.677900 -0.677400 +vn 0.401900 -0.912600 -0.074200 +vn 0.498600 -0.736100 0.457700 +vn 0.156200 -0.114500 0.981000 +vn -0.178700 0.187500 0.965800 +vn 0.091000 0.457500 0.884500 +vn 0.002000 0.558000 0.829800 +vn 0.067600 0.602300 0.795300 +vn -0.002600 0.679200 0.734000 +vn -0.005100 0.783400 0.621400 +vn -0.386600 0.911000 0.143000 +vn -0.436900 0.899000 -0.030300 +vn -0.609100 0.779700 0.145100 +vn 0.595400 0.041800 0.802400 +vn 0.240800 0.385000 0.890900 +vn 0.007900 0.651400 0.758700 +vn -0.004900 0.565400 0.824800 +vn 0.008500 0.706100 0.708000 +vn -0.112300 0.665400 0.737900 +vn -0.237300 0.424700 0.873700 +vn 0.932400 0.082700 -0.351800 +vn 0.926200 -0.135100 -0.351900 +vn 0.563900 0.116400 0.817600 +vn 0.285600 -0.137700 0.948400 +vn 0.176000 -0.105300 0.978700 +vn 0.071300 -0.066800 0.995200 +vn -0.049100 -0.127700 0.990600 +vn -0.146200 -0.028600 0.988800 +vn -0.174000 0.385200 0.906200 +vn -0.104200 0.480600 0.870700 +vn 0.213000 -0.097600 0.972100 +vn 0.913900 0.385900 0.125900 +vn 0.950600 0.277800 0.138500 +vn 0.326200 -0.935600 -0.134800 +vn 0.603600 -0.742800 -0.289700 +vn -0.324300 0.532500 0.781800 +vn 0.023700 0.403100 0.914900 +vn 0.311000 -0.065300 0.948100 +vn 0.338100 -0.185900 0.922500 +vn 0.116700 -0.179700 0.976700 +vn -0.164600 0.530700 0.831400 +vn 0.186100 0.306800 0.933400 +vn 0.246100 0.297000 0.922600 +vn -0.008500 -0.050000 0.998700 +vn 0.744600 -0.142600 0.652100 +vn 0.215400 -0.128400 0.968000 +vn -0.131900 -0.192100 0.972400 +vn -0.202200 -0.154400 0.967100 +vn -0.168300 0.478200 0.862000 +vn 0.597500 0.007600 0.801800 +vn 0.627100 0.085800 0.774200 +vn 0.713700 0.632400 0.301100 +vn 0.461900 0.863000 0.204500 +vn 0.328900 -0.175000 0.928000 +vn 0.053100 -0.148700 0.987400 +vn -0.075700 0.635300 0.768500 +vn -0.044800 0.817900 0.573600 +vn -0.150900 -0.086300 0.984800 +vn -0.106300 0.524700 0.844600 +vn -0.081100 0.375100 0.923400 +vn 0.032900 0.085900 0.995700 +vn 0.219900 -0.181800 0.958400 +vn -0.157100 0.103900 0.982100 +vn -0.110900 0.258600 0.959600 +vn -0.491000 -0.813100 -0.312700 +vn -0.964800 -0.129900 -0.228500 +vn -0.989000 0.137500 0.054700 +vn -0.519400 -0.232900 0.822100 +vn -0.148900 0.394400 0.906800 +vn 0.308600 0.403700 0.861300 +vn 0.048000 0.635500 0.770600 +vn 0.663200 -0.641700 -0.385200 +vn -0.095200 -0.239500 0.966200 +vn -0.435700 -0.314600 0.843300 +vn -0.669400 -0.084900 0.738000 +vn -0.423900 0.057500 0.903900 +vn -0.111700 0.263100 0.958300 +vn 0.993700 0.089700 0.066400 +vn 0.980600 0.152100 0.123700 +vn 0.545600 -0.356800 0.758300 +vn 0.020600 0.109200 0.993800 +vn 0.327700 0.385500 0.862500 +vn 0.099600 0.667200 0.738100 +vn -0.860300 -0.208200 0.465400 +vn -0.871600 0.045300 0.488100 +vn 0.818900 0.154400 -0.552800 +vn 0.813000 0.431800 -0.390500 +vn 0.240700 0.969500 0.046500 +vn -0.392500 -0.168600 0.904100 +vn -0.467200 0.188800 0.863800 +vn 0.851400 0.400400 -0.338700 +vn 0.813200 0.499800 -0.298000 +vn 0.204200 0.800000 0.564100 +vn 0.196200 0.606300 0.770700 +vn 0.917000 0.291400 0.272500 +vn 0.984000 0.062400 0.166900 +vn 0.697000 -0.675400 -0.240800 +vn 0.832100 -0.518800 -0.196200 +vn -0.361300 0.810800 0.460500 +vn -0.481000 0.722100 0.497100 +vn -0.290000 0.767300 0.571900 +vn -0.664600 -0.268000 0.697500 +vn -0.159600 0.286400 0.944700 +vn -0.236200 0.569600 0.787200 +vn -0.196300 0.497100 0.845200 +vn -0.179800 0.427000 0.886100 +vn -0.084800 0.708600 -0.700500 +vn -0.055400 0.613600 -0.787700 +vn -0.096600 0.621500 -0.777400 +vn 0.123600 0.049000 0.991100 +vn -0.046800 -0.076600 -0.995900 +vn 0.949900 -0.301700 -0.080600 +vn 0.960100 -0.275000 -0.051200 +vn -0.757600 -0.017500 0.652500 +vn -0.796800 -0.180500 0.576700 +vn -0.822700 -0.281500 0.493800 +vn -0.935800 0.004300 0.352500 +vn -0.989200 -0.132800 0.062100 +vn -0.886700 -0.295900 0.355200 +vn 0.700700 -0.294900 0.649600 +vn -0.442100 0.345100 0.827900 +vn -0.198500 0.443000 0.874300 +vn -0.227800 0.674700 0.702000 +vn -0.202100 0.786700 0.583200 +vn -0.257400 -0.126400 -0.958000 +vn -0.284000 -0.395400 -0.873500 +vn -0.008500 0.777000 0.629400 +vn 0.135000 0.917500 0.374100 +vn 0.373500 0.927300 0.024800 +vn -0.311600 0.375000 0.873100 +vn -0.011800 0.620100 0.784400 +vn -0.380500 0.728200 0.570000 +vn -0.622800 0.448500 0.641000 +vn 0.649400 0.175200 0.739900 +vn -0.100400 0.340100 0.935000 +vn 0.246900 -0.888900 -0.385900 +vn 0.543000 -0.831600 -0.116500 +vn 0.693200 0.038500 0.719700 +vn 0.373600 0.422700 0.825700 +vn 0.039200 0.788500 0.613700 +vn -0.199500 0.365700 0.909100 +vn 0.176300 0.377500 0.909100 +vn -0.031700 0.803800 0.594000 +vn -0.092300 0.326900 0.940500 +vn -0.164600 0.616100 0.770300 +vn -0.097200 0.623300 0.775900 +vn -0.948800 0.093000 -0.301700 +vn 0.152800 0.902500 0.402600 +vn 0.715800 0.326900 0.617100 +vn 0.771600 0.403600 0.491600 +vn 0.306700 0.944500 0.117000 +vn -0.188500 0.409600 0.892600 +vn 0.386400 -0.126400 0.913600 +vn 0.360600 0.906700 0.218700 +vn -0.950100 0.234700 -0.205500 +vn -0.975700 -0.194100 0.101700 +vn -0.966700 -0.209900 -0.146300 +vn -0.284000 0.578100 0.764900 +vn 0.640300 0.253600 -0.725000 +vn 0.495800 0.220100 0.840100 +vn 0.405600 0.217400 0.887800 +vn -0.542800 0.313300 0.779200 +vn -0.775700 -0.102500 0.622800 +vn -0.146400 -0.348500 -0.925800 +vn -0.595600 -0.351500 -0.722300 +vn -0.511900 -0.401400 -0.759500 +vn 0.298900 0.697300 0.651400 +vn 0.267400 0.700800 0.661300 +vn 0.253700 0.554500 0.792500 +vn -0.066400 0.334700 0.939900 +vn 0.463700 -0.065900 0.883500 +vn 0.366800 0.153400 0.917500 +vn 0.083300 0.674000 0.733900 +vn -0.958500 0.275500 -0.073100 +vn -0.866800 0.467700 0.172800 +vn -0.704900 0.695000 -0.142000 +vn 0.392900 0.850500 -0.349600 +vn -0.418300 0.893200 0.164600 +vn -0.499600 0.845000 -0.190700 +vn 0.544500 -0.837100 0.051900 +vn -0.071000 0.345400 0.935800 +vn -0.333300 0.025500 -0.942400 +vn -0.527300 0.407200 -0.745700 +vn -0.168000 0.390900 -0.904900 +vn 0.298300 0.002100 0.954500 +vn 0.311000 0.001400 0.950400 +vn 0.236400 0.465600 0.852800 +vn -0.257700 0.329500 0.908300 +vn -0.501300 -0.254600 0.826900 +vn -0.065900 0.994300 -0.083700 +vn -0.196800 0.976700 0.084800 +vn 0.183200 0.962900 0.198200 +vn -0.237300 -0.602900 -0.761700 +vn -0.594600 0.024100 0.803600 +vn -0.471400 -0.254400 0.844400 +vn -0.295100 0.003500 0.955400 +vn -0.222000 -0.145800 0.964000 +vn 0.453700 0.341500 0.823100 +vn -0.152600 0.151900 0.976500 +vn -0.443800 0.304300 0.842900 +vn -0.187500 0.534500 0.824100 +vn -0.264900 0.567600 0.779500 +vn 0.679100 -0.097500 -0.727500 +vn 0.641900 -0.131600 -0.755400 +vn 0.587300 -0.011400 -0.809300 +vn 0.251300 0.006300 0.967900 +vn -0.613800 0.789300 -0.017700 +vn -0.272200 -0.248300 0.929600 +vn -0.089300 -0.065700 0.993800 +vn -0.517000 -0.308900 0.798200 +vn -0.695400 -0.236800 0.678500 +vn -0.504600 -0.286000 0.814600 +vn -0.232300 -0.255900 0.938400 +vn -0.223800 0.406800 0.885600 +vn -0.416500 0.548900 0.724700 +vn 0.294800 0.889100 0.350100 +vn -0.003600 -0.983300 0.182000 +vn 0.000500 -0.989000 0.147900 +vn -0.042200 -0.939800 0.339100 +vn -0.153200 0.315400 0.936500 +vn -0.249100 0.654400 0.713900 +vn 0.162900 -0.050100 0.985400 +vn -0.006600 0.086300 0.996200 +vn -0.531000 -0.232600 0.814800 +vn -0.370900 -0.383400 0.845800 +vn -0.316600 -0.175900 0.932100 +vn -0.189500 -0.187800 0.963700 +vn -0.082600 -0.068100 0.994200 +vn -0.081900 0.213500 0.973500 +vn -0.248800 0.676200 0.693400 +vn -0.797000 0.188000 -0.574000 +vn -0.772600 0.239000 -0.588200 +vn 0.333700 0.929300 0.158200 +vn -0.187400 0.484900 0.854200 +vn -0.204100 0.453200 0.867700 +vn -0.234500 0.766300 0.598100 +vn 0.551500 -0.726200 -0.410400 +vn 0.906500 -0.087000 -0.413000 +vn -0.210200 -0.223900 0.951700 +vn -0.057100 0.069700 0.995900 +vn -0.244000 -0.445400 0.861400 +vn -0.277900 -0.230500 0.932500 +vn -0.115900 -0.029300 0.992800 +vn -0.120500 0.240200 0.963200 +vn -0.157100 0.318200 0.934900 +vn 0.401000 0.466800 0.788200 +vn -0.243200 -0.390900 0.887700 +vn -0.244900 -0.188200 0.951100 +vn -0.194700 -0.076200 0.977900 +vn -0.080400 0.392700 0.916100 +vn -0.027600 0.164200 0.986000 +vn 0.962000 0.187700 -0.198400 +vn -0.017000 0.247500 0.968700 +vn -0.325000 -0.362700 -0.873300 +vn -0.341000 0.931000 0.130100 +vn -0.241800 -0.121100 0.962700 +vn -0.022700 0.086400 0.996000 +vn -0.081700 0.886300 0.455700 +vn -0.265600 0.813400 0.517500 +vn 0.315700 0.197900 0.927900 +vn -0.012200 0.707700 0.706400 +vn -0.942900 0.288900 0.165700 +vn 0.376800 -0.186900 0.907200 +vn 0.250700 -0.011900 0.968000 +vn 0.406900 0.027700 0.913000 +vn 0.757300 -0.111000 0.643500 +vn -0.320800 0.777600 0.540800 +vn 0.564000 0.417100 0.712700 +vn 0.481000 0.452800 0.750700 +vn 0.485000 0.345900 0.803200 +vn 0.454500 -0.148900 0.878200 +vn 0.543100 -0.473900 0.693100 +vn 0.441700 0.306300 0.843200 +vn 0.396100 -0.222900 0.890700 +vn 0.414800 -0.201200 0.887300 +vn 0.137100 -0.876000 0.462400 +vn 0.276800 -0.519900 0.808100 +vn 0.219300 -0.608600 0.762500 +vn 0.496200 0.395000 0.773100 +vn 0.437600 0.259500 0.860900 +vn 0.551000 0.321500 0.770000 +vn 0.572200 0.089900 0.815200 +vn 0.450500 -0.190500 0.872200 +vn 0.488700 -0.114200 0.864900 +vn 0.350300 -0.058400 0.934800 +vn 0.687600 -0.146400 0.711100 +vn 0.854700 -0.094500 0.510300 +vn 0.800100 -0.228100 0.554700 +vn 0.939300 0.105700 -0.326500 +vn -0.336500 0.078100 0.938400 +vn 0.182900 -0.178500 0.966800 +vn 0.768400 0.106100 0.631100 +vn 0.642700 -0.374600 0.668300 +vn -0.187300 -0.495200 -0.848300 +vn -0.023500 -0.609800 -0.792200 +vn 0.449800 -0.448200 0.772500 +vn 0.482100 -0.528300 0.698900 +vn 0.469500 -0.328700 0.819400 +vn 0.682400 -0.608700 -0.404700 +vn 0.685200 -0.661100 -0.305800 +vn 0.675400 -0.582200 -0.452500 +vn 0.686600 -0.090500 -0.721300 +vn 0.709300 -0.206900 -0.673800 +vn 0.771500 -0.264000 -0.578800 +vn 0.434500 0.472900 0.766500 +vn 0.201800 0.755400 0.623400 +vn 0.466000 -0.168400 0.868600 +vn 0.480400 -0.195000 0.855100 +vn 0.473700 -0.201200 0.857400 +vn 0.924200 0.317900 0.211700 +vn -0.701200 0.413900 -0.580600 +vn 0.488300 0.365700 0.792300 +vn 0.430900 -0.235800 0.871000 +vn 0.430100 -0.243300 0.869400 +vn 0.809700 -0.033400 0.585900 +vn 0.129400 -0.351900 0.927000 +vn -0.190400 -0.566900 0.801500 +vn 0.045100 -0.843100 0.535800 +vn 0.649000 0.290400 0.703100 +vn 0.719100 0.529900 -0.449400 +vn 0.802800 0.468300 -0.368900 +vn 0.799600 0.401400 -0.446600 +vn 0.730100 0.211600 0.649700 +vn -0.906900 0.418400 0.049400 +vn -0.928800 0.117300 0.351500 +vn -0.995800 0.080900 -0.042200 +vn 0.347800 0.562100 0.750400 +vn 0.665000 0.364200 0.651900 +vn 0.590300 0.398500 0.701900 +vn 0.522300 0.430300 0.736200 +vn 0.422800 -0.131100 0.896600 +vn 0.292800 0.655400 0.696200 +vn 0.327200 -0.756600 0.566000 +vn -0.002400 -0.712900 -0.701300 +vn 0.781600 -0.421800 0.459500 +vn 0.624300 -0.615200 0.481300 +vn -0.725500 -0.688000 -0.014400 +vn 0.671300 -0.119400 0.731500 +vn 0.782400 0.275900 0.558200 +vn 0.661400 0.141100 0.736600 +vn 0.770500 -0.408000 0.489700 +vn 0.507600 -0.528800 0.680200 +vn 0.583000 -0.699600 0.413100 +vn 0.252900 0.621900 0.741100 +vn 0.244600 0.569200 0.784900 +vn 0.831300 0.060200 0.552600 +vn 0.936800 0.023600 0.349000 +vn 0.479900 -0.744100 0.464700 +vn 0.530100 -0.802500 0.273800 +vn 0.820400 -0.250300 0.514000 +vn 0.766200 0.314000 0.560600 +vn 0.835900 -0.100800 0.539600 +vn 0.784300 -0.272700 0.557200 +vn 0.817000 -0.126600 0.562500 +vn 0.727800 -0.057200 0.683300 +vn 0.722100 -0.195200 0.663600 +vn 0.825600 0.226100 0.517000 +vn 0.838400 0.325900 0.436800 +vn 0.757000 0.343100 0.556000 +vn -0.116800 0.109500 -0.987100 +vn -0.082400 0.219100 -0.972200 +vn 0.581400 -0.744300 0.328300 +vn 0.406000 -0.851000 0.333000 +vn 0.727500 -0.558700 0.398100 +vn 0.819300 0.074200 0.568500 +vn 0.929000 -0.331200 -0.164600 +vn 0.672100 0.389800 0.629500 +vn 0.806100 -0.035500 0.590700 +vn 0.741100 -0.040100 0.670200 +vn 0.701200 -0.051700 0.711100 +vn 0.611500 0.056000 0.789200 +vn 0.593600 0.083200 0.800400 +vn 0.520200 0.141300 0.842200 +vn 0.346600 0.614200 0.709000 +vn 0.708300 0.367600 0.602600 +vn 0.574800 -0.230900 0.785000 +vn 0.561500 -0.035800 0.826700 +vn 0.557400 -0.056700 0.828300 +vn 0.766400 -0.019500 0.642000 +vn 0.828700 0.066400 0.555700 +vn 0.748200 0.038300 0.662400 +vn 0.746100 0.131800 0.652600 +vn -0.032500 0.399500 -0.916100 +vn -0.015500 0.392800 -0.919500 +vn -0.011800 0.318600 -0.947800 +vn 0.407300 0.095500 0.908300 +vn 0.674700 0.276500 0.684300 +vn 0.863100 0.359000 0.355200 +vn 0.774400 0.272300 0.571100 +vn 0.459900 0.228700 0.857900 +vn 0.531300 -0.115000 0.839300 +vn 0.543100 -0.555600 0.629500 +vn 0.355300 0.522500 0.775000 +vn 0.406100 0.509400 0.758600 +vn 0.511200 0.296900 0.806500 +vn 0.523000 -0.498000 0.691600 +vn 0.863200 0.018100 0.504500 +vn 0.823100 -0.013400 0.567600 +vn 0.757100 0.074200 0.649000 +vn -0.044500 0.269300 -0.962000 +vn -0.119800 0.379400 -0.917400 +vn 0.840800 -0.052000 0.538900 +vn 0.520600 -0.345500 0.780800 +vn 0.624500 -0.371700 0.686900 +vn 0.563600 -0.335500 0.754800 +vn 0.461200 -0.167800 0.871300 +vn 0.669600 -0.417900 0.614000 +vn 0.599000 -0.113200 0.792700 +vn 0.557400 -0.184600 0.809400 +vn 0.391900 0.035500 0.919300 +vn 0.475100 -0.188800 0.859400 +vn 0.707900 -0.375600 0.598100 +vn 0.568400 -0.558500 -0.604100 +vn 0.597900 -0.500700 0.625900 +vn 0.627200 -0.316300 0.711800 +vn 0.560700 0.351500 0.749700 +vn 0.563400 0.446300 0.695300 +vn 0.607300 0.357500 0.709400 +vn 0.742400 -0.084800 0.664600 +vn 0.555000 -0.429800 0.712200 +vn 0.699700 -0.024800 0.714000 +vn -0.030100 0.371400 -0.927900 +vn 0.614200 -0.004400 0.789100 +vn -0.200700 -0.084300 0.976000 +vn 0.177000 0.063000 0.982200 +vn -0.830300 -0.315300 -0.459400 +vn 0.471500 -0.123000 0.873200 +vn 0.726800 -0.587100 0.356400 +vn 0.628500 -0.406800 0.662800 +vn 0.465200 -0.882700 0.066100 +vn 0.516700 0.484000 0.706200 +vn 0.753000 0.293600 0.588800 +vn 0.629200 0.410800 0.659700 +vn -0.517300 -0.538100 -0.665500 +vn 0.171000 -0.711600 -0.681400 +vn 0.469600 -0.312900 0.825500 +vn 0.629800 0.046800 0.775400 +vn 0.706500 0.015500 0.707500 +vn 0.467300 -0.452700 0.759400 +vn 0.420100 0.530900 0.735900 +vn 0.591600 0.233400 0.771700 +vn 0.705800 0.021100 0.708000 +vn 0.734600 -0.135900 0.664700 +vn 0.630800 0.344500 0.695300 +vn 0.562100 -0.605100 0.563800 +vn 0.549500 0.412900 0.726300 +vn 0.271400 0.734800 0.621600 +vn 0.621800 0.214200 0.753300 +vn 0.559900 -0.389800 0.731100 +vn 0.648900 -0.207300 0.732000 +vn 0.614500 0.363900 0.699900 +vn 0.494700 0.462900 0.735400 +vn 0.608200 0.365500 0.704600 +vn 0.466900 0.489100 0.736700 +vn 0.577600 0.188800 0.794200 +vn 0.774800 -0.018200 0.631900 +vn 0.536300 0.480900 -0.693600 +vn 0.053200 -0.731900 -0.679300 +vn 0.111500 -0.753500 -0.647900 +vn 0.702000 0.063900 0.709200 +vn -0.139100 -0.500000 0.854700 +vn 0.291700 0.207300 0.933800 +vn 0.463800 -0.856500 0.226300 +vn 0.262300 0.688800 0.675800 +vn 0.894900 0.291200 0.338100 +vn 0.583700 -0.787200 -0.199200 +vn 0.326600 0.597300 0.732400 +vn 0.520100 0.134900 0.843300 +vn 0.612400 -0.041000 0.789500 +vn 0.258300 -0.120000 0.958600 +vn 0.695200 0.411600 0.589300 +vn 0.813100 -0.010700 0.582000 +vn 0.125900 -0.887800 0.442500 +vn 0.031500 -0.913100 0.406400 +vn 0.030400 -0.995900 0.084600 +vn 0.554900 -0.442200 0.704600 +vn -0.355200 0.354700 -0.864900 +vn -0.429500 0.154400 -0.889700 +vn -0.354400 0.230400 -0.906200 +vn 0.747800 0.202400 0.632300 +vn 0.841400 0.181600 0.509000 +vn 0.232700 -0.470000 0.851400 +vn 0.316500 0.124200 0.940400 +vn 0.595300 -0.430400 0.678500 +vn 0.694700 -0.430400 0.576300 +vn 0.697000 0.418300 0.582400 +vn 0.569500 0.489900 0.660000 +vn 0.742900 -0.043500 0.668000 +vn 0.598800 -0.061000 0.798500 +vn 0.552000 -0.212800 0.806200 +vn 0.598300 -0.158900 0.785400 +vn 0.639500 -0.228000 0.734200 +vn 0.608100 -0.124900 0.784000 +vn 0.828700 0.127800 0.544800 +vn 0.904500 0.071500 0.420400 +vn -0.337400 -0.924000 -0.179800 +vn -0.353100 -0.914300 -0.198100 +vn 0.508500 0.076600 0.857700 +vn 0.747100 -0.014900 0.664500 +vn 0.910600 0.064300 0.408200 +vn 0.505900 -0.414400 0.756500 +vn 0.549900 -0.123900 0.826000 +vn 0.527600 -0.013100 0.849400 +vn 0.469900 0.319400 0.822900 +vn 0.599600 0.380300 0.704100 +vn -0.016300 -0.476700 -0.878900 +vn 0.614800 -0.109700 0.781000 +vn 0.532300 -0.107700 0.839600 +vn 0.337600 -0.773000 -0.537000 +vn 0.418200 -0.698500 -0.580700 +vn 0.457300 -0.800800 -0.386600 +vn -0.494200 0.449700 0.744000 +vn 0.820700 0.350500 0.451100 +vn 0.967000 -0.133200 0.217200 +vn 0.888200 -0.239900 0.391700 +vn 0.621200 0.286500 0.729300 +vn 0.874200 0.483000 0.049300 +vn 0.604800 -0.187200 0.774100 +vn 0.251800 -0.859400 -0.444900 +vn 0.548600 0.094500 0.830700 +vn -0.815100 0.339500 -0.469300 +vn -0.692000 -0.172900 -0.700800 +vn -0.385200 0.378000 -0.841800 +vn 0.826700 0.115600 0.550600 +vn 0.802900 0.306700 0.511000 +vn 0.405700 0.107200 0.907700 +vn 0.587300 -0.204600 0.783000 +vn 0.543200 0.198700 0.815700 +vn 0.640600 -0.078000 0.763800 +vn 0.635800 -0.207900 0.743300 +vn 0.655600 -0.338700 0.674800 +vn 0.622300 0.106700 0.775400 +vn 0.592800 0.054100 0.803500 +vn 0.927900 0.234300 0.289800 +vn -0.743300 -0.651800 0.150400 +vn 0.804100 0.318600 0.501900 +vn 0.541500 0.431900 0.721200 +vn 0.418500 0.458700 0.783800 +vn 0.570100 -0.134200 0.810500 +vn -0.981500 -0.159100 0.105900 +vn -0.992400 -0.086300 -0.087900 +vn 0.561800 -0.032000 0.826600 +vn 0.616600 -0.167100 0.769300 +vn 0.737900 0.176700 0.651400 +vn 0.235500 0.011600 0.971800 +vn 0.517200 -0.459800 0.721800 +vn 0.694200 -0.255100 -0.673000 +vn 0.771000 -0.242200 -0.588900 +vn 0.680400 -0.401400 -0.613100 +vn -0.536800 0.746300 -0.393500 +vn -0.592200 0.723500 -0.354700 +vn -0.351900 -0.256200 -0.900300 +vn 0.870000 0.144200 0.471400 +vn -0.490100 0.144100 -0.859600 +vn -0.565400 0.277500 -0.776700 +vn -0.443000 0.222500 -0.868400 +vn 0.134000 -0.980400 -0.144000 +vn 0.214000 -0.935100 -0.282300 +vn 0.328900 0.551300 0.766700 +vn 0.757500 0.197100 0.622300 +vn 0.754800 0.297400 0.584600 +vn 0.889900 -0.454100 0.042600 +vn 0.964100 -0.265100 0.014000 +vn 0.643100 -0.003600 0.765700 +vn -0.416400 -0.081700 -0.905500 +vn -0.608600 -0.478200 0.633200 +vn -0.739700 0.099000 0.665600 +vn -0.596000 -0.426600 0.680200 +vn -0.961000 -0.273400 0.040900 +vn 0.829200 0.043200 0.557300 +vn 0.886900 -0.023700 0.461300 +vn 0.174500 -0.028000 0.984300 +vn -0.149600 -0.676200 -0.721300 +vn -0.215200 -0.568300 -0.794200 +vn 0.774900 0.379700 0.505200 +vn -0.279700 0.310000 -0.908600 +vn -0.542100 0.370000 -0.754400 +vn 0.254700 0.685800 0.681700 +vn 0.211300 0.773700 0.597200 +vn -0.241400 -0.945800 -0.217100 +vn 0.998900 0.045300 0.011200 +vn 0.414400 0.784800 -0.460700 +vn 0.199800 -0.632400 0.748400 +vn 0.159000 0.130300 0.978600 +vn -0.094000 -0.010000 0.995500 +vn 0.379500 -0.705600 0.598400 +vn 0.785700 -0.574400 -0.229500 +vn 0.784800 -0.544500 -0.295900 +vn 0.751700 -0.590700 -0.293200 +vn -0.912100 -0.402900 0.075400 +vn 0.053500 0.735300 -0.675600 +vn 0.714200 0.693300 0.095800 +vn 0.384600 -0.110200 0.916400 +vn 0.103900 0.847900 0.519800 +vn 0.907100 -0.212400 0.363300 +vn 0.785900 -0.553500 0.275800 +vn 0.914300 -0.337500 0.223900 +vn 0.760400 -0.186600 0.622000 +vn 0.563500 0.766700 -0.307600 +vn 0.461300 0.699800 -0.545400 +vn 0.185800 0.892900 -0.410000 +vn 0.777100 -0.627300 0.050800 +vn 0.710700 0.701500 -0.052800 +vn 0.908700 0.390900 0.146500 +vn -0.156200 -0.314600 -0.936300 +vn 0.213100 0.211200 -0.953900 +vn 0.562500 0.580300 -0.588900 +vn 0.304700 -0.076200 0.949400 +vn -0.002600 -0.996800 0.079800 +vn 0.089800 -0.949800 -0.299700 +vn -0.830500 0.487700 0.269100 +vn -0.445000 0.829100 0.338400 +vn -0.179500 0.892900 0.412900 +vn -0.072600 0.955700 0.285300 +vn 0.756700 -0.265800 0.597200 +vn 0.577500 -0.168200 0.798900 +vn 0.550200 0.103200 0.828600 +vn -0.489600 0.076300 -0.868600 +vn -0.571200 0.229400 -0.788100 +vn -0.526300 0.050000 -0.848800 +vn 0.668700 0.395600 0.629500 +vn -0.759300 -0.637700 0.129600 +vn 0.615300 -0.276700 0.738100 +vn 0.984800 0.125700 0.119900 +vn 0.876200 0.423200 0.230300 +vn 0.920600 0.272600 0.279500 +vn 0.588800 -0.630700 -0.505400 +vn 0.589200 -0.790000 0.169800 +vn 0.304300 -0.950700 0.060000 +vn 0.518500 -0.837900 0.170300 +vn -0.168000 0.255700 -0.952000 +vn 0.443600 0.704400 0.554100 +vn 0.320100 0.683100 0.656500 +vn 0.394000 -0.140800 0.908200 +vn 0.483400 -0.474200 -0.735800 +vn -0.912200 0.023000 0.409000 +vn -0.959300 0.116500 0.257200 +vn -0.952000 -0.161700 0.260000 +vn -0.362800 0.727000 -0.582900 +vn 0.948300 0.028200 0.316100 +vn 0.875600 0.250300 0.413000 +vn 0.042700 -0.828500 0.558200 +vn 0.803900 0.343700 0.485300 +vn 0.663200 -0.624000 0.413200 +vn 0.432400 0.150700 0.889000 +vn 0.357200 0.454600 0.815900 +vn -0.083100 -0.021100 -0.996300 +vn -0.070700 0.019600 -0.997300 +vn -0.068000 0.089000 -0.993700 +vn 0.317000 -0.100500 0.943100 +vn 0.027600 -0.998700 -0.043100 +vn 0.033900 -0.999000 -0.029100 +vn 0.025700 -0.999400 -0.023800 +vn 0.968600 0.089200 0.232100 +vn -0.163400 0.596500 -0.785800 +vn 0.460400 -0.864700 -0.200800 +vn 0.300200 -0.034800 0.953200 +vn 0.561600 0.225000 0.796200 +vn 0.831300 -0.073600 -0.550900 +vn 0.497700 -0.217300 0.839700 +vn -0.535000 0.761200 -0.366500 +vn -0.534400 0.792900 -0.292600 +vn -0.690900 0.461500 -0.556400 +vn 0.906800 -0.025000 -0.420700 +vn -0.079300 -0.016800 -0.996700 +vn 0.345100 0.280500 0.895700 +vn 0.297200 0.146500 0.943500 +vn 0.974700 0.174200 -0.140000 +vn 0.437300 -0.325400 -0.838300 +vn 0.591400 0.253600 0.765400 +vn 0.993900 -0.106200 0.030700 +vn -0.431800 -0.048000 0.900700 +vn -0.147600 0.788600 0.596800 +vn -0.578600 -0.803600 -0.138900 +vn -0.081600 0.177100 -0.980800 +vn 0.659600 -0.028600 0.751000 +vn 0.382300 0.752400 0.536400 +vn -0.722300 0.604400 0.336100 +vn -0.753000 0.583800 0.303700 +vn -0.940300 0.281600 0.191100 +vn 0.831000 -0.123700 0.542400 +vn -0.194200 0.145900 -0.970000 +vn 0.111200 0.943400 -0.312300 +vn -0.762900 -0.625400 0.164100 +vn 0.842600 0.524000 -0.124300 +vn -0.028700 -0.119000 -0.992500 +vn -0.084600 -0.062700 -0.994400 +vn -0.021900 -0.054200 -0.998300 +vn -0.839900 0.390300 0.376900 +vn -0.975900 0.093500 0.197200 +vn -0.939100 0.239900 0.246100 +vn 0.933200 -0.345700 -0.097800 +vn -0.916800 -0.343000 0.204200 +vn -0.981700 0.165000 0.095400 +vn 0.935600 -0.332400 -0.118400 +vn 0.961100 -0.240900 -0.134600 +vn 0.998300 -0.055800 -0.018600 +vn 0.996700 0.078300 -0.021100 +vn 0.959200 0.259900 0.110900 +vn -0.904800 -0.424200 -0.036700 +vn -0.516700 0.061300 0.853900 +vn -0.768000 0.159800 0.620100 +vn -0.597000 -0.472600 0.648200 +vn -0.757300 -0.586300 0.287500 +vn -0.967900 -0.082600 0.237500 +vn -0.285300 -0.678400 0.677000 +vn 0.014300 -0.998800 0.045600 +vn 0.016700 -0.997200 0.072300 +vn 0.164100 -0.983400 0.077600 +vn -0.871800 0.309200 0.379800 +vn -0.876500 -0.015100 0.481100 +vn -0.976300 0.041900 0.212300 +vn -0.930200 0.330500 0.159700 +vn -0.514800 0.516300 -0.684400 +vn 0.381900 -0.888700 -0.253600 +vn -0.908800 0.386100 0.158100 +vn 0.989300 0.138800 0.045000 +vn -0.994300 0.106000 0.007000 +vn 0.610800 0.224500 -0.759200 +vn -0.926700 -0.295100 -0.232600 +vn 0.643900 -0.200000 -0.738500 +vn 0.744900 -0.180100 -0.642300 +vn 0.228300 -0.772500 0.592500 +vn 0.367400 -0.755000 0.543100 +vn 0.281200 -0.883300 0.375000 +vn 0.150200 -0.987000 -0.057400 +vn 0.032000 -0.999000 0.031700 +vn 0.538200 0.137700 -0.831500 +vn 0.646600 0.151200 -0.747600 +vn 0.895900 0.231700 0.378900 +vn 0.934700 -0.220400 -0.278700 +vn -0.954200 -0.035000 -0.297200 +vn -0.942000 0.248700 0.225300 +vn -0.879200 0.274100 0.389700 +vn -0.665800 0.669100 -0.330200 +vn 0.961100 0.227900 0.155600 +vn 0.728100 -0.580300 -0.364800 +vn -0.833900 0.396700 -0.383500 +vn 0.723700 0.355800 0.591300 +vn -0.852600 -0.314300 -0.417500 +vn 0.538400 -0.524900 -0.659200 +vn 0.407000 -0.831400 -0.378200 +vn 0.134500 0.772700 -0.620300 +vn 0.199800 0.777000 -0.596900 +vn 0.182000 0.829100 -0.528600 +vn 0.796500 -0.176600 -0.578300 +vn 0.810700 -0.021300 -0.585100 +vn 0.717900 -0.089900 -0.690300 +vn 0.762000 -0.442600 -0.472600 +vn 0.704100 -0.322500 -0.632600 +vn 0.480500 -0.394000 -0.783500 +vn 0.301300 -0.643000 -0.704100 +vn -0.922900 0.199600 -0.329100 +vn 0.772100 -0.013700 -0.635300 +vn 0.748200 -0.076100 -0.659000 +vn 0.727000 -0.071600 -0.682900 +vn -0.047000 0.325900 -0.944200 +vn -0.878800 -0.332100 0.342600 +vn -0.774200 -0.471200 -0.422500 +vn -0.796000 0.604300 -0.035400 +vn -0.902000 -0.421100 0.094900 +vn 0.861500 0.133300 -0.489800 +vn 0.752300 0.249300 -0.609800 +vn 0.096000 0.273700 -0.957000 +vn 0.011100 0.643100 -0.765600 +vn -0.034800 0.303800 -0.952100 +vn -0.166600 -0.848800 -0.501700 +vn -0.341900 -0.596100 -0.726400 +vn 0.586700 0.058400 -0.807700 +vn 0.667300 -0.028500 -0.744200 +vn 0.769100 0.279600 -0.574700 +vn 0.672700 0.267700 -0.689700 +vn 0.755600 0.298100 -0.583200 +vn -0.693600 -0.702900 0.157600 +vn -0.884000 -0.093400 -0.458000 +vn -0.819500 -0.352900 -0.451600 +vn 0.773300 -0.107200 -0.624800 +vn -0.946300 0.019800 -0.322500 +vn 0.748200 -0.213100 -0.628300 +vn 0.817800 -0.236500 -0.524700 +vn 0.654300 -0.117500 -0.747100 +vn 0.668300 -0.105300 -0.736400 +vn 0.655900 -0.072000 -0.751400 +vn -0.910100 0.028700 -0.413400 +vn 0.206300 0.926100 -0.315900 +vn 0.245600 0.957700 -0.149800 +vn 0.255100 0.944300 -0.207800 +vn -0.065600 0.841500 -0.536200 +vn 0.021600 0.847800 -0.529800 +vn -0.040800 0.733400 -0.678500 +vn -0.278400 -0.520700 -0.807000 +vn -0.234800 -0.225800 -0.945400 +vn -0.180500 0.821000 0.541600 +vn 0.580400 -0.722500 0.375700 +vn 0.711400 -0.597300 0.370300 +vn -0.995500 -0.071700 0.061500 +vn -0.997700 0.056000 0.036300 +vn 0.695100 0.330000 -0.638700 +vn 0.804600 -0.375300 -0.460000 +vn 0.783100 -0.536800 -0.313900 +vn -0.978900 -0.149000 0.139700 +vn 0.575500 -0.788000 -0.218800 +vn -0.475200 -0.432900 0.766000 +vn -0.336800 -0.528800 0.779000 +vn -0.556000 0.616000 -0.558100 +vn -0.245100 0.618800 -0.746400 +vn -0.257800 0.857000 -0.446200 +vn -0.497500 0.729500 -0.469400 +vn 0.832500 -0.027800 -0.553300 +vn 0.842300 -0.144600 -0.519300 +vn -0.689300 0.300500 -0.659100 +vn -0.547700 0.355000 -0.757600 +vn 0.874000 -0.203500 -0.441300 +vn 0.771100 -0.344200 -0.535700 +vn 0.693700 -0.666600 -0.272700 +vn 0.658700 -0.604100 -0.448600 +vn 0.570000 -0.779700 -0.259000 +vn -0.932100 -0.352100 0.084600 +vn -0.563100 0.727300 0.392300 +vn -0.921900 0.360300 0.142000 +vn -0.862800 0.436500 0.254700 +vn 0.816600 -0.266900 -0.511800 +vn 0.394200 -0.577200 0.715100 +vn 0.525900 -0.824500 0.209100 +vn 0.353300 -0.924300 0.144000 +vn -0.400000 0.771800 0.494200 +vn -0.476600 0.733800 0.484100 +vn -0.966600 0.152000 -0.206500 +vn 0.039600 -0.928700 -0.368600 +vn 0.120500 -0.752700 -0.647200 +vn 0.058900 -0.973200 -0.222400 +vn 0.603600 -0.017900 -0.797100 +vn 0.328500 0.060100 -0.942600 +vn -0.225900 -0.326800 -0.917700 +vn -0.667700 -0.358500 -0.652400 +vn -0.491400 0.870700 0.020100 +vn -0.421100 0.822700 0.381800 +vn -0.678600 0.649800 0.342200 +vn -0.941200 -0.132100 -0.310800 +vn 0.204100 -0.821700 0.532100 +vn -0.867300 0.175700 -0.465700 +vn -0.742100 0.524600 -0.417100 +vn -0.676800 0.478600 -0.559300 +vn 0.647100 -0.550000 0.527900 +vn -0.215700 0.711400 -0.668800 +vn -0.101800 0.485500 -0.868300 +vn -0.341700 0.514100 -0.786700 +vn 0.701300 0.423600 -0.573300 +vn 0.612500 0.355200 -0.706100 +vn -0.719300 -0.653800 0.234700 +vn 0.918800 0.185000 0.348600 +vn -0.383900 -0.369600 0.846100 +vn -0.510000 -0.272400 0.815900 +vn -0.027100 0.356500 -0.933900 +vn 0.053500 -0.722500 -0.689200 +vn 0.232200 -0.470800 0.851100 +vn 0.613700 -0.062300 -0.787000 +vn -0.076800 -0.406600 -0.910300 +vn -0.025400 -0.368700 -0.929200 +vn 0.559400 -0.748000 0.357100 +vn -0.111700 0.646000 -0.755100 +vn 0.930100 0.312500 0.193100 +vn -0.770600 0.603200 -0.205500 +vn -0.692800 0.696600 0.186300 +vn 0.901700 -0.120000 -0.415300 +vn 0.858300 0.464800 0.217300 +vn -0.092700 0.882200 -0.461700 +vn 0.078800 0.861800 -0.501100 +vn 0.004900 0.847700 -0.530400 +vn 0.718800 -0.425700 -0.549600 +vn 0.254700 0.504900 -0.824700 +vn 0.560000 0.070500 -0.825400 +vn 0.206900 0.426800 -0.880300 +vn 0.675100 -0.110600 -0.729400 +vn -0.870800 0.371300 0.322200 +vn 0.815800 0.555700 -0.160000 +vn 0.478500 -0.347900 -0.806200 +vn 0.004300 -0.990900 0.134100 +vn 0.000500 -0.992200 0.124500 +vn -0.069700 -0.858600 0.507900 +vn -0.141300 -0.816200 0.560200 +vn 0.040100 -0.989300 0.140500 +vn 0.116100 -0.946600 -0.300800 +vn -0.693500 -0.379300 -0.612500 +vn -0.590900 -0.598700 -0.540700 +vn -0.279500 -0.776800 -0.564300 +vn -0.982400 0.129600 -0.134700 +vn -0.889400 -0.415400 -0.190800 +vn 0.994600 0.069400 0.077400 +vn -0.867000 -0.396000 -0.302300 +vn -0.134000 -0.622500 -0.771000 +vn 0.907300 0.319200 0.273800 +vn 0.178700 -0.500900 -0.846800 +vn 0.949400 0.126300 0.287300 +vn -0.206300 -0.721600 0.660800 +vn -0.385200 -0.784200 0.486400 +vn -0.241500 -0.887200 0.393000 +vn -0.503400 0.668400 0.547600 +vn 0.254500 0.421100 -0.870600 +vn 0.159900 0.479100 -0.863000 +vn 0.195500 0.675500 -0.710900 +vn 0.654000 0.079500 -0.752200 +vn 0.958300 0.152400 0.241700 +vn 0.659800 -0.739900 0.131100 +vn -0.400800 -0.248400 -0.881800 +vn -0.744200 -0.220000 -0.630700 +vn 0.926100 0.271100 0.262500 +vn 0.847500 0.436700 0.301700 +vn -0.786900 -0.530100 0.315800 +vn -0.837900 -0.410300 0.359800 +vn -0.797500 -0.553700 0.239500 +vn 0.175600 -0.955800 -0.235700 +vn -0.173700 -0.219900 -0.959900 +vn -0.495700 -0.199900 -0.845200 +vn 0.643000 -0.694900 0.321900 +vn 0.106800 -0.964200 -0.242600 +vn -0.005800 -0.998500 -0.054400 +vn 0.054800 -0.848000 -0.527000 +vn 0.959000 0.130700 0.251400 +vn 0.516800 -0.435500 -0.737000 +vn 0.837900 0.516900 0.175500 +vn -0.742100 -0.002600 -0.670200 +vn 0.574700 0.723600 0.382200 +vn 0.660300 0.748000 0.066900 +vn 0.659800 0.630200 0.409200 +vn 0.669700 0.741900 -0.032200 +vn -0.590700 -0.745800 -0.307700 +vn -0.552900 0.783700 0.283100 +vn -0.267900 0.857600 0.438900 +vn 0.461300 0.846900 -0.264400 +vn 0.679900 0.733300 -0.001200 +vn 0.500400 0.836000 0.225000 +vn 0.263800 0.808400 0.526200 +vn -0.073900 0.990900 0.112400 +vn -0.106200 0.952700 0.284800 +vn -0.558900 0.827500 -0.052900 +vn -0.612400 0.781300 -0.120100 +vn -0.502200 0.857400 0.112200 +vn 0.125800 0.937200 0.325400 +vn -0.010600 0.957200 0.289400 +vn 0.289800 0.942700 -0.165400 +vn 0.266200 0.963700 0.021700 +vn 0.153800 0.942100 0.297900 +vn -0.047800 0.901900 0.429300 +vn -0.147700 0.750700 0.643800 +vn 0.092800 0.995600 -0.007200 +vn -0.034300 0.988700 0.146000 +vn 0.099100 0.966300 -0.237500 +vn 0.357000 0.871100 0.337200 +vn -0.628200 0.279700 -0.726000 +vn -0.607800 0.347400 -0.714000 +vn 0.640600 0.767800 -0.010000 +vn -0.036100 0.453700 -0.890400 +vn 0.079000 0.996700 0.015400 +vn 0.167800 0.985800 -0.001900 +vn -0.024800 0.997200 0.069900 +vn -0.142600 0.872100 0.468100 +vn -0.779100 0.493100 -0.387000 +vn -0.407300 0.896800 -0.172800 +vn -0.356200 0.905300 -0.231300 +vn 0.129300 0.988200 0.082100 +vn 0.041800 0.984700 0.169100 +vn 0.103200 0.895100 0.433600 +vn 0.304600 0.895700 -0.324000 +vn 0.288900 0.948100 -0.132600 +vn 0.145500 0.963700 -0.224000 +vn -0.015700 0.999200 -0.035500 +vn -0.080700 0.930100 0.358100 +vn -0.683600 0.515800 -0.516300 +vn 0.108000 0.986700 -0.121700 +vn 0.018700 0.998200 -0.056900 +vn -0.097100 0.994100 -0.046900 +vn 0.530300 0.800100 0.280400 +vn 0.245400 0.968800 0.034600 +vn 0.340900 0.940100 0.001600 +vn 0.204700 0.953800 0.219900 +vn 0.735900 0.630500 0.246800 +vn 0.638000 0.724800 0.260000 +vn 0.609900 0.719100 0.333000 +vn 0.019400 0.862000 0.506500 +vn -0.925300 -0.349700 0.146900 +vn -0.760300 0.592800 0.265500 +vn -0.463000 -0.594700 0.657200 +vn -0.877700 -0.234700 0.417900 +vn -0.736100 0.601600 -0.310200 +vn -0.922200 0.153800 -0.354700 +vn 0.533900 0.796700 0.283200 +vn 0.734700 0.533500 0.419000 +vn -0.043100 0.907500 0.417700 +vn -0.410600 0.904100 0.117900 +vn 0.104300 0.762400 -0.638700 +vn 0.013200 0.999400 0.030600 +vn 0.283300 0.947600 -0.147600 +vn -0.032200 0.882500 0.469200 +vn -0.232100 0.926100 -0.297400 +vn -0.471800 0.775100 0.420200 +vn -0.735800 0.570700 0.364500 +vn -0.437700 0.770600 0.463200 +vn 0.020100 0.936500 -0.350000 +vn -0.373500 -0.191500 -0.907600 +vn -0.978500 0.180700 0.098900 +vn 0.015400 0.817000 0.576300 +vn -0.545400 0.803200 -0.239600 +vn -0.880000 0.302700 0.366000 +vn -0.872000 0.481500 0.087900 +vn -0.965800 0.249400 0.071400 +vn -0.125900 0.953100 -0.275200 +vn 0.239900 0.967100 -0.084900 +vn -0.820600 0.545500 -0.170500 +vn 0.659100 0.594500 0.460500 +vn -0.567200 0.501100 -0.653500 +vn -0.528600 0.229500 -0.817300 +vn -0.762300 0.299500 -0.573700 +vn 0.816100 0.577400 -0.021500 +vn -0.856300 0.256900 0.448100 +vn -0.907400 0.295300 0.299000 +vn 0.777300 0.612700 0.142700 +vn -0.988400 -0.149000 -0.030200 +vn 0.765700 0.641400 0.046200 +vn -0.075300 -0.221300 -0.972300 +vn 0.009500 -0.353600 -0.935300 +vn -0.680700 0.732300 0.020300 +vn 0.762400 0.560200 -0.323600 +vn 0.533900 0.607800 0.587800 +vn 0.575500 0.716200 0.394800 +vn -0.585700 0.595800 0.549400 +vn -0.469000 0.789600 0.395600 +vn 0.100800 0.414500 -0.904400 +vn 0.063100 0.460600 -0.885400 +vn 0.248000 0.384100 -0.889300 +vn 0.751700 0.659000 -0.023800 +vn 0.708900 0.693000 0.131300 +vn 0.668500 0.689500 0.278700 +vn 0.740100 0.659400 -0.131900 +vn 0.671400 0.741000 0.003900 +vn 0.609500 0.777000 0.157400 +vn 0.651600 0.651400 -0.388600 +vn 0.670200 0.700400 -0.245600 +vn 0.740900 0.624900 -0.245900 +vn -0.885600 0.229800 -0.403600 +vn -0.216500 0.918500 -0.330700 +vn -0.135600 0.884500 -0.446400 +vn -0.577700 0.183800 -0.795300 +vn 0.641100 0.756600 -0.128300 +vn 0.519200 0.790600 0.324500 +vn 0.761900 0.518200 -0.388500 +vn 0.199600 0.625500 0.754200 +vn -0.787500 -0.584500 0.195300 +vn 0.415800 0.830200 0.371300 +vn 0.030500 0.874100 0.484700 +vn 0.566800 0.821600 -0.060800 +vn 0.554500 0.830900 0.046400 +vn 0.489000 0.852000 0.186700 +vn 0.340500 0.801300 0.491800 +vn 0.571800 0.758300 -0.313200 +vn 0.554300 0.813500 -0.175500 +vn 0.440500 0.892000 0.100800 +vn 0.391600 0.878900 0.272500 +vn 0.490700 0.823400 -0.284900 +vn -0.020800 0.247600 -0.968600 +vn -0.776500 0.342200 -0.529100 +vn -0.769700 -0.194700 -0.607900 +vn -0.428700 -0.426100 -0.796600 +vn -0.826300 -0.562900 -0.018000 +vn -0.486900 0.609700 0.625400 +vn -0.845500 -0.358000 0.396200 +vn -0.973700 -0.012700 -0.227500 +vn -0.374900 -0.841200 0.389700 +vn -0.275300 -0.898800 0.341200 +vn -0.353400 0.745600 0.565000 +vn -0.485200 0.746900 0.454600 +vn -0.665400 0.519500 0.536000 +vn -0.347100 0.742700 0.572500 +vn -0.318400 0.603600 0.730900 +vn -0.442700 0.065700 0.894300 +vn -0.922500 0.260900 0.284600 +vn -0.555800 -0.061700 -0.829000 +vn -0.324400 -0.069900 -0.943300 +vn -0.580000 0.211800 -0.786600 +vn -0.432400 0.719000 0.544100 +vn -0.822000 -0.329300 0.464600 +vn -0.744100 -0.271200 0.610500 +vn -0.776500 0.232400 0.585600 +vn -0.238200 -0.724700 -0.646600 +vn -0.798800 -0.319100 0.509900 +vn -0.807900 -0.335300 0.484500 +vn -0.872500 0.102600 0.477700 +vn -0.700800 0.447600 0.555400 +vn 0.133400 0.328300 -0.935100 +vn 0.048100 -0.998000 -0.040800 +vn 0.312600 -0.944700 -0.098700 +vn 0.079500 -0.992600 -0.091000 +vn -0.744800 0.455900 -0.487100 +vn -0.608100 0.503200 0.614000 +vn -0.560400 0.228600 0.796000 +vn -0.762400 -0.227100 0.605900 +vn -0.624800 0.478700 0.616800 +vn -0.423200 0.249600 -0.870900 +vn -0.637200 0.689800 0.343600 +vn -0.734200 0.257100 0.628300 +vn -0.690500 0.702000 -0.174100 +vn -0.487900 0.795600 0.359200 +vn -0.639300 -0.343300 0.688000 +vn -0.868600 0.405400 0.284800 +vn -0.980200 0.097800 0.172200 +vn -0.944200 0.292600 0.150900 +vn -0.609300 0.372300 0.700100 +vn -0.661300 0.374100 0.650100 +vn -0.822000 -0.051800 0.567100 +vn -0.302500 0.089500 -0.948900 +vn -0.319600 0.139900 -0.937200 +vn -0.358800 0.097500 -0.928300 +vn -0.390900 0.012600 -0.920300 +vn -0.361700 0.150100 -0.920100 +vn -0.330000 0.116500 -0.936800 +vn -0.765500 0.018100 -0.643200 +vn -0.634100 -0.278500 -0.721300 +vn -0.665900 -0.640400 0.382500 +vn -0.327600 -0.852600 0.407100 +vn -0.716300 0.327500 0.616100 +vn -0.977900 0.151200 0.144300 +vn -0.412200 0.832300 0.370600 +vn -0.506100 0.741700 0.440100 +vn -0.277000 -0.818300 0.503600 +vn -0.735000 -0.322000 0.596700 +vn -0.836800 0.539000 -0.096000 +vn -0.604900 0.510500 0.611100 +vn -0.480000 0.655900 0.582600 +vn 0.530000 0.707900 -0.466900 +vn -0.341900 -0.255200 0.904400 +vn -0.496700 -0.128500 0.858400 +vn -0.522000 -0.096900 0.847400 +vn -0.963500 0.143200 -0.226100 +vn -0.290100 -0.212700 0.933000 +vn -0.612300 0.126600 0.780400 +vn -0.681200 0.095600 0.725800 +vn -0.904400 -0.249700 -0.345900 +vn -0.625900 -0.337400 0.703100 +vn -0.629300 -0.489000 0.604100 +vn -0.867900 0.414000 -0.274300 +vn -0.969100 -0.075800 -0.234500 +vn 0.178200 -0.553500 -0.813500 +vn 0.220700 -0.670100 -0.708700 +vn -0.625400 -0.157600 0.764200 +vn -0.424800 -0.320400 0.846700 +vn -0.768200 0.270900 0.580100 +vn -0.610800 0.007000 0.791700 +vn -0.364800 0.223500 -0.903800 +vn -0.423000 0.329400 -0.844100 +vn -0.328800 0.355300 -0.875000 +vn -0.737600 -0.032700 0.674400 +vn -0.717600 -0.116900 0.686600 +vn -0.248300 -0.388000 0.887600 +vn -0.553100 -0.339600 -0.760700 +vn 0.018200 -0.495900 0.868200 +vn -0.053700 0.246100 -0.967700 +vn -0.076700 0.345900 -0.935100 +vn -0.882100 0.455400 0.120200 +vn -0.745500 0.657200 -0.110400 +vn -0.556800 0.128800 -0.820600 +vn -0.671900 0.274600 -0.687900 +vn -0.509500 0.185800 -0.840100 +vn -0.790900 0.376600 0.482300 +vn 0.290900 0.342000 -0.893500 +vn 0.432200 0.339500 -0.835400 +vn 0.423800 0.294900 -0.856300 +vn -0.815300 -0.528600 -0.236300 +vn -0.809300 0.123200 0.574300 +vn -0.587400 0.188800 -0.787000 +vn -0.903400 0.144100 0.403800 +vn -0.761300 0.478400 0.437600 +vn -0.660100 0.720100 0.213700 +vn -0.744700 0.128600 0.654900 +vn -0.315100 -0.222700 -0.922500 +vn -0.528900 0.341700 -0.776900 +vn -0.353800 0.152000 -0.922800 +vn -0.952400 -0.282600 0.114400 +vn -0.670500 0.126800 0.730900 +vn -0.505200 -0.860900 0.060100 +vn -0.892900 -0.237900 0.382200 +vn -0.854100 -0.069500 0.515400 +vn -0.825900 0.140600 0.546000 +vn -0.721200 0.334200 0.606700 +vn -0.715000 0.469700 -0.517800 +vn -0.750800 -0.213800 0.625000 +vn -0.831500 -0.208200 0.515000 +vn -0.782400 0.256700 0.567400 +vn -0.446700 -0.777800 -0.442100 +vn -0.660100 0.034200 0.750300 +vn -0.642900 0.413600 0.644600 +vn -0.764100 0.066100 0.641700 +vn -0.511200 -0.015200 -0.859300 +vn 0.342300 -0.911400 -0.228400 +vn -0.244200 -0.045100 -0.968700 +vn -0.109300 -0.221700 -0.969000 +vn -0.705000 0.189400 0.683400 +vn -0.139600 -0.839200 0.525600 +vn -0.794400 -0.065700 0.603800 +vn -0.085800 0.119000 -0.989200 +vn 0.455900 0.783200 -0.422700 +vn -0.661000 0.595800 0.456000 +vn -0.819200 -0.157500 0.551400 +vn -0.889100 0.393600 0.233700 +vn -0.760600 -0.374900 0.530000 +vn -0.715500 0.233800 0.658300 +vn -0.444500 0.867600 -0.222800 +vn -0.698900 0.432000 0.570000 +vn -0.673500 0.528500 0.516800 +vn -0.677800 0.477200 0.559300 +vn -0.749500 -0.187200 0.634900 +vn -0.782800 0.078300 0.617300 +vn -0.771900 -0.364600 0.520800 +vn 0.132500 0.238400 -0.962100 +vn 0.130600 0.387800 -0.912400 +vn 0.135400 0.277100 -0.951200 +vn -0.396100 0.029900 -0.917700 +vn -0.608100 0.060700 -0.791500 +vn -0.573700 -0.143700 -0.806300 +vn -0.730600 -0.540300 0.417400 +vn 0.056300 -0.245600 -0.967700 +vn 0.221600 -0.604100 -0.765500 +vn 0.021600 0.242200 -0.970000 +vn -0.845500 0.145300 0.513700 +vn -0.034900 0.138800 -0.989700 +vn -0.555000 0.762800 0.331600 +vn -0.709500 -0.036300 -0.703800 +vn -0.537900 -0.152600 -0.829000 +vn -0.612000 -0.283200 -0.738400 +vn -0.412300 0.001600 -0.911000 +vn -0.184500 -0.962800 0.197200 +vn -0.032300 -0.989600 0.139900 +vn -0.382000 0.436000 -0.814800 +vn -0.437200 0.760000 0.480800 +vn -0.304300 -0.630000 0.714500 +vn -0.002000 0.424400 -0.905500 +vn -0.616200 -0.468500 0.633000 +vn -0.372300 0.735000 0.566600 +vn -0.506200 0.017600 -0.862200 +vn 0.354100 -0.513800 -0.781400 +vn -0.393500 -0.118200 -0.911700 +vn 0.357000 0.466300 -0.809400 +vn 0.355400 0.444400 -0.822300 +vn 0.296200 0.347100 -0.889800 +vn -0.061200 0.638100 -0.767500 +vn -0.060300 0.616700 -0.784900 +vn -0.059000 0.644300 -0.762400 +vn -0.420200 0.110600 -0.900600 +vn 0.014900 0.592700 -0.805300 +vn -0.028300 0.386900 -0.921700 +vn -0.124900 0.584900 -0.801400 +vn 0.136000 0.865600 -0.481900 +vn 0.184300 0.709800 -0.679800 +vn 0.120000 0.622500 -0.773400 +vn -0.003800 0.720200 -0.693700 +vn 0.164100 0.727300 -0.666300 +vn 0.300500 0.687900 -0.660700 +vn 0.377000 0.442300 -0.813700 +vn 0.541800 0.322900 -0.775900 +vn -0.907800 -0.093900 -0.408800 +vn -0.861400 -0.304100 -0.406700 +vn -0.430900 0.598300 -0.675600 +vn -0.711100 -0.186700 -0.677800 +vn -0.688400 -0.510000 -0.515800 +vn -0.664200 -0.325500 -0.672900 +vn -0.473100 -0.378800 -0.795300 +vn -0.961400 -0.007800 -0.274900 +vn -0.884900 -0.116900 -0.450800 +vn -0.498400 -0.648400 -0.575400 +vn -0.942600 -0.169300 -0.287800 +vn -0.949100 -0.103400 -0.297400 +vn -0.636500 -0.520100 -0.569400 +vn -0.632500 -0.600700 -0.488800 +vn -0.682100 -0.529200 -0.504600 +vn -0.983900 0.052900 -0.170300 +vn -0.964000 -0.008400 -0.265700 +vn -0.747600 -0.539100 -0.388000 +vn -0.823600 -0.404800 -0.397100 +vn -0.651400 0.728700 -0.211000 +vn -0.601200 -0.626300 -0.496200 +vn -0.902900 -0.344600 -0.256900 +vn -0.970100 -0.147700 -0.192700 +vn -0.964900 -0.149800 -0.215700 +vn -0.686400 -0.621800 -0.377000 +vn -0.890700 -0.353900 -0.285100 +vn 0.009400 0.783300 -0.621500 +vn 0.292500 0.587100 -0.754800 +vn 0.262200 0.486900 -0.833200 +vn -0.523500 0.732400 -0.435300 +vn -0.526700 0.692000 -0.493600 +vn -0.315700 -0.922300 -0.223000 +vn -0.984500 0.107900 -0.138000 +vn -0.985500 0.110500 -0.128500 +vn -0.040700 0.624500 -0.779900 +vn -0.001700 0.556500 -0.830800 +vn -0.033800 0.728100 -0.684600 +vn -0.089600 -0.995600 0.025800 +vn -0.154400 -0.981700 0.111500 +vn -0.117300 -0.983800 0.135600 +vn -0.587000 -0.802200 0.108300 +vn -0.135800 -0.990700 -0.011400 +vn -0.370200 -0.908400 -0.194300 +vn -0.108200 0.703700 -0.702100 +vn -0.073900 0.362900 -0.928900 +vn -0.706900 -0.339300 -0.620600 +vn -0.763500 -0.280800 -0.581500 +vn -0.839900 -0.142400 -0.523700 +vn -0.859300 0.082000 -0.504800 +vn -0.929300 -0.329900 -0.165500 +vn 0.640200 0.338900 -0.689400 +vn 0.558500 0.297700 -0.774200 +vn -0.796700 -0.350000 -0.492700 +vn -0.882100 -0.261900 -0.391500 +vn -0.398000 0.770100 -0.498400 +vn -0.667400 0.600500 -0.440400 +vn -0.858100 0.300200 -0.416500 +vn -0.730300 -0.606000 -0.315200 +vn -0.654300 -0.668600 -0.353200 +vn -0.664500 -0.644700 -0.377900 +vn -0.844400 -0.439400 -0.306500 +vn 0.124800 0.480500 -0.868000 +vn 0.022800 0.451100 -0.892200 +vn 0.133600 0.545700 -0.827200 +vn 0.076300 0.380900 -0.921400 +vn -0.860400 -0.313700 -0.401500 +vn -0.924200 -0.117800 -0.363400 +vn -0.877400 0.160800 -0.451900 +vn -0.994200 0.075600 0.075900 +vn -0.842100 -0.289200 -0.455200 +vn -0.884700 0.012900 -0.466000 +vn -0.904000 -0.355400 -0.237400 +vn -0.844500 -0.454700 -0.282700 +vn -0.852800 -0.248500 -0.459200 +vn -0.817000 -0.258300 -0.515400 +vn -0.917400 -0.266000 -0.295800 +vn -0.942900 -0.309700 -0.122200 +vn 0.127300 0.419400 -0.898800 +vn -0.869000 -0.135400 -0.476000 +vn -0.900400 -0.241300 -0.361900 +vn -0.907200 -0.277500 -0.316200 +vn -0.822700 0.182400 -0.538400 +vn -0.876800 -0.298300 -0.377100 +vn -0.616500 0.057300 -0.785200 +vn -0.660200 0.533900 -0.528200 +vn -0.459000 0.559400 -0.690100 +vn -0.934100 -0.163700 -0.317100 +vn -0.798800 -0.438500 0.411900 +vn -0.615800 0.166100 -0.770100 +vn -0.695800 0.388300 -0.604200 +vn -0.776600 -0.551600 -0.304400 +vn 0.035100 0.162500 -0.986100 +vn 0.114200 -0.496500 -0.860400 +vn -0.261500 -0.927100 0.268400 +vn -0.204000 -0.943700 -0.260300 +vn -0.081600 -0.996300 0.025300 +vn -0.798200 -0.593200 -0.104700 +vn -0.962500 -0.254600 -0.093700 +vn -0.936300 -0.340700 -0.084800 +vn -0.993900 0.034400 -0.105000 +vn 0.312900 0.789200 -0.528400 +vn 0.153500 0.797000 -0.584100 +vn -0.851800 0.376300 -0.364500 +vn -0.471100 0.832900 -0.290300 +vn -0.876500 -0.285100 -0.387900 +vn -0.304000 0.663300 -0.683800 +vn -0.736000 -0.664100 -0.131300 +vn -0.974500 0.213400 -0.069100 +vn -0.952900 0.287200 -0.097400 +vn -0.984800 -0.044800 -0.167500 +vn -0.970100 0.203100 -0.133000 +vn -0.584500 0.270000 -0.765100 +vn -0.608600 -0.099100 -0.787300 +vn -0.652900 0.150200 -0.742400 +vn -0.886200 0.349700 -0.303900 +vn 0.068700 -0.924600 -0.374800 +vn 0.118300 -0.746800 -0.654300 +vn -0.918200 -0.304600 -0.253000 +vn -0.848400 -0.474800 -0.234000 +vn -0.674900 0.571700 -0.466400 +vn -0.789800 0.562800 -0.243700 +vn -0.939000 0.226800 -0.258600 +vn -0.963000 -0.099200 -0.250600 +vn -0.263200 -0.584200 -0.767700 +vn -0.958600 -0.282400 -0.037000 +vn -0.997300 0.013700 0.072800 +vn 0.493200 0.368100 -0.788200 +vn 0.601500 0.266800 -0.753000 +vn -0.146200 0.325800 -0.934000 +vn -0.741700 -0.650600 -0.163000 +vn -0.778600 0.515500 -0.357700 +vn -0.945200 -0.094800 -0.312500 +vn 0.529300 0.615200 -0.584300 +vn 0.457300 0.520600 -0.720900 +vn 0.428500 0.526900 -0.734000 +vn 0.011800 -0.997700 0.065700 +vn -0.677100 -0.564900 -0.471600 +vn -0.612400 -0.525300 -0.590700 +vn -0.552300 -0.673600 -0.491100 +vn -0.598000 -0.785600 0.158400 +vn -0.974800 -0.169300 -0.145500 +vn -0.978700 0.147300 -0.142800 +vn -0.814000 0.387400 -0.432800 +vn -0.844500 0.347500 -0.407500 +vn 0.146800 0.274100 -0.950400 +vn 0.060000 0.674400 -0.735900 +vn -0.054700 0.706000 -0.706100 +vn -0.619300 0.418300 -0.664500 +vn -0.654300 0.472400 -0.590400 +vn 0.475300 0.475200 -0.740500 +vn 0.393400 0.486900 -0.779900 +vn -0.960100 -0.267600 -0.080500 +vn -0.609300 -0.355800 -0.708600 +vn -0.708700 -0.248200 -0.660400 +vn -0.561100 -0.138600 -0.816000 +vn -0.237100 -0.930200 0.280000 +vn -0.052900 -0.997800 0.038500 +vn -0.165600 0.864300 -0.474900 +vn -0.649300 0.666900 -0.365500 +vn -0.665900 0.633200 -0.394400 +vn 0.273400 0.861800 -0.427100 +vn -0.465700 -0.832900 -0.299000 +vn -0.481300 -0.831800 -0.276600 +vn -0.526200 -0.821700 -0.218700 +vn -0.916900 -0.282500 -0.281700 +vn -0.722200 -0.104900 -0.683600 +vn -0.740200 -0.020400 -0.672000 +vn -0.596900 0.026300 -0.801900 +vn -0.666500 0.146600 -0.730900 +vn -0.087000 0.552400 -0.829000 +vn -0.997300 -0.072300 -0.007700 +vn -0.778500 -0.208100 -0.592100 +vn -0.721100 0.220600 -0.656800 +vn -0.983400 -0.141200 -0.113700 +vn -0.108100 0.531100 -0.840300 +vn -0.771000 -0.170700 -0.613500 +vn -0.001100 0.927300 -0.374300 +vn 0.218200 0.847700 -0.483600 +vn -0.635800 0.479400 -0.604900 +vn 0.222400 -0.567700 -0.792600 +vn 0.213800 -0.104300 -0.971300 +vn 0.469600 0.186100 -0.863000 +vn 0.438200 0.418800 -0.795300 +vn 0.457700 0.405700 -0.791200 +vn 0.162900 -0.544300 -0.822900 +vn 0.214400 -0.114000 -0.970100 +vn -0.799200 0.070600 -0.596900 +vn 0.355100 0.663100 -0.658900 +vn -0.681400 -0.466200 -0.564200 +vn 0.632900 0.304000 -0.712100 +vn 0.379500 0.368200 -0.848800 +vn 0.475900 0.229600 -0.849000 +vn 0.106700 0.671200 -0.733500 +vn 0.021300 -0.995500 -0.091600 +vn -0.006700 -0.998500 -0.054400 +vn 0.159800 0.340400 -0.926600 +vn -0.986600 0.047700 -0.155900 +vn -0.075900 0.558900 -0.825700 +vn -0.140500 0.498500 -0.855400 +vn -0.749900 -0.351800 -0.560200 +vn -0.803900 -0.098500 -0.586500 +vn 0.002200 -0.998900 -0.045500 +vn -0.002200 -0.999200 -0.039100 +vn -0.072900 0.627500 -0.775200 +vn -0.084800 0.675800 -0.732100 +vn -0.118700 0.787300 -0.605000 +vn 0.202600 0.307600 -0.929700 +vn -0.882800 -0.209400 -0.420400 +vn -0.675300 -0.450000 -0.584300 +vn -0.636400 -0.687400 -0.349900 +vn -0.821100 -0.240700 -0.517500 +vn -0.047200 0.519900 -0.852900 +vn -0.794400 -0.088300 -0.600800 +vn -0.819400 0.421300 -0.388600 +vn -0.790200 -0.454100 -0.411400 +vn -0.828800 -0.361100 -0.427400 +vn -0.886300 -0.046000 -0.460700 +vn -0.834300 0.174400 -0.523000 +vn -0.761600 0.235900 -0.603500 +vn -0.594600 0.232200 -0.769700 +vn -0.613500 0.777500 -0.138300 +vn -0.089500 0.725800 -0.682100 +vn -0.465700 -0.711400 -0.526300 +vn -0.567900 -0.722700 -0.393900 +vn -0.802500 0.276600 -0.528600 +vn -0.690700 -0.120700 -0.712900 +vn -0.897100 0.149100 -0.415800 +vn -0.742100 0.427300 -0.516500 +vn -0.451200 0.838100 -0.306500 +vn -0.573400 0.310800 -0.758000 +vn -0.598600 -0.737600 -0.312300 +vn -0.536400 -0.602400 -0.591000 +vn -0.713400 -0.624600 -0.317600 +vn -0.888400 -0.288600 -0.357000 +vn -0.913300 0.097800 -0.395400 +vn -0.769200 0.150600 -0.621000 +vn -0.007800 -0.991500 0.129400 +vn -0.011600 -0.999900 0.003000 +vn -0.928600 -0.098300 -0.357800 +vn -0.936700 0.019600 -0.349500 +vn -0.193200 0.777100 -0.599000 +vn 0.204400 -0.977400 0.053200 +vn -0.697800 0.251200 -0.670800 +vn -0.698000 0.596400 -0.396300 +vn -0.557400 0.790800 -0.252700 +vn -0.722100 -0.249000 -0.645400 +vn -0.833300 0.011400 -0.552600 +vn -0.684900 -0.017300 -0.728400 +vn -0.748200 0.178800 -0.638900 +vn 0.479500 0.206300 -0.852900 +vn 0.497400 0.259700 -0.827700 +vn -0.788000 0.370900 -0.491400 +vn -0.626200 0.138100 -0.767300 +vn -0.812400 -0.503100 -0.294600 +vn 0.593700 0.494800 -0.634500 +vn -0.763500 0.609600 -0.213200 +vn -0.725300 0.660500 -0.193900 +vn -0.616900 0.767500 0.173900 +vn -0.752700 -0.619500 -0.222900 +vn 0.529900 0.114400 -0.840300 +vn 0.328000 0.428400 -0.842000 +vn 0.412300 0.184700 -0.892100 +vn 0.576500 0.574200 -0.581300 +vn -0.169500 0.826500 -0.536800 +vn -0.057600 0.777700 -0.625900 +vn -0.036100 0.733200 -0.679000 +vn 0.456600 0.649400 -0.608100 +vn 0.149600 0.353100 -0.923500 +vn 0.412300 0.741900 -0.528800 +vn 0.392500 0.596400 -0.700200 +vn 0.719000 0.219600 -0.659400 +vn 0.017100 -0.991900 0.125600 +vn -0.114300 -0.963000 0.243800 +vn 0.031700 -0.981600 0.188400 +vn -0.258900 -0.965000 -0.041100 +vn -0.222600 -0.962600 -0.154100 +vn 0.242800 0.422900 -0.873000 +vn 0.176100 0.557800 -0.811000 +vn 0.212700 0.529400 -0.821200 +vn -0.071300 0.822000 -0.565000 +vn 0.267200 0.699500 -0.662700 +vn 0.325900 0.724000 -0.607900 +vn 0.174700 0.505100 -0.845100 +vn -0.092700 -0.952900 -0.288700 +vn 0.001600 -0.999700 -0.025000 +vn 0.022600 0.519500 -0.854100 +vn 0.498400 0.464200 -0.732100 +vn 0.013500 0.441500 -0.897200 +vn 0.075100 -0.997000 0.019300 +vn -0.193500 0.878200 -0.437300 +vn -0.068000 0.838700 -0.540300 +vn 0.465200 0.652000 -0.598700 +vn -0.319900 0.597900 -0.734900 +vn 0.299500 -0.953000 -0.045600 +vn -0.148000 -0.974400 -0.169300 +vn -0.197500 -0.980200 0.009200 +vn -0.164200 -0.982500 0.087500 +vn 0.270900 -0.955400 -0.117200 +vn 0.279000 0.287600 -0.916200 +vn -0.431700 0.226500 -0.873100 +vn 0.121500 0.174600 -0.977100 +vn -0.104700 0.894400 -0.434900 +vn -0.001700 0.837600 -0.546300 +vn -0.235100 0.858000 -0.456600 +vn 0.274800 -0.558700 -0.782500 +vn 0.365200 0.260100 -0.893800 +vn -0.218500 0.817500 -0.532800 +vn 0.536800 0.261800 -0.802000 +vn 0.437300 0.205100 -0.875600 +vn -0.063700 0.383200 -0.921400 +vn -0.005400 0.426700 -0.904400 +vn -0.040100 0.405900 -0.913000 +vn -0.519200 -0.840700 -0.153600 +vn -0.124000 0.393700 -0.910800 +vn 0.580200 0.300200 -0.757100 +vn 0.103300 0.707100 -0.699500 +vn 0.126100 0.387200 -0.913300 +vn -0.070900 0.635400 -0.768900 +vn -0.178900 0.643400 -0.744300 +vn -0.241500 0.505000 -0.828600 +vn -0.307100 0.511000 -0.802800 +vn 0.165800 -0.174600 -0.970500 +vn 0.295700 0.289300 -0.910400 +vn 0.456000 0.357500 -0.815000 +vn 0.161600 0.620200 -0.767600 +vn 0.305900 0.222600 -0.925600 +vn 0.507700 0.625800 -0.592000 +vn -0.135700 0.539200 -0.831100 +vn -0.057800 0.751900 -0.656700 +vn -0.068500 0.448900 -0.890900 +vn -0.089500 0.626300 -0.774400 +vn 0.002400 0.663000 -0.748600 +vn 0.128900 0.866000 -0.483100 +vn 0.028300 0.515900 -0.856200 +vn 0.077800 0.786700 -0.612400 +vn 0.011700 0.475900 -0.879400 +vn 0.160500 0.879300 -0.448300 +vn -0.455000 -0.707800 0.540200 +vn 0.091900 0.261600 -0.960800 +vn 0.126200 0.581300 -0.803800 +vn 0.236000 -0.642500 0.729000 +vn 0.193900 0.668300 -0.718200 +vn 0.269800 0.815400 -0.512100 +vn 0.256900 0.192600 -0.947100 +vn -0.575700 -0.815400 -0.060200 +vn 0.194900 0.243800 -0.950000 +vn 0.062700 0.579300 -0.812700 +vn -0.004900 0.469300 -0.883000 +vn 0.510600 0.092900 -0.854700 +vn -0.432100 -0.874500 -0.220100 +vn -0.096500 -0.929700 -0.355400 +vn 0.486900 0.119200 -0.865300 +vn -0.544800 -0.099900 -0.832600 +vn -0.472200 0.352400 -0.808000 +vn -0.258000 -0.097200 -0.961200 +vn -0.407100 -0.221700 -0.886000 +vn -0.274100 0.008200 -0.961700 +vn -0.374600 0.129200 -0.918100 +vn 0.413900 -0.154300 -0.897200 +vn -0.135700 0.319300 -0.937800 +vn -0.191500 0.380400 -0.904800 +vn 0.161300 -0.004500 -0.986900 +vn 0.035200 0.277200 -0.960100 +vn 0.273300 -0.330900 -0.903200 +vn -0.125200 -0.435400 -0.891500 +vn 0.506000 -0.062000 -0.860300 +vn -0.421000 -0.237600 -0.875400 +vn -0.409100 -0.241600 -0.879900 +vn -0.339400 0.174100 -0.924400 +vn -0.476500 -0.647100 -0.595100 +vn -0.320200 -0.605900 -0.728200 +vn -0.346600 -0.701800 -0.622400 +vn -0.508400 -0.116600 -0.853100 +vn -0.491000 -0.481900 -0.725700 +vn 0.152200 -0.333600 -0.930300 +vn -0.270200 0.262400 -0.926300 +vn -0.211500 0.153700 -0.965200 +vn -0.342500 0.120200 -0.931800 +vn 0.127900 -0.059900 -0.990000 +vn -0.129700 -0.507300 -0.851900 +vn -0.079600 -0.988700 -0.126700 +vn -0.196100 0.120200 -0.973200 +vn -0.293400 0.007600 -0.955900 +vn -0.241400 0.251500 -0.937300 +vn -0.157400 0.023200 -0.987200 +vn -0.351700 0.031100 -0.935600 +vn -0.041200 -0.356100 -0.933500 +vn -0.421800 -0.510700 -0.749100 +vn 0.162600 -0.271500 -0.948600 +vn -0.307400 -0.092100 -0.947100 +vn 0.039200 -0.416700 -0.908200 +vn 0.278000 -0.866300 -0.415100 +vn -0.052000 0.331500 -0.942000 +vn 0.047700 -0.287300 -0.956600 +vn -0.333100 -0.380800 -0.862600 +vn 0.032100 -0.309000 -0.950500 +vn -0.325400 -0.756400 -0.567300 +vn -0.395200 -0.244100 -0.885500 +vn -0.246600 -0.312100 -0.917500 +vn -0.361200 -0.367100 -0.857200 +vn -0.161000 -0.316900 -0.934700 +vn 0.072800 -0.996300 0.045500 +vn -0.226900 -0.237400 -0.944500 +vn -0.000300 -0.175700 -0.984400 +vn -0.137700 -0.333500 -0.932600 +vn 0.258900 -0.327600 -0.908600 +vn 0.254200 0.229500 -0.939500 +vn -0.314200 -0.409600 -0.856400 +vn 0.578900 -0.093600 -0.810000 +vn 0.482400 0.020500 -0.875700 +vn -0.098900 0.231700 -0.967700 +vn 0.498700 -0.414700 -0.761100 +vn -0.169900 -0.376900 -0.910500 +vn 0.440000 0.062000 -0.895800 +vn 0.477300 -0.246100 -0.843500 +vn 0.448600 -0.100400 -0.888100 +vn 0.454500 -0.089400 -0.886200 +vn 0.389800 -0.030600 -0.920400 +vn 0.399600 0.041700 -0.915700 +vn 0.332400 -0.404800 -0.851800 +vn 0.306600 -0.118000 -0.944500 +vn 0.340500 -0.235900 -0.910200 +vn -0.203500 0.277400 -0.938900 +vn 0.323300 -0.137900 -0.936200 +vn 0.421800 0.035500 -0.906000 +vn -0.647200 -0.745000 0.161300 +vn -0.233900 -0.741300 -0.629100 +vn 0.294700 -0.367600 -0.882000 +vn 0.424100 0.076800 -0.902300 +vn -0.543200 -0.839100 0.029600 +vn -0.377200 -0.926100 0.004200 +vn 0.215600 -0.440000 -0.871700 +vn 0.237100 -0.256300 -0.937000 +vn 0.410800 -0.016000 -0.911600 +vn 0.273800 -0.137000 -0.951900 +vn 0.328900 -0.083900 -0.940600 +vn 0.431100 0.049300 -0.900900 +vn 0.028900 -0.999300 -0.022200 +vn 0.022200 -0.999300 -0.028200 +vn 0.126400 -0.328300 -0.936100 +vn 0.143200 -0.441700 -0.885600 +vn 0.208100 -0.423300 -0.881700 +vn 0.224400 -0.138600 -0.964600 +vn 0.264600 -0.178000 -0.947800 +vn 0.284800 -0.176500 -0.942200 +vn 0.102000 -0.253000 -0.962100 +vn 0.268100 -0.160300 -0.949900 +vn -0.620300 0.115500 -0.775700 +vn 0.123200 -0.134300 -0.983200 +vn 0.199700 -0.326100 -0.924000 +vn 0.251300 -0.151400 -0.956000 +vn 0.296700 -0.160900 -0.941300 +vn 0.376400 -0.046300 -0.925300 +vn 0.365700 0.112200 -0.923900 +vn 0.335700 0.189300 -0.922700 +vn 0.210500 -0.357000 -0.910100 +vn 0.217100 -0.209000 -0.953500 +vn 0.374500 0.077000 -0.924000 +vn 0.150900 -0.217700 -0.964300 +vn 0.250300 -0.126100 -0.959900 +vn 0.296900 0.010400 -0.954800 +vn 0.205700 -0.578800 -0.789000 +vn 0.247900 -0.519200 -0.817900 +vn 0.262300 -0.214200 -0.940900 +vn 0.327800 0.111800 -0.938100 +vn 0.228400 -0.189700 -0.954900 +vn 0.202200 -0.319100 -0.925900 +vn 0.213900 -0.259400 -0.941800 +vn 0.239500 -0.257400 -0.936100 +vn 0.128000 -0.468000 -0.874400 +vn 0.272500 -0.035100 -0.961500 +vn 0.128700 -0.661200 -0.739100 +vn 0.223500 -0.243600 -0.943700 +vn 0.230600 -0.131100 -0.964200 +vn 0.122200 -0.140100 -0.982500 +vn 0.114000 -0.516100 -0.848900 +vn 0.224100 -0.152000 -0.962600 +vn 0.308900 0.079500 -0.947700 +vn -0.551600 -0.040700 -0.833100 +vn 0.121700 -0.378900 -0.917400 +vn 0.228500 -0.121500 -0.965900 +vn 0.233900 -0.118200 -0.965000 +vn 0.138600 -0.159300 -0.977400 +vn 0.129800 -0.023800 -0.991200 +vn 0.119800 -0.154700 -0.980700 +vn 0.144600 -0.333000 -0.931800 +vn 0.225000 0.034900 -0.973700 +vn 0.172500 -0.278900 -0.944700 +vn 0.222500 -0.102800 -0.969500 +vn 0.232200 -0.160700 -0.959300 +vn 0.089000 -0.475200 -0.875300 +vn 0.000000 -0.518100 -0.855300 +vn 0.182000 -0.236400 -0.954400 +vn 0.202900 -0.134800 -0.969800 +vn -0.057700 -0.843000 0.534800 +vn 0.044600 -0.638000 -0.768700 +vn 0.063600 -0.437600 -0.896900 +vn 0.198600 -0.187700 -0.961900 +vn 0.156600 -0.285900 -0.945400 +vn -0.679400 -0.110200 -0.725400 +vn 0.069800 -0.356900 -0.931500 +vn 0.158000 -0.259500 -0.952700 +vn 0.166700 -0.081900 -0.982600 +vn 0.231500 -0.158600 -0.959800 +vn 0.209000 -0.103700 -0.972400 +vn 0.120200 -0.051000 -0.991400 +vn 0.133700 0.032800 -0.990400 +vn -0.094100 -0.434800 -0.895600 +vn 0.080200 -0.310000 -0.947300 +vn 0.153900 -0.161000 -0.974900 +vn 0.510200 -0.860000 0.004700 +vn 0.300200 -0.953900 -0.002600 +vn -0.107600 -0.675400 0.729600 +vn -0.565900 -0.104200 -0.817800 +vn 0.191400 -0.058800 -0.979700 +vn 0.147100 -0.177100 -0.973100 +vn -0.014900 -0.446900 -0.894400 +vn 0.094700 -0.091400 -0.991300 +vn 0.096400 -0.242700 -0.965300 +vn 0.488400 -0.858000 0.159000 +vn 0.408800 -0.911900 -0.035100 +vn 0.598900 -0.787900 0.143100 +vn 0.097100 -0.085200 -0.991600 +vn 0.063100 0.030100 -0.997500 +vn -0.460200 -0.718300 -0.521800 +vn 0.654100 -0.734400 0.181100 +vn -0.188000 -0.469700 -0.862500 +vn -0.113400 -0.393600 -0.912200 +vn -0.147900 -0.345900 -0.926500 +vn 0.339000 -0.820900 0.459500 +vn -0.107500 -0.195200 -0.974900 +vn 0.185200 -0.976800 0.107300 +vn -0.092700 -0.993300 -0.068800 +vn -0.008500 -0.997100 0.075700 +vn -0.297000 -0.444100 -0.845300 +vn -0.315600 -0.400600 -0.860200 +vn -0.162500 -0.284400 -0.944800 +vn -0.047900 0.077600 -0.995800 +vn -0.507300 -0.162100 -0.846300 +vn -0.687000 -0.702400 -0.186200 +vn -0.865400 -0.060300 -0.497400 +vn -0.055900 -0.039200 -0.997700 +vn -0.215100 -0.157700 -0.963800 +vn -0.440400 -0.330800 -0.834700 +vn -0.491700 -0.814200 0.308500 +vn -0.376400 -0.238100 -0.895300 +vn -0.288900 -0.087800 -0.953300 +vn -0.264100 0.085800 -0.960600 +vn -0.498800 -0.370400 -0.783600 +vn -0.272000 -0.565300 0.778700 +vn -0.238500 -0.855700 0.459200 +vn 0.055100 -0.994000 -0.094700 +vn 0.039600 -0.995600 -0.085200 +vn 0.019200 -0.999800 0.009800 +vn -0.055600 -0.998400 0.008300 +vn 0.028700 -0.998500 0.046000 +vn -0.228400 -0.927100 -0.297200 +vn -0.264700 -0.964000 0.024900 +vn -0.063500 -0.941100 -0.332100 +vn -0.027900 -0.940600 -0.338200 +vn -0.115500 -0.845800 -0.520800 +vn 0.098000 -0.974600 0.201400 +vn 0.196400 -0.220200 0.955400 +vn 0.157300 -0.987300 -0.022400 +vn -0.232300 -0.972500 -0.013400 +vn 0.075200 -0.978900 0.189800 +vn -0.015800 -0.994800 0.100500 +vn -0.138500 -0.988000 -0.068200 +vn -0.122700 -0.975600 -0.181600 +vn -0.016400 -0.994400 -0.104000 +vn 0.463800 -0.876400 0.129900 +vn -0.641100 -0.731200 0.233200 +vn -0.457400 -0.812200 0.362000 +vn -0.361000 -0.894000 0.265200 +vn -0.188600 -0.969000 0.159300 +vn -0.448200 -0.879600 0.159300 +vn 0.395900 -0.876200 0.274700 +vn 0.071100 -0.981700 -0.176200 +vn -0.024800 -0.999600 0.011300 +vn 0.025400 -0.999500 -0.016400 +vn 0.017900 -0.999400 -0.029100 +vn -0.127000 -0.666100 0.734900 +vn -0.035600 -0.999400 0.002800 +vn -0.613500 -0.789700 -0.009100 +vn 0.077100 -0.950300 0.301600 +vn 0.091400 -0.914700 0.393600 +vn 0.121000 -0.991900 0.039300 +vn -0.064900 -0.997600 -0.022400 +vn -0.402700 -0.889400 0.216400 +vn 0.037500 -0.990500 -0.132200 +vn -0.495600 -0.851100 0.173200 +vn 0.161000 -0.986700 -0.021900 +vn 0.173600 -0.983200 0.056400 +vn -0.006000 -0.998800 -0.047900 +vn 0.044100 -0.998400 -0.034900 +vn 0.031700 -0.999500 -0.008000 +vn -0.571600 -0.747800 -0.337700 +vn -0.154900 -0.975900 0.153600 +vn -0.037800 -0.999300 0.003800 +vn -0.526800 -0.838300 0.139900 +vn -0.461700 -0.884500 -0.067700 +vn -0.459900 -0.884100 0.083300 +vn 0.175100 -0.507200 0.843800 +vn 0.305600 -0.901100 0.307600 +vn 0.066300 -0.951500 0.300300 +vn -0.040200 -0.990400 0.132500 +vn -0.120400 -0.987900 0.097100 +vn 0.207200 -0.976400 0.060300 +vn 0.245300 -0.968100 -0.049900 +vn -0.615700 -0.787800 0.018500 +vn 0.284400 -0.947100 -0.148600 +vn 0.140300 -0.985200 0.098500 +vn -0.458500 -0.811000 0.363200 +vn 0.162100 -0.973800 0.159400 +vn 0.308300 -0.928200 0.208300 +vn -0.656700 -0.740000 -0.145000 +vn -0.394300 -0.918600 0.026200 +vn -0.201400 -0.969200 -0.141800 +vn 0.013800 -0.998100 -0.059200 +vn -0.690400 -0.722800 0.029800 +vn -0.568100 -0.799700 -0.194000 +vn -0.400800 -0.910500 -0.101600 +vn 0.094700 -0.995500 0.005200 +vn 0.079600 -0.996500 -0.025800 +vn -0.468400 -0.883500 -0.004800 +vn -0.060400 -0.990200 0.126000 +vn -0.312100 -0.943700 -0.109800 +vn -0.101900 -0.992500 -0.068000 +vn 0.193700 -0.978100 -0.076200 +vn 0.099500 -0.990600 -0.093400 +vn -0.485600 -0.800200 0.351800 +vn -0.096300 -0.860400 0.500400 +vn -0.433000 -0.810700 0.394100 +vn -0.710800 -0.556500 0.430100 +vn -0.113000 -0.686500 0.718200 +vn -0.304000 -0.940300 0.152900 +vn 0.022600 -0.996700 0.077600 +vn -0.013700 -0.992900 -0.117800 +vn 0.047200 -0.998200 -0.037500 +vn 0.023300 -0.997300 0.068600 +vn -0.006300 -0.998000 0.062900 +vn 0.290500 -0.942400 0.165500 +vn -0.055700 -0.842300 0.536100 +vn -0.075500 -0.843800 0.531300 +vn -0.040800 -0.950600 0.307600 +vn -0.191600 -0.929600 0.314700 +vn 0.021900 -0.999700 0.009600 +vn 0.022200 -0.999700 0.007200 +vn -0.312700 -0.945900 0.086200 +vn -0.245400 -0.833300 0.495200 +vn -0.344400 -0.626500 0.699100 +vn -0.430000 -0.895700 0.113500 +vn -0.107000 -0.696000 0.710000 +vn 0.009800 -0.996600 0.082000 +vn -0.450800 -0.763200 0.462900 +vn 0.018000 -0.999200 -0.034800 +vn -0.012000 -0.989400 0.144400 +vn -0.154400 -0.936500 0.314900 +vn 0.290300 -0.910200 0.295300 +vn 0.398100 -0.840400 0.367600 +vn 0.109200 -0.992600 -0.053700 +vn 0.188000 -0.940500 -0.282800 +vn 0.162100 -0.986500 -0.023000 +vn -0.687900 -0.706400 0.166600 +vn 0.109100 -0.993700 0.022400 +vn -0.498900 -0.828900 -0.253200 +vn 0.316800 -0.946000 0.068900 +vn 0.028500 -0.995800 0.086100 +vn -0.706700 -0.624400 0.332500 +vn 0.029700 -0.999100 0.030600 +vn -0.597400 -0.795800 -0.098800 +vn -0.664000 -0.747700 -0.000600 +vn -0.623500 -0.778600 0.071300 +vn -0.062300 -0.879500 0.471800 +vn -0.332500 -0.850500 0.407600 +vn -0.641400 -0.734200 0.222400 +vn -0.583900 -0.744400 0.323700 +vn -0.611600 -0.705200 0.358700 +vn 0.199500 -0.917000 0.345400 +vn -0.353900 -0.912000 -0.207100 +vn -0.434600 -0.896700 -0.084000 +vn -0.542700 -0.795100 0.270500 +vn -0.607200 -0.622900 0.493200 +vn -0.471200 -0.856400 -0.211200 +vn -0.233700 -0.971300 -0.042700 +vn -0.477600 -0.872700 0.101200 +vn 0.127200 -0.991700 0.017500 +vn -0.367000 -0.926900 -0.077600 +vn -0.315600 -0.948300 0.032800 +vn -0.362900 -0.905000 0.222100 +vn -0.469600 -0.747100 0.470400 +vn -0.012900 -0.999000 0.041800 +vn -0.382900 -0.857300 0.344000 +vn -0.473700 -0.667300 0.574700 +vn -0.487700 -0.555300 0.673600 +vn -0.138500 -0.985700 0.095600 +vn -0.431000 -0.805500 0.406600 +vn 0.020800 -0.992300 -0.121600 +vn 0.189900 -0.979300 -0.069400 +vn -0.048200 -0.988000 -0.146500 +vn 0.008900 -0.999800 0.017600 +vn -0.242300 -0.950200 0.195900 +vn -0.341500 -0.688000 0.640200 +vn -0.281300 -0.952500 0.117000 +vn -0.135200 -0.982000 0.131600 +vn -0.032100 -0.997500 0.062500 +vn -0.262900 -0.963700 0.046800 +vn -0.264100 -0.911600 0.314800 +vn -0.064100 -0.977800 -0.199700 +vn -0.286500 -0.867200 0.407300 +vn -0.317300 -0.798400 0.511600 +vn 0.026600 -0.999200 0.029700 +vn 0.014100 -0.999700 0.017200 +vn -0.010900 -0.999300 0.036300 +vn 0.010200 -0.999200 0.038000 +vn -0.237100 -0.760600 0.604300 +vn -0.211300 -0.646400 0.733100 +vn 0.025400 -0.997100 -0.071900 +vn -0.173200 -0.967800 -0.182500 +vn 0.043500 -0.998300 -0.038100 +vn -0.338700 -0.928600 -0.151600 +vn -0.297400 -0.949400 -0.101000 +vn -0.040700 -0.998800 -0.027400 +vn 0.067600 -0.995500 0.065300 +vn 0.060400 -0.997300 0.041200 +vn 0.194300 -0.980300 -0.033900 +vn 0.062500 -0.997300 0.037700 +vn 0.065100 -0.996100 0.060100 +vn -0.170100 -0.985400 0.006900 +vn 0.066600 -0.997700 -0.015200 +vn 0.119400 -0.992600 -0.021100 +vn 0.049700 -0.996400 0.067900 +vn 0.076400 -0.994800 -0.067800 +vn -0.041000 -0.998500 0.036000 +vn -0.011100 -0.999600 0.024700 +vn -0.061300 -0.997600 0.030700 +vn -0.088400 -0.996000 -0.009200 +vn 0.102700 -0.994700 0.007600 +vn -0.164000 -0.663900 0.729600 +vn 0.169400 -0.974600 0.146400 +vn 0.079700 -0.988500 0.128600 +vn 0.029300 -0.970700 0.238400 +vn -0.016400 -0.993000 0.117200 +vn 0.151000 -0.964500 0.216600 +vn 0.147400 -0.985200 -0.087100 +vn 0.015800 -0.999700 0.018500 +vn 0.006700 -0.999000 0.044500 +vn 0.008700 -0.999700 0.020600 +vn -0.179100 -0.955100 0.236100 +vn -0.088000 -0.995100 0.043300 +vn 0.353800 -0.887100 0.296300 +vn 0.338700 -0.932100 0.128100 +vn 0.240800 -0.969900 0.036500 +vn 0.446900 -0.894200 0.026000 +vn 0.489100 -0.792800 0.363500 +vn 0.590400 -0.802600 0.084300 +vn 0.379300 -0.917100 -0.122000 +vn -0.226600 -0.596200 0.770200 +vn 0.158900 -0.937700 0.308900 +vn 0.167600 -0.785400 0.595900 +vn 0.286600 -0.842700 0.455700 +vn 0.407600 -0.881600 0.237700 +vn 0.454700 -0.890500 0.017200 +vn 0.206600 -0.973400 -0.098700 +vn 0.167600 -0.982900 -0.076200 +vn 0.019600 -0.974700 0.222600 +vn 0.017200 -0.996600 0.080300 +vn 0.291400 -0.950600 -0.107300 +vn 0.027200 -0.857300 0.514000 +vn -0.139300 -0.952000 0.272400 +vn 0.002000 -0.999500 0.032700 +vn 0.020300 -0.999600 0.016400 +vn -0.012600 -0.733100 0.680000 +vn 0.099500 -0.989900 0.101100 +vn 0.169700 -0.978100 -0.120400 +vn -0.010300 -0.998200 -0.058400 +vn 0.037800 -0.919600 0.391100 +vn 0.011500 -0.996600 -0.081900 +vn -0.096900 -0.975000 0.199600 +vn 0.209400 -0.958700 -0.192400 +vn -0.090300 -0.638600 0.764200 +vn -0.078600 -0.839800 0.537000 +vn -0.100100 -0.671800 0.733900 +vn -0.378600 -0.905200 0.192800 +vn 0.352100 -0.904000 -0.242500 +vn 0.186900 -0.981700 0.036400 +vn 0.384300 -0.895100 -0.225900 +vn 0.524900 -0.847300 0.081300 +vn -0.011300 -0.998500 -0.052900 +vn 0.257100 -0.941900 -0.216100 +vn 0.308300 -0.925600 -0.219300 +vn 0.295600 -0.918100 -0.264100 +vn -0.124500 -0.866400 -0.483500 +vn -0.131200 -0.828800 -0.543900 +vn -0.178600 -0.839200 -0.513600 +vn -0.060300 -0.913800 -0.401700 +vn 0.070400 -0.863200 -0.500000 +vn 0.050400 -0.917000 -0.395700 +vn -0.084400 -0.940100 -0.330100 +vn 0.029200 -0.999500 -0.005100 +vn 0.134300 -0.990600 0.025500 +vn 0.276100 -0.960600 -0.031000 +vn 0.058100 -0.988900 -0.136400 +vn 0.006600 -0.982500 -0.185900 +vn -0.025800 -0.983400 -0.179400 +vn -0.005600 -0.995800 -0.091100 +vn -0.183900 -0.874100 -0.449500 +vn -0.048800 -0.977900 -0.203100 +vn -0.004700 -0.999300 -0.037500 +s 1 +f 877//1 1//2 916//3 +f 788//4 907//5 23//6 +f 79//7 2//8 114//9 +f 987//10 1117//11 358//12 +f 114//9 124//13 327//14 +f 3//15 134//16 1050//17 +f 85//18 1062//19 53//20 +f 1080//21 1018//22 1021//23 +f 8//24 4//25 649//26 +f 1664//27 2216//28 625//29 +f 1186//30 249//31 250//32 +f 5//33 991//34 6//35 +f 7//36 391//37 1180//38 +f 1062//19 30//39 53//20 +f 29//40 8//24 1630//41 +f 345//42 9//43 2504//44 +f 1044//45 10//46 26//47 +f 989//48 24//49 2748//50 +f 11//51 12//52 2397//53 +f 346//54 1133//55 345//42 +f 1126//56 2505//57 346//54 +f 13//58 1166//59 985//60 +f 1046//61 2504//44 14//62 +f 15//63 506//64 882//65 +f 1133//55 9//43 345//42 +f 16//66 318//67 624//68 +f 1074//69 110//70 1531//71 +f 1685//72 17//73 2506//74 +f 2331//75 1612//76 2338//77 +f 1433//78 1497//79 19//80 +f 957//81 865//82 4//25 +f 20//83 198//84 18//85 +f 17//73 20//83 2506//74 +f 21//86 2177//87 2176//88 +f 2//8 124//13 114//9 +f 1096//89 1030//90 1089//91 +f 2187//92 1909//93 2188//94 +f 22//95 471//96 23//6 +f 1685//72 18//85 1384//97 +f 1329//98 1381//99 1036//100 +f 277//101 112//102 378//103 +f 1126//56 2507//104 2505//57 +f 1030//90 1035//105 1115//106 +f 1091//107 1074//69 1015//108 +f 198//84 187//109 18//85 +f 187//109 198//84 85//18 +f 987//10 2508//110 1117//11 +f 93//111 79//7 318//67 +f 1116//112 1036//100 1085//113 +f 94//114 18//85 27//115 +f 697//116 8//24 28//117 +f 1045//118 985//60 10//46 +f 828//119 25//120 2509//121 +f 10//46 985//60 26//47 +f 35//122 803//123 222//124 +f 94//114 27//115 80//125 +f 1435//126 1779//127 1775//128 +f 1103//129 1166//59 1023//130 +f 28//117 8//24 29//40 +f 30//39 16//66 429//131 +f 1023//130 31//132 1627//133 +f 74//134 54//135 373//136 +f 839//137 40//138 806//139 +f 9//43 32//140 2749//141 +f 1012//142 2235//143 837//144 +f 373//136 42//145 460//146 +f 33//147 1055//148 680//149 +f 1045//118 13//58 985//60 +f 1498//150 1048//151 813//152 +f 34//153 38//154 1301//155 +f 38//154 47//156 1301//155 +f 47//156 1373//157 1301//155 +f 2166//158 1168//159 357//160 +f 1381//99 1025//161 1024//162 +f 1055//148 201//163 1027//164 +f 1021//23 1031//165 1080//21 +f 837//144 2235//143 2236//166 +f 1166//59 1103//129 985//60 +f 34//153 1650//167 38//154 +f 39//168 542//169 1374//170 +f 1018//22 1032//171 567//172 +f 14//62 32//140 2510//173 +f 1278//174 2364//175 351//176 +f 1532//177 803//123 35//122 +f 36//178 2160//179 1951//180 +f 1204//181 37//182 2067//183 +f 1028//184 387//185 1029//186 +f 49//187 38//154 1650//167 +f 49//187 47//156 38//154 +f 55//188 39//168 1373//157 +f 727//189 2278//190 881//191 +f 1658//192 649//26 651//193 +f 17//73 2512//194 2511//195 +f 1126//56 2509//121 2507//104 +f 249//31 40//138 41//196 +f 1091//107 1015//108 77//197 +f 985//60 1773//198 26//47 +f 353//199 187//109 381//200 +f 47//156 55//188 1373//157 +f 1537//201 542//169 39//168 +f 55//188 1537//201 39//168 +f 890//202 1503//203 1114//204 +f 429//131 16//66 624//68 +f 357//160 987//10 358//12 +f 1080//21 1032//171 1018//22 +f 366//205 27//115 353//199 +f 373//136 54//135 42//145 +f 1649//206 43//207 1650//167 +f 49//187 569//208 47//156 +f 47//156 50//209 55//188 +f 2111//210 1563//211 2112//212 +f 1303//213 1994//214 952//215 +f 1630//41 649//26 1658//192 +f 1074//69 1531//71 1015//108 +f 1532//177 35//122 862//216 +f 858//217 877//1 1648//218 +f 44//219 45//220 1656//221 +f 1450//222 46//223 506//64 +f 1649//206 62//224 43//207 +f 47//156 569//208 50//209 +f 543//225 542//169 48//226 +f 2144//227 1634//228 35//122 +f 869//229 250//32 41//196 +f 1892//230 136//231 1733//232 +f 43//207 59//233 49//187 +f 59//233 569//208 49//187 +f 50//209 51//234 55//188 +f 1537//201 48//226 542//169 +f 1385//235 2345//236 62//224 +f 52//237 1674//238 2096//239 +f 53//20 30//39 54//135 +f 932//240 41//196 839//137 +f 1220//241 2192//242 937//243 +f 55//188 51//234 1537//201 +f 725//244 894//245 970//246 +f 60//247 56//248 57//249 +f 58//250 1220//241 937//243 +f 30//39 429//131 54//135 +f 662//251 2295//252 1241//253 +f 62//224 59//233 43//207 +f 179//254 685//255 361//256 +f 1870//257 60//247 57//249 +f 970//246 737//258 736//259 +f 60//247 1854//260 56//248 +f 1780//261 694//262 61//263 +f 20//83 1037//264 1062//19 +f 85//18 53//20 435//265 +f 66//266 76//267 1253//268 +f 623//269 62//224 2345//236 +f 623//269 59//233 62//224 +f 331//270 323//271 91//272 +f 51//234 63//273 1537//201 +f 2326//274 145//275 64//276 +f 1854//260 1712//277 691//278 +f 483//279 849//280 2513//281 +f 1124//282 1505//283 2146//284 +f 1134//285 65//286 1633//287 +f 788//4 1012//142 907//5 +f 2317//288 1657//289 2320//290 +f 97//291 76//267 66//266 +f 76//267 75//292 1804//293 +f 75//292 67//294 1804//293 +f 463//295 68//296 298//297 +f 69//298 592//299 285//300 +f 771//301 131//302 70//303 +f 497//304 59//233 71//305 +f 665//306 72//307 664//308 +f 73//309 1400//310 1528//311 +f 877//1 878//312 918//313 +f 1795//314 1384//97 94//114 +f 74//134 373//136 334//315 +f 81//316 75//292 76//267 +f 826//317 1167//318 921//319 +f 283//320 445//321 449//322 +f 684//323 281//324 339//325 +f 1118//326 773//327 772//328 +f 1071//329 1091//107 77//197 +f 2268//330 333//331 552//332 +f 305//333 78//334 736//259 +f 1048//151 1071//329 77//197 +f 78//334 305//333 980//335 +f 697//116 4//25 8//24 +f 318//67 79//7 114//9 +f 1183//336 2512//194 2514//337 +f 651//193 1545//338 1658//192 +f 80//125 366//205 314//339 +f 97//291 81//316 76//267 +f 2515//340 82//341 2516//342 +f 274//343 91//272 323//271 +f 123//344 275//345 283//320 +f 275//345 445//321 283//320 +f 123//344 283//320 646//346 +f 982//347 83//348 678//349 +f 1854//260 691//278 732//350 +f 84//351 104//352 106//353 +f 56//248 732//350 57//249 +f 187//109 85//18 381//200 +f 88//354 86//355 87//356 +f 66//266 88//354 97//291 +f 89//357 621//358 221//359 +f 447//360 69//298 98//361 +f 90//362 338//363 91//272 +f 63//273 502//364 2517//365 +f 92//366 484//367 483//279 +f 903//368 92//366 483//279 +f 1182//369 93//111 1037//264 +f 1182//369 2518//370 2511//195 +f 79//7 100//371 2//8 +f 18//85 94//114 1384//97 +f 335//372 95//373 1181//374 +f 856//375 103//376 1248//377 +f 1247//378 103//376 86//355 +f 86//355 103//376 87//356 +f 96//379 88//354 87//356 +f 96//379 97//291 88//354 +f 96//379 81//316 97//291 +f 98//361 285//300 112//102 +f 69//298 285//300 98//361 +f 917//380 483//279 1747//381 +f 443//382 130//383 444//384 +f 171//385 282//386 313//387 +f 274//343 90//362 91//272 +f 315//388 670//389 99//390 +f 647//391 499//392 495//393 +f 100//371 2519//394 2//8 +f 443//382 468//395 150//396 +f 771//301 70//303 338//363 +f 548//397 593//398 638//399 +f 1114//204 1113//400 1187//401 +f 1061//402 1083//403 101//404 +f 41//196 40//138 839//137 +f 1353//405 102//406 1881//407 +f 856//375 111//408 103//376 +f 103//376 117//409 87//356 +f 142//410 81//316 96//379 +f 2409//411 745//412 185//413 +f 317//414 2104//415 1477//416 +f 267//417 443//382 150//396 +f 104//352 105//418 106//353 +f 168//419 578//420 631//421 +f 107//422 96//379 87//356 +f 117//409 107//422 87//356 +f 108//423 81//316 142//410 +f 108//423 523//424 81//316 +f 2410//425 404//426 184//427 +f 274//343 323//271 275//345 +f 464//428 109//429 1780//261 +f 110//70 1535//430 1536//431 +f 1531//71 110//70 802//432 +f 114//9 327//14 390//433 +f 1920//434 645//435 299//436 +f 1947//437 2368//438 1317//439 +f 2473//440 129//441 856//375 +f 129//441 111//408 856//375 +f 111//408 141//442 103//376 +f 103//376 141//442 117//409 +f 141//442 118//443 117//409 +f 107//422 142//410 96//379 +f 112//102 285//300 378//103 +f 312//444 282//386 171//385 +f 1747//381 483//279 72//307 +f 119//445 523//424 108//423 +f 447//360 113//446 69//298 +f 318//67 114//9 2520//447 +f 2321//448 2135//449 2521//450 +f 116//451 111//408 129//441 +f 116//451 141//442 111//408 +f 117//409 118//443 107//422 +f 107//422 161//452 142//410 +f 523//424 119//445 711//453 +f 331//270 430//454 323//271 +f 447//360 68//296 470//455 +f 120//456 1460//457 1950//458 +f 151//459 363//460 121//461 +f 312//444 122//462 282//386 +f 1338//463 2082//464 1339//465 +f 116//451 140//466 141//442 +f 710//467 275//345 123//344 +f 2463//468 1201//469 1209//470 +f 1103//129 1023//130 1060//471 +f 100//371 1075//472 2519//394 +f 125//473 1389//474 2522//475 +f 138//476 139//477 2473//440 +f 118//443 148//478 107//422 +f 176//479 108//423 142//410 +f 176//479 119//445 108//423 +f 340//480 670//389 315//388 +f 122//462 330//481 126//482 +f 1458//483 127//484 474//485 +f 193//486 89//357 221//359 +f 166//487 430//454 150//396 +f 378//103 282//386 1148//488 +f 2215//489 128//490 2216//28 +f 1919//491 1204//181 1761//492 +f 2473//440 159//493 129//441 +f 129//441 159//493 116//451 +f 148//478 161//452 107//422 +f 170//494 119//445 176//479 +f 130//383 131//302 444//384 +f 311//495 432//496 428//497 +f 976//498 132//499 965//500 +f 430//454 267//417 150//396 +f 133//501 134//16 135//502 +f 1077//503 328//504 124//13 +f 136//231 1892//230 1883//505 +f 137//506 661//507 662//251 +f 138//476 2443//508 139//477 +f 139//477 147//509 2473//440 +f 2473//440 147//509 159//493 +f 159//493 160//510 116//451 +f 116//451 160//510 140//466 +f 140//466 148//478 141//442 +f 148//478 118//443 141//442 +f 161//452 143//511 142//410 +f 142//410 143//511 176//479 +f 119//445 604//512 711//453 +f 443//382 70//303 130//383 +f 416//513 151//459 144//514 +f 607//515 538//516 167//517 +f 133//501 1851//518 134//16 +f 145//275 2433//519 2399//520 +f 1050//17 134//16 450//521 +f 1835//522 1338//463 1389//474 +f 146//523 147//509 139//477 +f 175//524 148//478 140//466 +f 148//478 175//524 161//452 +f 149//525 166//487 150//396 +f 286//526 167//517 329//527 +f 329//527 89//357 193//486 +f 425//528 154//529 151//459 +f 967//530 607//515 152//531 +f 154//529 498//532 153//533 +f 154//529 1009//534 498//532 +f 733//535 155//536 156//537 +f 473//538 621//358 89//357 +f 1731//539 1778//540 1476//541 +f 101//404 958//542 157//543 +f 465//544 1230//545 455//546 +f 2234//547 2364//175 158//548 +f 147//509 174//549 159//493 +f 174//549 160//510 159//493 +f 175//524 140//466 160//510 +f 175//524 162//550 161//452 +f 161//452 162//550 143//511 +f 162//550 177//551 143//511 +f 177//551 176//479 143//511 +f 170//494 197//552 119//445 +f 197//552 225//553 604//512 +f 119//445 197//552 604//512 +f 2410//425 2409//411 404//426 +f 431//554 341//555 192//556 +f 163//557 164//558 2523//559 +f 149//525 445//321 166//487 +f 152//531 607//515 167//517 +f 981//560 1108//561 168//419 +f 139//477 173//562 146//523 +f 176//479 169//563 170//494 +f 169//563 197//552 170//494 +f 171//385 329//527 193//486 +f 315//388 99//390 356//564 +f 221//359 343//565 312//444 +f 447//360 98//361 68//296 +f 172//566 203//567 1769//568 +f 173//562 174//549 146//523 +f 174//549 147//509 146//523 +f 196//569 160//510 174//549 +f 183//570 175//524 160//510 +f 199//571 162//550 175//524 +f 169//563 176//479 177//551 +f 221//359 165//572 178//573 +f 732//350 691//278 155//536 +f 68//296 98//361 211//574 +f 126//482 179//254 284//575 +f 180//576 855//577 823//578 +f 202//579 203//567 1851//518 +f 673//580 965//500 6//35 +f 181//581 2021//582 182//583 +f 196//569 183//570 160//510 +f 175//524 183//570 199//571 +f 169//563 191//584 197//552 +f 284//575 179//254 361//256 +f 144//514 121//461 184//427 +f 404//426 144//514 184//427 +f 700//585 416//513 2409//411 +f 185//413 700//585 2409//411 +f 416//513 425//528 151//459 +f 1059//586 1024//162 186//587 +f 18//85 187//109 27//115 +f 2052//588 2268//330 1119//589 +f 188//590 1496//591 2342//592 +f 162//550 189//593 177//551 +f 189//593 190//594 177//551 +f 190//594 191//584 169//563 +f 177//551 190//594 169//563 +f 445//321 275//345 323//271 +f 835//595 2410//425 2371//596 +f 298//297 211//574 277//101 +f 192//556 269//597 386//598 +f 193//486 312//444 171//385 +f 756//599 194//600 2524//601 +f 213//602 1769//568 203//567 +f 1208//603 1698//604 1769//568 +f 80//125 27//115 366//205 +f 2464//605 173//562 195//606 +f 2464//605 174//549 173//562 +f 196//569 199//571 183//570 +f 189//593 162//550 199//571 +f 217//607 197//552 191//584 +f 228//608 225//553 197//552 +f 474//485 383//609 1240//610 +f 361//256 685//255 339//325 +f 213//602 214//611 1769//568 +f 214//611 1208//603 1769//568 +f 198//84 1062//19 85//18 +f 204//612 174//549 2464//605 +f 205//613 196//569 174//549 +f 208//614 199//571 207//615 +f 208//614 189//593 199//571 +f 439//616 200//617 876//618 +f 710//467 750//619 275//345 +f 248//620 2525//621 201//163 +f 202//579 565//622 203//567 +f 54//135 429//131 42//145 +f 204//612 205//613 174//549 +f 205//613 206//623 196//569 +f 196//569 206//623 199//571 +f 206//623 207//615 199//571 +f 189//593 208//614 190//594 +f 190//594 217//607 191//584 +f 225//553 2526//624 209//625 +f 1049//626 767//627 210//628 +f 1086//629 122//462 126//482 +f 211//574 98//361 112//102 +f 2216//28 1865//630 626//631 +f 211//574 112//102 277//101 +f 1055//148 212//632 201//163 +f 909//633 1111//634 878//312 +f 565//622 237//635 213//602 +f 203//567 565//622 213//602 +f 237//635 214//611 213//602 +f 1157//636 345//42 1046//61 +f 1702//637 1913//638 1907//639 +f 215//640 216//641 2464//605 +f 216//641 204//612 2464//605 +f 208//614 223//642 190//594 +f 227//643 217//607 190//594 +f 227//643 228//608 217//607 +f 217//607 228//608 197//552 +f 218//644 219//645 2526//624 +f 316//646 1477//416 1478//647 +f 220//648 562//649 873//650 +f 739//651 480//652 212//632 +f 221//359 163//557 2523//559 +f 803//123 1648//218 222//124 +f 215//640 226//653 216//641 +f 223//642 227//643 190//594 +f 228//608 247//654 225//553 +f 247//654 224//655 2527//656 +f 224//655 218//644 2527//656 +f 242//657 772//328 713//658 +f 733//535 829//659 64//276 +f 416//513 297//660 425//528 +f 130//383 70//303 131//302 +f 200//617 909//633 878//312 +f 353//199 27//115 187//109 +f 381//200 85//18 435//265 +f 2463//468 1260//661 215//640 +f 1260//661 226//653 215//640 +f 226//653 239//662 216//641 +f 239//662 204//612 216//641 +f 227//643 246//663 228//608 +f 228//608 246//663 247//654 +f 662//251 181//581 924//664 +f 405//665 340//480 342//666 +f 480//652 229//667 201//163 +f 212//632 480//652 201//163 +f 229//667 248//620 201//163 +f 1114//204 1503//203 834//668 +f 238//669 2528//670 1209//470 +f 234//671 204//612 239//662 +f 234//671 205//613 204//612 +f 234//671 206//623 205//613 +f 206//623 234//671 207//615 +f 223//642 235//672 227//643 +f 227//643 235//672 246//663 +f 19//80 1497//79 230//673 +f 84//351 106//353 231//674 +f 798//675 122//462 1086//629 +f 282//386 798//675 1148//488 +f 431//554 342//666 341//555 +f 565//622 232//676 237//635 +f 264//677 233//678 238//669 +f 238//669 233//678 2528//670 +f 1260//661 254//679 226//653 +f 234//671 2529//680 208//614 +f 207//615 234//671 208//614 +f 208//614 235//672 223//642 +f 231//674 106//353 940//681 +f 897//682 1050//17 1431//683 +f 332//684 453//685 236//686 +f 221//359 178//573 343//565 +f 232//676 244//687 237//635 +f 237//635 244//687 214//611 +f 251//688 238//669 214//611 +f 233//678 270//689 1260//661 +f 239//662 255//690 234//671 +f 255//690 240//691 234//671 +f 240//691 235//672 2529//680 +f 235//672 241//692 246//663 +f 886//693 242//657 1110//694 +f 2410//425 184//427 2371//596 +f 282//386 122//462 798//675 +f 814//695 968//696 243//697 +f 1994//214 1755//698 1995//699 +f 244//687 251//688 214//611 +f 1260//661 245//700 254//679 +f 254//679 239//662 226//653 +f 254//679 255//690 239//662 +f 259//701 235//672 240//691 +f 259//701 241//692 235//672 +f 241//692 261//702 246//663 +f 261//702 273//703 246//663 +f 246//663 273//703 247//654 +f 247//654 272//704 224//655 +f 266//705 1078//706 218//644 +f 1011//707 1112//708 1500//709 +f 192//556 341//555 269//597 +f 479//710 253//711 229//667 +f 472//712 248//620 253//711 +f 384//713 324//714 459//715 +f 249//31 41//196 250//32 +f 1349//716 244//687 232//676 +f 251//688 264//677 238//669 +f 270//689 245//700 1260//661 +f 252//717 982//347 508//718 +f 479//710 768//719 253//711 +f 233//678 289//720 270//689 +f 254//679 256//721 255//690 +f 256//721 257//722 255//690 +f 255//690 257//722 240//691 +f 257//722 258//723 240//691 +f 258//723 290//724 240//691 +f 290//724 259//701 240//691 +f 291//725 241//692 259//701 +f 291//725 260//726 241//692 +f 260//726 261//702 241//692 +f 260//726 273//703 261//702 +f 273//703 272//704 247//654 +f 341//555 262//727 269//597 +f 736//259 962//728 961//729 +f 299//436 263//730 935//731 +f 858//217 1648//218 803//123 +f 1192//732 287//733 251//688 +f 301//734 264//677 251//688 +f 265//735 233//678 264//677 +f 265//735 289//720 233//678 +f 256//721 254//679 245//700 +f 304//736 256//721 245//700 +f 322//737 273//703 260//726 +f 266//705 224//655 272//704 +f 430//454 443//382 267//417 +f 791//738 178//573 487//739 +f 262//727 268//740 269//597 +f 677//741 768//719 479//710 +f 251//688 244//687 1192//732 +f 287//733 301//734 251//688 +f 289//720 245//700 270//689 +f 280//742 257//722 256//721 +f 257//722 279//743 258//723 +f 258//723 271//744 290//724 +f 296//745 260//726 291//725 +f 272//704 273//703 266//705 +f 386//598 269//597 268//740 +f 750//619 274//343 275//345 +f 768//719 2269//746 472//712 +f 253//711 768//719 472//712 +f 43//207 49//187 1650//167 +f 2269//746 593//398 1014//747 +f 1079//748 1097//749 1021//23 +f 301//734 265//735 264//677 +f 265//735 303//750 289//720 +f 276//751 256//721 304//736 +f 276//751 280//742 256//721 +f 280//742 279//743 257//722 +f 279//743 271//744 258//723 +f 440//752 277//101 278//753 +f 286//526 329//527 171//385 +f 276//751 279//743 280//742 +f 271//744 309//754 290//724 +f 296//745 322//737 260//726 +f 328//504 266//705 273//703 +f 281//324 324//714 339//325 +f 378//103 313//387 282//386 +f 194//600 283//320 449//322 +f 284//575 385//755 458//756 +f 2216//28 626//631 625//29 +f 285//300 286//526 313//387 +f 8//24 649//26 1630//41 +f 435//265 53//20 74//134 +f 53//20 54//135 74//134 +f 301//734 287//733 288//757 +f 300//758 265//735 301//734 +f 303//750 304//736 289//720 +f 304//736 245//700 289//720 +f 309//754 293//759 290//724 +f 290//724 293//759 259//701 +f 294//760 291//725 259//701 +f 467//761 1413//762 2215//489 +f 1397//763 73//309 1497//79 +f 300//758 303//750 265//735 +f 292//764 276//751 304//736 +f 292//764 279//743 276//751 +f 293//759 294//760 259//701 +f 294//760 295//765 291//725 +f 295//765 296//745 291//725 +f 462//766 1275//767 297//660 +f 68//296 211//574 298//297 +f 935//731 934//768 299//436 +f 1545//338 250//32 869//229 +f 288//757 300//758 301//734 +f 300//758 302//769 303//750 +f 302//769 304//736 303//750 +f 302//769 1302//770 304//736 +f 304//736 1302//770 292//764 +f 292//764 1199//771 279//743 +f 1199//771 310//772 271//744 +f 279//743 1199//771 271//744 +f 271//744 310//772 309//754 +f 294//760 336//773 295//765 +f 295//765 322//737 296//745 +f 328//504 273//703 322//737 +f 979//774 305//333 306//775 +f 184//427 659//776 2371//596 +f 262//727 356//564 311//495 +f 470//455 463//295 307//777 +f 2270//778 1014//747 308//779 +f 1219//780 1295//781 1199//771 +f 309//754 310//772 293//759 +f 252//717 560//782 994//783 +f 311//495 356//564 432//496 +f 193//486 221//359 312//444 +f 313//387 286//526 171//385 +f 178//573 791//738 343//565 +f 1//2 877//1 858//217 +f 907//5 1012//142 837//144 +f 380//784 353//199 381//200 +f 1318//785 300//758 288//757 +f 1368//786 1318//785 288//757 +f 1318//785 302//769 300//758 +f 314//339 335//372 1181//374 +f 1035//105 1011//707 1116//112 +f 293//759 336//773 294//760 +f 894//245 2114//787 1120//788 +f 1173//789 281//324 448//790 +f 340//480 315//388 341//555 +f 332//684 284//575 458//756 +f 316//646 317//414 1477//416 +f 16//66 93//111 318//67 +f 1017//791 664//308 973//792 +f 182//583 637//793 1335//794 +f 319//795 320//796 352//797 +f 1318//785 1700//798 302//769 +f 302//769 1700//798 1302//770 +f 337//799 295//765 336//773 +f 321//800 322//737 2530//801 +f 325//802 321//800 2530//801 +f 321//800 328//504 322//737 +f 1438//803 1751//804 1375//805 +f 356//564 446//806 432//496 +f 136//231 1883//505 818//807 +f 592//299 286//526 285//300 +f 166//487 323//271 430//454 +f 867//808 2531//809 2295//252 +f 1223//810 1318//785 1368//786 +f 1224//811 1225//812 1700//798 +f 1254//813 1163//814 2287//815 +f 281//324 373//136 324//714 +f 121//461 363//460 781//816 +f 1369//817 293//759 310//772 +f 293//759 1369//817 336//773 +f 374//818 321//800 325//802 +f 326//819 328//504 321//800 +f 326//819 327//14 328//504 +f 329//527 538//516 473//538 +f 126//482 330//481 179//254 +f 91//272 338//363 331//270 +f 453//685 332//684 458//756 +f 167//517 538//516 329//527 +f 344//820 319//795 352//797 +f 1939//821 2080//822 2268//330 +f 2080//822 333//331 2268//330 +f 1009//534 154//529 1008//823 +f 389//824 74//134 334//315 +f 335//372 380//784 395//825 +f 1371//826 336//773 1369//817 +f 336//773 1371//826 337//799 +f 325//802 295//765 337//799 +f 326//819 390//433 327//14 +f 791//738 330//481 343//565 +f 338//363 443//382 430//454 +f 361//256 339//325 384//713 +f 340//480 341//555 342//666 +f 431//554 131//302 342//666 +f 343//565 330//481 122//462 +f 778//827 352//797 351//176 +f 344//820 364//828 319//795 +f 364//828 1304//829 319//795 +f 345//42 1157//636 346//54 +f 502//364 347//830 2517//365 +f 369//831 325//802 337//799 +f 982//347 252//717 83//348 +f 658//832 1478//647 770//833 +f 1014//747 548//397 349//834 +f 348//835 349//834 350//836 +f 312//444 343//565 122//462 +f 778//827 351//176 666//837 +f 777//838 778//827 666//837 +f 370//839 352//797 778//827 +f 370//839 344//820 352//797 +f 1194//840 414//841 1179//842 +f 366//205 353//199 335//372 +f 839//137 806//139 354//843 +f 471//96 788//4 23//6 +f 124//13 1047//844 1077//503 +f 635//845 355//846 1331//847 +f 337//799 1239//848 369//831 +f 706//849 670//389 340//480 +f 268//740 311//495 428//497 +f 315//388 356//564 262//727 +f 357//160 358//12 359//850 +f 1241//253 2531//809 180//576 +f 281//324 334//315 373//136 +f 360//851 1388//852 1514//853 +f 369//831 374//818 325//802 +f 375//854 321//800 374//818 +f 1730//855 1733//232 474//485 +f 284//575 361//256 384//713 +f 152//531 632//856 362//857 +f 151//459 153//533 363//460 +f 127//484 1730//855 474//485 +f 393//858 1304//829 364//828 +f 1304//829 393//858 365//859 +f 366//205 335//372 314//339 +f 353//199 380//784 335//372 +f 367//860 1482//861 1405//862 +f 346//54 1157//636 1126//56 +f 1162//863 1174//864 549//865 +f 368//866 369//831 1239//848 +f 520//867 461//868 297//660 +f 242//657 1118//326 772//328 +f 778//827 419//869 370//839 +f 370//839 419//869 344//820 +f 393//858 364//828 344//820 +f 371//870 372//871 1499//872 +f 373//136 460//146 324//714 +f 314//339 1181//374 1710//873 +f 1431//683 1697//874 1432//875 +f 821//876 552//332 1994//214 +f 368//866 402//877 369//831 +f 402//877 374//818 369//831 +f 390//433 326//819 321//800 +f 375//854 390//433 321//800 +f 1844//878 376//879 1732//880 +f 384//713 339//325 324//714 +f 311//495 268//740 262//727 +f 99//390 723//881 377//882 +f 285//300 313//387 378//103 +f 778//827 417//883 419//869 +f 419//869 406//884 344//820 +f 406//884 393//858 344//820 +f 393//858 392//885 365//859 +f 1182//369 379//886 2532//887 +f 380//784 381//200 382//888 +f 819//889 137//506 383//609 +f 1236//890 1235//891 388//892 +f 1275//767 154//529 425//528 +f 284//575 384//713 385//755 +f 386//598 268//740 456//893 +f 167//517 286//526 602//894 +f 387//185 1031//165 1097//749 +f 388//892 394//895 1244//896 +f 389//824 334//315 1173//789 +f 1233//897 402//877 368//866 +f 415//898 375//854 374//818 +f 415//898 390//433 375//854 +f 893//899 1358//900 1937//901 +f 298//297 277//101 440//752 +f 377//882 454//902 356//564 +f 391//37 1217//903 1180//38 +f 406//884 392//885 393//858 +f 381//200 435//265 382//888 +f 435//265 74//134 389//824 +f 1271//904 409//905 388//892 +f 1235//891 1271//904 388//892 +f 409//905 394//895 388//892 +f 335//372 395//825 95//373 +f 917//380 903//368 483//279 +f 221//359 621//358 163//557 +f 113//446 447//360 454//902 +f 377//882 356//564 99//390 +f 392//885 396//906 1259//907 +f 397//908 412//909 1271//904 +f 398//910 1244//896 394//895 +f 398//910 399//911 1244//896 +f 400//912 382//888 389//824 +f 2466//913 2534//914 2533//915 +f 422//916 402//877 1194//840 +f 422//916 374//818 402//877 +f 403//917 390//433 415//898 +f 403//917 624//68 390//433 +f 338//363 70//303 443//382 +f 2409//411 144//514 404//426 +f 405//665 342//666 131//302 +f 646//346 283//320 2535//918 +f 418//919 392//885 406//884 +f 419//869 418//919 406//884 +f 1229//920 1259//907 396//906 +f 396//906 407//921 1229//920 +f 1196//922 412//909 397//908 +f 412//909 408//923 1271//904 +f 408//923 413//924 1271//904 +f 413//924 409//905 1271//904 +f 413//924 394//895 409//905 +f 436//925 398//910 394//895 +f 398//910 1288//926 399//911 +f 877//1 1639//927 1636//928 +f 380//784 410//929 395//825 +f 442//930 415//898 2536//931 +f 423//932 624//68 403//917 +f 699//933 733//535 64//276 +f 917//380 1747//381 411//934 +f 154//529 153//533 151//459 +f 392//885 407//921 396//906 +f 426//935 408//923 412//909 +f 413//924 421//936 394//895 +f 414//841 1194//840 402//877 +f 442//930 403//917 415//898 +f 315//388 262//727 341//555 +f 756//599 646//346 2535//918 +f 2409//411 416//513 144//514 +f 417//883 418//919 419//869 +f 418//919 433//937 392//885 +f 392//885 433//937 407//921 +f 1865//630 84//351 1167//318 +f 1196//922 426//935 412//909 +f 426//935 420//938 408//923 +f 408//923 457//939 413//924 +f 457//939 421//936 413//924 +f 436//925 394//895 421//936 +f 1173//789 334//315 281//324 +f 438//940 422//916 1194//840 +f 438//940 441//941 422//916 +f 442//930 2536//931 422//916 +f 441//941 442//930 422//916 +f 429//131 624//68 423//932 +f 163//557 424//942 164//558 +f 297//660 1275//767 425//528 +f 151//459 121//461 144//514 +f 433//937 434//943 407//921 +f 434//943 455//546 407//921 +f 1196//922 466//944 426//935 +f 466//944 420//938 426//935 +f 420//938 469//945 408//923 +f 408//923 469//945 457//939 +f 427//946 398//910 436//925 +f 427//946 1288//926 398//910 +f 980//335 849//280 78//334 +f 432//496 470//455 428//497 +f 429//131 423//932 42//145 +f 338//363 430//454 331//270 +f 444//384 131//302 431//554 +f 446//806 470//455 432//496 +f 685//255 684//323 339//325 +f 924//664 182//583 1335//794 +f 433//937 149//525 434//943 +f 382//888 435//265 389//824 +f 382//888 410//929 380//784 +f 421//936 452//947 436//925 +f 452//947 427//946 436//925 +f 904//948 970//246 78//334 +f 437//949 438//940 1179//842 +f 437//949 453//685 438//940 +f 453//685 441//941 438//940 +f 459//715 423//932 403//917 +f 200//617 439//616 371//870 +f 417//883 194//600 418//919 +f 367//860 1176//950 1482//861 +f 440//752 1288//926 427//946 +f 458//756 442//930 441//941 +f 385//755 403//917 442//930 +f 385//755 459//715 403//917 +f 468//395 443//382 444//384 +f 445//321 323//271 166//487 +f 446//806 447//360 470//455 +f 684//323 448//790 281//324 +f 194//600 449//322 418//919 +f 418//919 449//322 433//937 +f 1697//874 1263//951 450//521 +f 1230//545 465//544 1197//952 +f 431//554 466//944 1197//952 +f 420//938 456//893 469//945 +f 469//945 428//497 457//939 +f 457//939 451//953 421//936 +f 451//953 452//947 421//936 +f 236//686 453//685 437//949 +f 458//756 385//755 442//930 +f 1712//277 508//718 691//278 +f 454//902 447//360 446//806 +f 454//902 446//806 356//564 +f 449//322 149//525 433//937 +f 434//943 465//544 455//546 +f 466//944 386//598 420//938 +f 420//938 386//598 456//893 +f 428//497 451//953 457//939 +f 463//295 452//947 451//953 +f 463//295 427//946 452//947 +f 298//297 440//752 427//946 +f 1171//954 1179//842 1366//955 +f 458//756 441//941 453//685 +f 460//146 423//932 459//715 +f 460//146 42//145 423//932 +f 461//868 462//766 297//660 +f 692//956 194//600 417//883 +f 465//544 431//554 1197//952 +f 307//777 463//295 451//953 +f 427//946 463//295 298//297 +f 2052//588 109//429 464//428 +f 1073//957 1179//842 1171//954 +f 385//755 384//713 459//715 +f 252//717 994//783 83//348 +f 706//849 340//480 405//665 +f 449//322 445//321 149//525 +f 149//525 150//396 434//943 +f 434//943 468//395 465//544 +f 465//544 444//384 431//554 +f 466//944 192//556 386//598 +f 428//497 307//777 451//953 +f 467//761 2216//28 1664//27 +f 470//455 68//296 463//295 +f 434//943 150//396 468//395 +f 468//395 444//384 465//544 +f 431//554 192//556 466//944 +f 456//893 268//740 469//945 +f 268//740 428//497 469//945 +f 428//497 470//455 307//777 +f 22//95 1549//958 471//96 +f 709//959 123//344 734//960 +f 1086//629 126//482 284//575 +f 377//882 757//961 454//902 +f 722//962 349//834 548//397 +f 454//902 757//961 113//446 +f 248//620 472//712 2537//963 +f 634//964 537//965 675//966 +f 614//967 657//968 718//969 +f 639//970 707//971 771//301 +f 2434//972 2225//973 769//974 +f 763//975 473//538 539//976 +f 1733//232 136//231 474//485 +f 776//977 462//766 511//978 +f 606//979 518//980 575//981 +f 476//982 511//978 520//867 +f 363//460 475//983 534//984 +f 898//985 849//280 92//366 +f 1347//986 232//676 1526//987 +f 696//988 511//978 476//982 +f 476//982 520//867 477//989 +f 1864//990 58//250 936//991 +f 755//992 478//993 493//994 +f 479//710 480//652 739//651 +f 539//976 473//538 538//516 +f 922//995 872//996 529//997 +f 481//998 482//999 891//1000 +f 483//279 484//367 849//280 +f 721//1001 720//1002 718//969 +f 640//1003 485//1004 641//1005 +f 242//657 486//1006 1110//694 +f 12//52 11//51 1987//1007 +f 569//208 2283//1008 50//209 +f 685//255 487//739 178//573 +f 755//992 488//1009 712//1010 +f 772//328 679//1011 713//658 +f 686//1012 489//1013 2306//1014 +f 569//208 497//304 490//1015 +f 490//1015 2283//1008 569//208 +f 1607//1016 2113//1017 888//1018 +f 71//305 503//1019 497//304 +f 1653//1020 1654//1021 1638//1022 +f 491//1023 549//865 164//558 +f 492//1024 2538//1025 794//1026 +f 493//994 494//1027 488//1009 +f 720//1002 495//393 2539//1028 +f 523//424 2361//1029 67//294 +f 764//1030 316//646 1478//647 +f 672//1031 477//989 496//1032 +f 29//40 1657//289 2298//1033 +f 501//1034 503//1019 71//305 +f 497//304 513//1035 490//1015 +f 363//460 153//533 498//532 +f 712//1010 488//1009 640//1003 +f 495//393 499//392 591//1036 +f 500//1037 2284//1038 512//1039 +f 500//1037 501//1034 2284//1038 +f 490//1015 502//364 2283//1008 +f 720//1002 754//1040 668//1041 +f 515//1042 503//1019 501//1034 +f 490//1015 513//1035 502//364 +f 1017//791 973//792 1534//1043 +f 496//1032 648//1044 2327//1045 +f 521//1046 501//1034 500//1037 +f 521//1046 515//1042 501//1034 +f 515//1042 524//1047 503//1019 +f 503//1019 524//1047 497//304 +f 497//304 524//1047 513//1035 +f 674//1048 476//982 783//1049 +f 674//1048 696//988 476//982 +f 533//1050 504//1051 618//1052 +f 743//1053 925//1054 731//1055 +f 164//558 549//865 165//572 +f 1978//1056 505//1057 506//64 +f 525//1058 512//1039 2360//1059 +f 507//1060 500//1037 512//1039 +f 513//1035 516//1061 502//364 +f 508//718 982//347 695//1062 +f 696//988 509//1063 776//977 +f 698//1064 730//1065 510//1066 +f 636//1067 620//1068 603//1069 +f 511//978 462//766 461//868 +f 776//977 509//1063 990//1070 +f 525//1058 507//1060 512//1039 +f 521//1046 500//1037 507//1060 +f 524//1047 522//1071 513//1035 +f 587//1072 514//1073 572//1074 +f 715//1075 585//1076 735//1077 +f 515//1042 541//1078 524//1047 +f 516//1061 347//830 502//364 +f 517//1079 1707//1080 2165//1081 +f 185//413 477//989 520//867 +f 518//980 785//1082 575//981 +f 355//846 519//1083 969//1084 +f 520//867 511//978 461//868 +f 515//1042 521//1046 541//1078 +f 522//1071 530//1085 513//1035 +f 513//1035 530//1085 516//1061 +f 758//1086 69//298 113//446 +f 640//1003 581//1087 485//1004 +f 496//1032 477//989 744//1088 +f 570//1089 2540//1090 596//1091 +f 526//1092 525//1058 2361//1029 +f 523//424 526//1092 2361//1029 +f 541//1078 522//1071 524//1047 +f 2541//1093 585//1076 2542//1094 +f 507//1060 525//1058 526//1092 +f 530//1085 558//1095 516//1061 +f 505//1057 1177//1096 1736//1097 +f 475//983 704//1098 533//1050 +f 527//1099 535//1100 705//1101 +f 795//1102 847//1103 796//1104 +f 796//1104 799//1105 568//1106 +f 799//1105 749//1107 568//1106 +f 857//1108 535//1100 799//1105 +f 528//1109 922//995 529//997 +f 546//1110 521//1046 507//1060 +f 546//1110 555//1111 521//1046 +f 555//1111 541//1078 521//1046 +f 541//1078 556//1112 522//1071 +f 556//1112 557//1113 522//1071 +f 522//1071 557//1113 530//1085 +f 557//1113 531//1114 530//1085 +f 530//1085 531//1114 558//1095 +f 558//1095 551//1115 516//1061 +f 551//1115 347//830 516//1061 +f 527//1099 705//1101 532//1116 +f 475//983 533//1050 534//984 +f 699//933 57//249 733//535 +f 535//1100 527//1099 799//1105 +f 526//1092 546//1110 507//1060 +f 536//1117 347//830 551//1115 +f 1736//1097 1177//1096 1016//1118 +f 621//358 537//965 163//557 +f 538//516 607//515 539//976 +f 555//1111 540//1119 541//1078 +f 540//1119 556//1112 541//1078 +f 1025//161 542//169 543//225 +f 2460//1120 133//501 135//502 +f 797//1121 133//501 2460//1120 +f 1870//257 57//249 699//933 +f 1405//862 1482//861 1484//1122 +f 763//975 537//965 621//358 +f 544//1123 581//1087 494//1027 +f 581//1087 640//1003 494//1027 +f 920//1124 545//1125 801//1126 +f 683//1127 1293//1128 784//1129 +f 2029//1130 2224//1131 1865//630 +f 711//453 583//1132 546//1110 +f 526//1092 711//453 546//1110 +f 546//1110 583//1132 555//1111 +f 547//1133 609//1134 548//397 +f 478//993 755//992 594//1135 +f 1174//864 448//790 549//865 +f 549//865 448//790 165//572 +f 632//856 602//894 758//1086 +f 1058//1136 491//1023 164//558 +f 563//1137 556//1112 540//1119 +f 600//1138 551//1115 558//1095 +f 600//1138 550//1139 551//1115 +f 550//1139 536//1117 551//1115 +f 536//1117 1019//1140 347//830 +f 1119//589 552//332 821//876 +f 821//876 1303//213 553//1141 +f 554//1142 719//1143 617//1144 +f 583//1132 582//1145 555//1111 +f 582//1145 584//1146 555//1111 +f 555//1111 584//1146 540//1119 +f 563//1137 573//1147 556//1112 +f 566//1148 557//1113 556//1112 +f 573//1147 566//1148 556//1112 +f 599//1149 2543//1150 566//1148 +f 599//1149 531//1114 2543//1150 +f 559//1151 558//1095 531//1114 +f 599//1149 559//1151 531//1114 +f 558//1095 559//1151 600//1138 +f 564//1152 536//1117 550//1139 +f 536//1117 564//1152 1019//1140 +f 560//782 1717//1153 994//783 +f 561//1154 936//991 2544//1155 +f 588//1156 540//1119 584//1146 +f 540//1119 588//1156 563//1137 +f 600//1138 564//1152 550//1139 +f 2442//1157 195//606 139//477 +f 202//579 133//501 797//1121 +f 202//579 1851//518 133//501 +f 565//622 202//579 574//1158 +f 801//1126 545//1125 1836//1159 +f 554//1142 759//1160 719//1143 +f 1021//23 681//1161 1079//748 +f 588//1156 573//1147 563//1137 +f 573//1147 599//1149 566//1148 +f 2452//1162 935//731 263//730 +f 995//1163 1019//1140 567//172 +f 636//1067 608//1164 789//1165 +f 155//536 695//1062 156//537 +f 967//530 608//1164 607//515 +f 2233//1166 795//1102 568//1106 +f 920//1124 617//1144 545//1125 +f 573//1147 613//1167 599//1149 +f 600//1138 590//1168 564//1152 +f 986//1169 2456//1170 2469//1171 +f 732//350 155//536 733//535 +f 59//233 497//304 569//208 +f 683//1127 570//1089 759//1160 +f 758//1086 602//894 592//299 +f 970//246 894//245 737//258 +f 571//1172 587//1072 493//994 +f 1977//1173 1699//1174 2039//1175 +f 572//1074 581//1087 544//1123 +f 588//1156 612//1176 573//1147 +f 590//1168 622//1177 564//1152 +f 2115//1178 574//1158 797//1121 +f 785//1082 688//1179 575//981 +f 632//856 152//531 602//894 +f 2545//1180 659//776 2546//1181 +f 577//1182 578//420 653//1183 +f 790//1184 510//1066 579//1185 +f 580//1186 761//1187 518//980 +f 581//1087 762//1188 580//1186 +f 616//1189 582//1145 583//1132 +f 604//512 616//1189 583//1132 +f 616//1189 584//1146 582//1145 +f 559//1151 599//1149 600//1138 +f 928//1190 590//1168 600//1138 +f 2115//1178 1526//987 574//1158 +f 623//269 2284//1038 501//1034 +f 944//1191 585//1076 2541//1093 +f 1249//1192 1889//1193 1950//458 +f 587//1072 572//1074 544//1123 +f 493//994 587//1072 544//1123 +f 608//1164 967//530 595//1194 +f 598//1195 588//1156 584//1146 +f 588//1156 598//1195 612//1176 +f 928//1190 589//1196 590//1168 +f 590//1168 589//1196 622//1177 +f 1995//699 765//1197 952//215 +f 654//1198 579//1185 629//1199 +f 499//392 638//399 591//1036 +f 459//715 324//714 460//146 +f 602//894 286//526 592//299 +f 548//397 1014//747 593//398 +f 709//959 749//1107 594//1135 +f 595//1194 967//530 362//857 +f 89//357 329//527 473//538 +f 570//1089 596//1091 2547//1200 +f 722//962 635//845 597//1201 +f 1531//71 802//432 1532//177 +f 598//1195 584//1146 616//1189 +f 612//1176 613//1167 573//1147 +f 599//1149 928//1190 600//1138 +f 1887//1202 36//178 1951//180 +f 618//1052 504//1051 579//1185 +f 579//1185 726//1203 601//1204 +f 629//1199 579//1185 601//1204 +f 1739//1205 1869//1206 977//1207 +f 1242//1208 135//502 134//16 +f 152//531 167//517 602//894 +f 603//1069 539//976 607//515 +f 209//625 616//1189 604//512 +f 613//1167 951//1209 599//1149 +f 2356//1210 1293//1128 848//1211 +f 675//966 660//1212 634//964 +f 580//1186 606//979 485//1004 +f 736//259 605//1213 962//728 +f 979//774 973//792 664//308 +f 619//1214 618//1052 579//1185 +f 606//979 580//1186 518//980 +f 581//1087 580//1186 485//1004 +f 603//1069 607//515 608//1164 +f 722//962 597//1201 349//834 +f 552//332 561//1154 2548//1215 +f 663//1216 609//1134 547//1133 +f 1457//1217 1390//1218 2169//1219 +f 598//1195 610//1220 612//1176 +f 610//1220 611//1221 612//1176 +f 612//1176 611//1221 613//1167 +f 613//1167 958//542 951//1209 +f 599//1149 951//1209 928//1190 +f 765//1197 1995//699 614//967 +f 703//1222 758//1086 757//961 +f 601//1204 726//1203 643//1223 +f 660//1212 675//966 633//1224 +f 663//1216 596//1091 609//1134 +f 682//1225 789//1165 615//1226 +f 209//625 598//1195 616//1189 +f 611//1221 958//542 613//1167 +f 617//1144 721//1001 545//1125 +f 618//1052 619//1214 787//1227 +f 693//1228 660//1212 633//1224 +f 636//1067 708//1229 620//1068 +f 763//975 621//358 473//538 +f 755//992 493//994 488//1009 +f 1210//1230 622//1177 589//1196 +f 2236//166 2240//1231 1498//150 +f 59//233 623//269 501//1034 +f 610//1220 1057//1232 611//1221 +f 390//433 624//68 2520//447 +f 652//1233 741//1234 794//1026 +f 625//29 626//631 1167//318 +f 652//1233 424//942 741//1234 +f 587//1072 656//1235 514//1073 +f 627//1236 876//618 941//1237 +f 633//1224 539//976 603//1069 +f 682//1225 636//1067 789//1165 +f 786//1238 601//1204 628//1239 +f 629//1199 601//1204 786//1238 +f 209//625 630//1240 598//1195 +f 598//1195 630//1240 610//1220 +f 611//1221 157//543 958//542 +f 756//599 2363//1241 646//346 +f 749//1107 527//1099 760//1242 +f 577//1182 631//421 578//420 +f 760//1242 527//1099 532//1116 +f 632//856 758//1086 703//1222 +f 708//1229 633//1224 620//1068 +f 660//1212 492//1024 634//964 +f 534//984 618//1052 781//816 +f 355//846 635//845 609//1134 +f 636//1067 603//1069 608//1164 +f 824//1243 871//1244 1931//1245 +f 637//793 826//317 1335//794 +f 630//1240 1057//1232 610//1220 +f 1432//875 1479//1246 1139//1247 +f 1864//990 1863//1248 58//250 +f 750//619 755//992 274//343 +f 647//391 638//399 499//392 +f 33//147 212//632 1055//148 +f 659//776 535//1100 2546//1181 +f 639//970 640//1003 641//1005 +f 585//1076 642//1249 743//1053 +f 628//1239 643//1223 615//1226 +f 628//1239 601//1204 643//1223 +f 1846//1250 644//1251 2130//1252 +f 1057//1232 157//543 611//1221 +f 2222//1253 645//435 1901//1254 +f 734//960 123//344 646//346 +f 50//209 2283//1008 51//234 +f 2233//1166 734//960 646//346 +f 698//1064 2542//1094 730//1065 +f 790//1184 698//1064 510//1066 +f 2222//1253 263//730 299//436 +f 709//959 594//1135 710//467 +f 570//1089 647//391 2549//1255 +f 742//1256 2550//1257 492//1024 +f 2283//1008 63//273 51//234 +f 978//1258 695//1062 983//1259 +f 723//881 99//390 670//389 +f 1836//1159 657//968 1995//699 +f 716//1260 708//1229 682//1225 +f 761//1187 595//1194 518//980 +f 1863//1248 2009//1261 58//250 +f 2272//1262 1267//1263 1264//1264 +f 744//1088 745//412 648//1044 +f 630//1240 209//625 219//645 +f 649//26 650//1265 651//193 +f 689//1266 586//1267 704//1098 +f 2363//1241 2362//1268 646//346 +f 708//1229 716//1260 633//1224 +f 575//981 688//1179 723//881 +f 696//988 6//35 509//1063 +f 652//1233 577//1182 653//1183 +f 705//1101 654//1198 656//1235 +f 1973//1269 36//178 655//1270 +f 705//1101 656//1235 587//1072 +f 799//1105 527//1099 749//1107 +f 363//460 534//984 781//816 +f 976//498 982//347 132//499 +f 982//347 678//349 132//499 +f 849//280 980//335 2513//281 +f 1995//699 657//968 614//967 +f 731//1055 2551//1271 577//1182 +f 801//1126 873//650 658//832 +f 781//816 659//776 121//461 +f 742//1256 492//1024 660//1212 +f 1722//1272 1977//1173 2178//1273 +f 759//1160 2552//1274 2553//1275 +f 654//1198 629//1199 656//1235 +f 661//507 1540//1276 662//251 +f 492//1024 794//1026 634//964 +f 596//1091 663//1216 547//1133 +f 664//308 72//307 2554//1277 +f 665//306 1787//1278 1747//381 +f 510//1066 730//1065 726//1203 +f 835//595 998//1279 2410//425 +f 686//1012 2189//1280 1144//1281 +f 1144//1281 2189//1280 666//837 +f 2189//1280 777//838 666//837 +f 648//1044 745//412 2246//1282 +f 896//1283 831//1284 667//1285 +f 718//969 720//1002 668//1041 +f 703//1222 377//882 723//881 +f 865//82 650//1265 1065//1286 +f 966//1287 1098//1288 1049//626 +f 669//1289 723//881 670//389 +f 545//1125 721//1001 718//969 +f 744//1088 185//413 745//412 +f 567//172 671//1290 995//1163 +f 783//1049 672//1031 972//1291 +f 165//572 448//790 685//255 +f 615//1226 643//1223 682//1225 +f 2549//1255 495//393 2552//1274 +f 673//580 696//988 674//1048 +f 675//966 537//965 633//1224 +f 971//1292 676//1293 672//1031 +f 638//399 2555//1294 591//1036 +f 1002//1295 1386//1296 1511//1297 +f 947//1298 156//537 978//1258 +f 997//1299 2259//1300 678//349 +f 52//237 2096//239 2097//1301 +f 1275//767 462//766 990//1070 +f 33//147 681//1161 679//1011 +f 679//1011 681//1161 713//658 +f 680//149 681//1161 33//147 +f 1669//1302 1022//1303 1674//238 +f 687//1304 692//956 2189//1280 +f 401//1305 2534//914 1474//1306 +f 1419//1307 1040//1308 1039//1309 +f 592//299 69//298 758//1086 +f 725//244 2114//787 894//245 +f 712//1010 90//362 274//343 +f 635//845 1822//1310 597//1201 +f 677//741 2555//1294 2556//1311 +f 730//1065 716//1260 682//1225 +f 784//1129 2540//1090 683//1127 +f 848//1211 1293//1128 683//1127 +f 448//790 684//323 685//255 +f 686//1012 687//1304 2189//1280 +f 688//1179 703//1222 723//881 +f 1534//1043 586//1267 689//1266 +f 726//1203 690//1312 643//1223 +f 726//1203 682//1225 690//1312 +f 691//278 508//718 695//1062 +f 498//532 689//1266 363//460 +f 702//1313 33//147 679//1011 +f 692//956 417//883 777//838 +f 719//1143 759//1160 2553//1275 +f 585//1076 742//1256 735//1077 +f 377//882 703//1222 757//961 +f 730//1065 682//1225 726//1203 +f 693//1228 742//1256 660//1212 +f 496//1032 971//1292 672//1031 +f 886//693 694//262 1118//326 +f 691//278 695//1062 155//536 +f 639//970 641//1005 707//971 +f 506//64 46//223 1978//1056 +f 1221//1314 2557//1315 1268//1316 +f 972//1291 674//1048 783//1049 +f 674//1048 972//1291 673//580 +f 696//988 673//580 6//35 +f 1073//957 437//949 1179//842 +f 492//1024 731//1055 2558//1317 +f 28//117 2299//1318 697//116 +f 704//1098 504//1051 533//1050 +f 704//1098 698//1064 790//1184 +f 738//1319 679//1011 772//328 +f 702//1313 212//632 33//147 +f 2113//1017 1120//788 2114//787 +f 1870//257 699//933 1869//1206 +f 132//499 678//349 2259//1300 +f 700//585 520//867 416//513 +f 705//1101 787//1227 619//1214 +f 1673//1320 1054//1321 701//1322 +f 90//362 712//1010 639//970 +f 1920//434 934//768 895//1323 +f 561//1154 1864//990 936//991 +f 738//1319 702//1313 679//1011 +f 702//1313 739//651 212//632 +f 1664//27 826//317 637//793 +f 725//244 727//189 881//191 +f 2559//1324 1705//1325 2560//1326 +f 362//857 703//1222 688//1179 +f 185//413 520//867 700//585 +f 56//248 1854//260 732//350 +f 506//64 505//1057 1378//1327 +f 704//1098 586//1267 698//1064 +f 535//1100 787//1227 705//1101 +f 504//1051 704//1098 790//1184 +f 641//1005 706//849 707//971 +f 491//1023 2304//1328 1153//1329 +f 424//942 1058//1136 164//558 +f 641//1005 485//1004 706//849 +f 682//1225 708//1229 636//1067 +f 123//344 709//959 710//467 +f 523//424 711//453 526//1092 +f 410//929 382//888 400//912 +f 594//1135 755//992 710//467 +f 640//1003 639//970 712//1010 +f 242//657 713//658 486//1006 +f 64//276 829//659 2326//274 +f 669//1289 714//1330 723//881 +f 715//1075 735//1077 716//1260 +f 728//1331 2096//239 105//418 +f 478//993 571//1172 493//994 +f 717//1332 1436//1333 1546//1334 +f 729//1335 1457//1217 2169//1219 +f 488//1009 494//1027 640//1003 +f 1095//1336 586//1267 1534//1043 +f 743//1053 933//1337 925//1054 +f 614//967 718//969 668//1041 +f 75//292 81//316 523//424 +f 719//1143 720//1002 721//1001 +f 669//1289 670//389 706//849 +f 742//1256 693//1228 735//1077 +f 609//1134 635//845 722//962 +f 714//1330 575//981 723//881 +f 642//1249 933//1337 743//1053 +f 219//645 1057//1232 630//1240 +f 596//1091 547//1133 2547//1200 +f 2341//1338 67//294 2361//1029 +f 534//984 533//1050 618//1052 +f 1534//1043 1533//1339 1017//791 +f 724//1340 553//1141 738//1319 +f 752//1341 739//651 702//1313 +f 752//1341 753//1342 739//651 +f 1284//1343 1283//1344 1928//1345 +f 881//191 2114//787 725//244 +f 687//1304 2402//1346 692//956 +f 593//398 2269//746 2556//1311 +f 653//1183 424//942 652//1233 +f 579//1185 510//1066 726//1203 +f 628//1239 615//1226 762//1188 +f 633//1224 763//975 539//976 +f 857//1108 796//1104 847//1103 +f 2352//1347 2562//1348 2561//1349 +f 904//948 727//189 725//244 +f 104//352 2097//1301 728//1331 +f 714//1330 606//979 575//981 +f 785//1082 362//857 688//1179 +f 532//1116 705//1101 587//1072 +f 568//1106 709//959 734//960 +f 713//658 681//1161 955//1350 +f 1721//1351 729//1335 2169//1219 +f 585//1076 715//1075 730//1065 +f 925//1054 631//421 2551//1271 +f 632//856 703//1222 362//857 +f 57//249 732//350 733//535 +f 724//1340 773//327 821//876 +f 977//1207 64//276 2763//1352 +f 2402//1346 2247//1353 692//956 +f 545//1125 718//969 657//968 +f 643//1223 690//1312 682//1225 +f 532//1116 571//1172 760//1242 +f 2233//1166 568//1106 734//960 +f 789//1165 608//1164 595//1194 +f 735//1077 693//1228 716//1260 +f 585//1076 743//1053 742//1256 +f 736//259 737//258 605//1213 +f 702//1313 738//1319 752//1341 +f 774//1354 479//710 739//651 +f 753//1342 774//1354 739//651 +f 297//660 416//513 520//867 +f 740//1355 903//368 917//380 +f 585//1076 944//1191 642//1249 +f 485//1004 714//1330 669//1289 +f 654//1198 619//1214 579//1185 +f 705//1101 619//1214 654//1198 +f 537//965 741//1234 163//557 +f 742//1256 743//1053 2550//1257 +f 477//989 185//413 744//1088 +f 747//1356 752//1341 738//1319 +f 998//1279 2246//1282 745//412 +f 1712//277 560//782 508//718 +f 746//1357 1637//1358 1541//1359 +f 479//710 229//667 480//652 +f 485//1004 606//979 714//1330 +f 1869//1206 699//933 977//1207 +f 821//876 553//1141 724//1340 +f 903//368 851//1360 92//366 +f 747//1356 738//1319 553//1141 +f 851//1360 898//985 92//366 +f 1919//491 748//1361 1204//181 +f 749//1107 760//1242 594//1135 +f 760//1242 478//993 594//1135 +f 437//949 332//684 236//686 +f 710//467 755//992 750//619 +f 751//1362 753//1342 752//1341 +f 754//1040 774//1354 753//1342 +f 751//1362 754//1040 753//1342 +f 274//343 755//992 712//1010 +f 692//956 2563//1363 2524//601 +f 2247//1353 2363//1241 2563//1363 +f 757//961 758//1086 113//446 +f 683//1127 759//1160 554//1142 +f 518//980 595//1194 785//1082 +f 532//1116 587//1072 571//1172 +f 760//1242 571//1172 478//993 +f 615//1226 761//1187 762//1188 +f 633//1224 537//965 763//975 +f 560//782 252//717 508//718 +f 761//1187 789//1165 595//1194 +f 656//1235 629//1199 514//1073 +f 363//460 689//1266 475//983 +f 716//1260 693//1228 633//1224 +f 764//1030 1478//647 658//832 +f 553//1141 765//1197 747//1356 +f 747//1356 751//1362 752//1341 +f 475//983 689//1266 704//1098 +f 766//1364 943//1365 767//627 +f 768//719 677//741 2269//746 +f 687//1304 686//1012 769//974 +f 653//1183 1058//1136 424//942 +f 72//307 665//306 1747//381 +f 628//1239 762//1188 581//1087 +f 658//832 770//833 920//1124 +f 771//301 405//665 131//302 +f 492//1024 2558//1317 2538//1025 +f 487//739 685//255 179//254 +f 772//328 773//327 724//1340 +f 775//1366 774//1354 754//1040 +f 775//1366 479//710 774//1354 +f 775//1366 677//741 479//710 +f 910//1367 1673//1320 940//681 +f 214//611 2564//1368 1208//603 +f 776//977 990//1070 462//766 +f 348//835 1125//1369 1014//747 +f 777//838 417//883 778//827 +f 514//1073 628//1239 581//1087 +f 514//1073 581//1087 572//1074 +f 617//1144 719//1143 721//1001 +f 762//1188 761//1187 580//1186 +f 511//978 696//988 776//977 +f 781//816 618//1052 787//1227 +f 952//215 765//1197 553//1141 +f 1889//1193 1540//1276 2185//1370 +f 44//219 779//1371 2177//87 +f 672//1031 783//1049 477//989 +f 2371//596 659//776 2545//1180 +f 547//1133 548//397 2565//1372 +f 647//391 547//1133 2565//1372 +f 1093//1373 219//645 1078//706 +f 1203//1374 1213//1375 780//1376 +f 603//1069 620//1068 633//1224 +f 659//776 781//816 535//1100 +f 596//1091 519//1083 609//1134 +f 554//1142 782//1377 683//1127 +f 1956//1378 44//219 2177//87 +f 706//849 485//1004 669//1289 +f 783//1049 476//982 477//989 +f 784//1129 519//1083 596//1091 +f 595//1194 362//857 785//1082 +f 568//1106 749//1107 709//959 +f 1098//1288 1672//1379 355//846 +f 514//1073 786//1238 628//1239 +f 203//567 172//566 134//16 +f 781//816 787//1227 535//1100 +f 668//1041 754//1040 751//1362 +f 775//1366 591//1036 677//741 +f 2237//1380 1012//142 788//4 +f 993//1381 886//693 1110//694 +f 615//1226 789//1165 761//1187 +f 609//1134 722//962 548//397 +f 579//1185 504//1051 790//1184 +f 730//1065 715//1075 716//1260 +f 609//1134 519//1083 355//846 +f 330//481 791//738 487//739 +f 765//1197 614//967 751//1362 +f 747//1356 765//1197 751//1362 +f 614//967 668//1041 751//1362 +f 792//1382 1908//1383 793//1384 +f 67//294 75//292 523//424 +f 634//964 794//1026 537//965 +f 794//1026 741//1234 537//965 +f 795//1102 796//1104 568//1106 +f 1014//747 1125//1369 308//779 +f 494//1027 493//994 544//1123 +f 202//579 797//1121 574//1158 +f 629//1199 786//1238 514//1073 +f 798//675 437//949 1073//957 +f 1365//1385 854//1386 1364//1387 +f 495//393 775//1366 2539//1028 +f 495//393 591//1036 775//1366 +f 163//557 741//1234 424//942 +f 1746//1388 921//319 1167//318 +f 857//1108 799//1105 796//1104 +f 898//985 727//189 904//948 +f 957//81 825//1389 865//82 +f 1552//1390 1549//958 22//95 +f 1552//1390 22//95 40//138 +f 800//1391 816//1392 868//1393 +f 800//1391 868//1393 867//808 +f 919//1394 828//119 820//1395 +f 920//1124 801//1126 658//832 +f 1433//78 923//1396 1497//79 +f 802//432 803//123 1532//177 +f 1228//1397 804//1398 2384//1399 +f 805//1400 2237//1380 807//1401 +f 2384//1399 2458//1402 2460//1120 +f 40//138 22//95 806//139 +f 2273//1403 2296//1404 2372//1405 +f 1451//1406 843//1407 807//1401 +f 1048//151 808//1408 1071//329 +f 1071//329 810//1409 1074//69 +f 2177//87 21//86 1731//539 +f 899//1410 2177//87 1731//539 +f 809//1411 1739//1205 977//1207 +f 1074//69 810//1409 1525//1412 +f 913//1413 828//119 919//1394 +f 1528//311 1400//310 1486//1414 +f 811//1415 560//782 1712//277 +f 2236//166 813//152 841//1416 +f 1535//430 627//1236 1536//431 +f 1936//1417 481//998 2566//1418 +f 2262//1419 2370//1420 2439//1421 +f 1945//1422 812//1423 1705//1325 +f 1907//639 1914//1424 1796//1425 +f 766//1364 866//1426 822//1427 +f 862//216 1548//1428 1015//108 +f 841//1416 813//152 77//197 +f 1329//98 1036//100 1500//709 +f 372//871 1329//98 1500//709 +f 1119//589 1118//326 694//262 +f 1400//310 1350//1429 1383//1430 +f 822//1427 814//695 243//697 +f 1479//1246 815//1431 1124//282 +f 825//1389 1546//1334 1186//30 +f 826//317 816//1392 1335//794 +f 823//578 1175//1432 1458//483 +f 817//1433 831//1284 896//1283 +f 815//1431 360//851 914//1434 +f 937//243 764//1030 562//649 +f 907//5 65//286 1134//285 +f 784//1129 866//1426 2567//1435 +f 1405//862 1484//1122 1483//1436 +f 1925//1437 817//1433 2484//1438 +f 1674//238 1054//1321 1673//1320 +f 1442//1439 1387//1440 1665//1441 +f 845//1442 850//1443 903//368 +f 1735//1444 850//1443 845//1442 +f 136//231 818//807 819//889 +f 939//1445 1763//1446 2157//1447 +f 1865//630 2216//28 128//490 +f 770//833 782//1377 920//1124 +f 901//1448 1925//1437 2484//1438 +f 820//1395 855//577 180//576 +f 820//1395 1044//45 855//577 +f 806//139 1646//1449 354//843 +f 929//1450 927//1451 900//1452 +f 773//327 1119//589 821//876 +f 2356//1210 968//696 814//695 +f 822//1427 866//1426 814//695 +f 2154//1453 1721//1351 2169//1219 +f 959//1454 825//1389 957//81 +f 907//5 837//144 905//1455 +f 1241//253 180//576 823//578 +f 1936//1417 2566//1418 824//1243 +f 1697//874 1698//604 1480//1456 +f 825//1389 1186//30 874//1457 +f 851//1360 850//1443 827//1458 +f 661//507 137//506 819//889 +f 921//319 816//1392 826//317 +f 827//1458 1680//1459 2278//190 +f 1743//1460 1670//1461 1346//1462 +f 913//1413 25//120 828//119 +f 733//535 156//537 829//659 +f 1835//522 830//1463 2122//1464 +f 529//997 872//996 831//1284 +f 1937//901 1830//1465 832//1466 +f 1112//708 1499//872 1500//709 +f 866//1426 784//1129 2356//1210 +f 832//1466 893//899 1937//901 +f 1583//1467 1558//1468 833//1469 +f 831//1284 872//996 667//1285 +f 834//668 1514//853 1513//1470 +f 2370//1420 835//595 2371//596 +f 841//1416 1548//1428 836//1471 +f 905//1455 837//144 842//1472 +f 838//1473 845//1442 740//1355 +f 921//319 919//1394 816//1392 +f 839//137 354//843 1632//1474 +f 875//1475 927//1451 926//1476 +f 1359//1477 908//1478 1682//1479 +f 1548//1428 862//216 840//1480 +f 837//144 841//1416 842//1472 +f 841//1416 77//197 1548//1428 +f 843//1407 805//1400 807//1401 +f 1831//1481 1136//1482 1832//1483 +f 1662//1484 1805//1485 1429//1486 +f 2123//1487 844//1488 943//1365 +f 1702//637 1735//1444 845//1442 +f 1288//926 440//752 846//1489 +f 2307//1490 1238//1491 847//1103 +f 929//1450 900//1452 838//1473 +f 105//418 910//1367 106//353 +f 1542//1492 1625//1493 854//1386 +f 838//1473 740//1355 929//1450 +f 1583//1467 1415//1494 1558//1468 +f 913//1413 919//1394 921//319 +f 562//649 764//1030 658//832 +f 848//1211 683//1127 782//1377 +f 92//366 849//280 484//367 +f 850//1443 851//1360 903//368 +f 1350//1429 1400//310 73//309 +f 922//995 852//1495 864//1496 +f 853//1497 854//1386 439//616 +f 2218//1498 2484//1438 817//1433 +f 855//577 26//47 1175//1432 +f 856//375 2375//1499 2374//1500 +f 1840//1501 1331//847 1672//1379 +f 1497//79 1163//814 1397//763 +f 1574//1502 1708//1503 1967//1504 +f 927//1451 929//1450 930//1505 +f 860//1506 927//1451 930//1505 +f 232//676 565//622 574//1158 +f 847//1103 1238//1491 857//1108 +f 802//432 858//217 803//123 +f 644//1251 859//1507 1847//1508 +f 926//1476 860//1506 861//1509 +f 862//216 35//122 1634//228 +f 806//139 1134//285 1646//1449 +f 939//1445 870//1510 1763//1446 +f 922//995 864//1496 863//1511 +f 864//1496 939//1445 2156//1512 +f 823//578 855//577 1175//1432 +f 1673//1320 910//1367 2096//239 +f 2011//1513 848//1211 770//833 +f 865//82 825//1389 2568//1514 +f 814//695 866//1426 2356//1210 +f 867//808 868//1393 180//576 +f 41//196 932//240 869//229 +f 1184//1515 1104//1516 2569//1517 +f 1658//192 1545//338 869//229 +f 1111//634 1541//1359 918//313 +f 926//1476 861//1509 1762//1518 +f 795//1102 2366//1519 847//1103 +f 863//1511 864//1496 2156//1512 +f 2315//1520 2307//1490 2244//1521 +f 482//999 870//1510 891//1000 +f 871//1244 891//1000 852//1495 +f 1336//1522 1505//283 1372//1523 +f 806//139 23//6 1134//285 +f 1440//1524 1514//853 834//668 +f 863//1511 2156//1512 872//996 +f 604//512 225//553 209//625 +f 1836//1159 1755//698 873//650 +f 1503//203 1440//1524 834//668 +f 868//1393 820//1395 180//576 +f 825//1389 874//1457 2568//1514 +f 2405//1525 2058//1526 2570//1527 +f 1254//813 1350//1429 1397//763 +f 482//999 875//1475 870//1510 +f 1879//1528 1878//1529 1763//1446 +f 1176//950 1959//1530 974//1531 +f 1641//1532 1337//1533 1409//1534 +f 876//618 200//617 915//1535 +f 2360//1059 512//1039 2344//1536 +f 770//833 848//1211 782//1377 +f 1477//416 243//697 968//696 +f 2161//1537 1281//1538 1026//1539 +f 877//1 916//3 878//312 +f 1702//637 845//1442 838//1473 +f 915//1535 200//617 916//3 +f 1238//1491 576//1540 857//1108 +f 879//1541 880//1542 1958//1543 +f 1701//1544 833//1469 1621//1545 +f 1878//1529 2157//1447 1763//1446 +f 1583//1467 833//1469 881//191 +f 882//65 506//64 1378//1327 +f 2309//1546 697//116 2299//1318 +f 944//1191 945//1547 642//1249 +f 1911//1548 1649//206 883//1549 +f 1670//1461 884//1550 1346//1462 +f 2405//1525 1459//1551 2058//1526 +f 927//1451 860//1506 926//1476 +f 2438//1552 2363//1241 2247//1353 +f 842//1472 841//1416 836//1471 +f 1683//1553 1359//1477 1682//1479 +f 2149//1554 2199//1555 367//860 +f 1238//1491 885//1556 576//1540 +f 969//1084 1049//626 1098//1288 +f 1670//1461 1575//1557 884//1550 +f 942//1558 25//120 913//1413 +f 1113//400 834//668 1513//1470 +f 872//996 2156//1512 895//1323 +f 1504//1559 889//1560 1505//283 +f 860//1506 930//1505 956//1561 +f 930//1505 740//1355 917//380 +f 886//693 1118//326 242//657 +f 1548//1428 840//1480 836//1471 +f 1405//862 2149//1554 367//860 +f 482//999 481//998 1682//1479 +f 1110//694 486//1006 887//1562 +f 898//985 827//1458 2278//190 +f 833//1469 888//1018 881//191 +f 860//1506 956//1561 861//1509 +f 1524//1563 1812//1564 1813//1565 +f 889//1560 1503//203 890//202 +f 890//202 1372//1523 1505//283 +f 824//1243 891//1000 871//1244 +f 849//280 898//985 904//948 +f 890//202 1505//283 889//1560 +f 65//286 907//5 905//1455 +f 1925//1437 2101//1566 817//1433 +f 892//1567 1856//1568 1756//1569 +f 482//999 1682//1479 953//1570 +f 78//334 970//246 736//259 +f 231//674 913//1413 921//319 +f 893//899 832//1466 900//1452 +f 900//1452 1702//637 838//1473 +f 627//1236 853//1497 439//616 +f 439//616 1334//1571 372//871 +f 942//1558 989//48 2748//50 +f 1334//1571 1329//98 372//871 +f 724//1340 738//1319 772//328 +f 894//245 1120//788 1100//1572 +f 121//461 659//776 184//427 +f 766//1364 969//1084 866//1426 +f 1963//1573 2101//1566 1925//1437 +f 2226//1574 2571//1575 2071//1576 +f 1945//1422 1325//1577 1492//1578 +f 832//1466 1702//637 900//1452 +f 667//1285 895//1323 934//768 +f 896//1283 667//1285 934//768 +f 896//1283 934//768 2452//1162 +f 823//578 1458//483 1241//253 +f 897//682 1432//875 1139//1247 +f 898//985 2278//190 727//189 +f 2039//1175 1956//1378 899//1410 +f 870//1510 1762//1518 1763//1446 +f 908//1478 900//1452 927//1451 +f 901//1448 2484//1438 902//1579 +f 845//1442 903//368 740//1355 +f 849//280 904//948 78//334 +f 905//1455 842//1472 1659//1580 +f 906//1581 1844//878 2422//1582 +f 23//6 907//5 1134//285 +f 1682//1479 908//1478 953//1570 +f 893//899 900//1452 908//1478 +f 1499//872 909//633 371//870 +f 106//353 910//1367 940//681 +f 911//1583 912//1584 1460//457 +f 832//1466 1913//638 1702//637 +f 940//681 942//1558 2572//1585 +f 231//674 940//681 2572//1585 +f 1630//41 1658//192 1618//1586 +f 914//1434 1440//1524 1504//1559 +f 1//2 915//1535 916//3 +f 916//3 200//617 878//312 +f 1639//927 877//1 918//313 +f 922//995 863//1511 872//996 +f 930//1505 917//380 956//1561 +f 1712//277 1856//1568 811//1415 +f 973//792 1095//1336 1534//1043 +f 918//313 1541//1359 1639//927 +f 851//1360 827//1458 898//985 +f 667//1285 872//996 895//1323 +f 1931//1245 871//1244 852//1495 +f 868//1393 816//1392 919//1394 +f 554//1142 617//1144 920//1124 +f 1746//1388 231//674 921//319 +f 1931//1245 852//1495 922//995 +f 1853//1587 2422//1582 1844//878 +f 2287//815 1163//814 923//1396 +f 2101//1566 831//1284 817//1433 +f 852//1495 939//1445 864//1496 +f 181//581 182//583 924//664 +f 946//1588 925//1054 933//1337 +f 875//1475 926//1476 870//1510 +f 902//1579 2058//1526 2046//1589 +f 881//191 888//1018 2114//787 +f 953//1570 908//1478 927//1451 +f 950//1590 589//1196 928//1190 +f 929//1450 740//1355 930//1505 +f 931//1591 2201//1592 2221//1593 +f 932//240 839//137 1632//1474 +f 945//1547 933//1337 642//1249 +f 945//1547 946//1588 933//1337 +f 946//1588 631//421 925//1054 +f 1100//1572 737//258 894//245 +f 902//1579 2046//1589 901//1448 +f 1122//1594 1505//283 1336//1522 +f 1673//1320 701//1322 940//681 +f 2452//1162 934//768 935//731 +f 936//991 937//243 562//649 +f 2091//1595 938//1596 1726//1597 +f 852//1495 891//1000 939//1445 +f 861//1509 1695//1598 1762//1518 +f 701//1322 942//1558 940//681 +f 915//1535 1//2 941//1237 +f 701//1322 989//48 942//1558 +f 950//1590 1210//1230 589//1196 +f 2123//1487 943//1365 243//697 +f 1762//1518 1695//1598 1879//1528 +f 844//1488 767//627 943//1365 +f 870//1510 926//1476 1762//1518 +f 2101//1566 529//997 831//1284 +f 953//1570 927//1451 875//1475 +f 941//1237 1//2 802//432 +f 960//1599 944//1191 1095//1336 +f 960//1599 945//1547 944//1191 +f 960//1599 946//1588 945//1547 +f 981//560 631//421 946//1588 +f 2395//1600 829//659 947//1298 +f 1959//1530 963//1601 948//1602 +f 975//1603 951//1209 949//1604 +f 975//1603 950//1590 951//1209 +f 156//537 695//1062 978//1258 +f 952//215 553//1141 1303//213 +f 891//1000 870//1510 939//1445 +f 482//999 953//1570 875//1475 +f 802//432 110//70 941//1237 +f 954//1605 2294//1606 2300//1607 +f 110//70 1536//431 941//1237 +f 961//729 946//1588 960//1599 +f 962//728 981//560 946//1588 +f 950//1590 955//1350 1210//1230 +f 955//1350 681//1161 1210//1230 +f 956//1561 411//934 861//1509 +f 2294//1606 957//81 2300//1607 +f 949//1604 958//542 887//1562 +f 1664//27 182//583 2573//1608 +f 2294//1606 959//1454 957//81 +f 973//792 960//1599 1095//1336 +f 961//729 962//728 946//1588 +f 736//259 961//729 305//333 +f 2010//1609 46//223 964//1610 +f 963//1601 2010//1609 964//1610 +f 6//35 965//500 2259//1300 +f 210//628 966//1287 1049//626 +f 967//530 152//531 362//857 +f 672//1031 676//1293 972//1291 +f 2356//1210 2011//1513 968//696 +f 771//301 338//363 639//970 +f 969//1084 519//1083 2567//1435 +f 1167//318 84//351 1746//1388 +f 306//775 961//729 960//1599 +f 767//627 844//1488 210//628 +f 956//1561 917//380 411//934 +f 486//1006 975//1603 949//1604 +f 904//948 725//244 970//246 +f 2327//1045 2395//1600 2223//1611 +f 2223//1611 2395//1600 971//1292 +f 972//1291 976//498 673//580 +f 145//275 809//1411 2763//1352 +f 306//775 960//1599 973//792 +f 829//659 156//537 947//1298 +f 865//82 1065//1286 4//25 +f 878//312 1111//634 918//313 +f 1874//1612 2421//1613 2425//1614 +f 1959//1530 948//1602 974//1531 +f 657//968 1836//1159 545//1125 +f 486//1006 949//1604 887//1562 +f 713//658 2574//1615 975//1603 +f 950//1590 2574//1615 955//1350 +f 950//1590 928//1190 951//1209 +f 971//1292 978//1258 676//1293 +f 673//580 976//498 965//500 +f 1965//1616 529//997 2101//1566 +f 2326//274 829//659 2395//1600 +f 980//335 979//774 2554//1277 +f 977//1207 699//933 64//276 +f 828//119 992//1617 820//1395 +f 1008//823 154//529 1275//767 +f 2395//1600 947//1298 971//1292 +f 971//1292 947//1298 978//1258 +f 979//774 980//335 305//333 +f 172//566 1697//874 450//521 +f 983//1259 982//347 976//498 +f 868//1393 919//1394 820//1395 +f 486//1006 713//658 975//1603 +f 964//1610 46//223 1578//1618 +f 978//1258 983//1259 676//1293 +f 676//1293 976//498 972//1291 +f 132//499 2259//1300 965//500 +f 979//774 306//775 973//792 +f 305//333 961//729 306//775 +f 962//728 605//1213 981//560 +f 605//1213 1108//561 981//560 +f 695//1062 982//347 983//1259 +f 1110//694 887//1562 1083//403 +f 676//1293 983//1259 976//498 +f 1117//11 984//1619 358//12 +f 1043//1620 988//1621 1054//1321 +f 1117//11 1039//1309 1133//55 +f 985//60 1103//129 1714//1622 +f 1526//987 2115//1178 986//1169 +f 1555//1623 661//507 819//889 +f 1398//1624 1184//1515 2575//1625 +f 1021//23 1018//22 1210//1230 +f 1773//198 985//60 1714//1622 +f 1039//1309 2508//110 2575//1625 +f 1175//1432 1773//198 127//484 +f 214//611 238//669 2564//1368 +f 988//1621 989//48 1054//1321 +f 990//1070 509//1063 991//34 +f 988//1621 358//12 989//48 +f 992//1617 1044//45 820//1395 +f 1145//1626 993//1381 1170//1627 +f 994//783 997//1299 678//349 +f 347//830 1019//1140 995//1163 +f 997//1299 1000//1628 5//33 +f 996//1629 991//34 5//33 +f 1000//1628 996//1629 5//33 +f 996//1629 990//1070 991//34 +f 1090//1630 1115//106 1033//1631 +f 1821//1632 2576//1633 2577//1634 +f 351//176 2364//175 666//837 +f 994//783 1002//1295 997//1299 +f 745//412 2410//425 998//1279 +f 1072//1635 1064//1636 671//1290 +f 1044//45 1045//118 10//46 +f 1002//1295 1006//1637 997//1299 +f 1006//1637 999//1638 997//1299 +f 997//1299 999//1638 1000//1628 +f 999//1638 1004//1639 1000//1628 +f 1000//1628 1004//1639 996//1629 +f 2259//1300 997//1299 5//33 +f 109//429 1119//589 694//262 +f 1004//1639 1001//1640 996//1629 +f 1060//471 1023//130 1627//133 +f 1020//1641 2270//778 308//779 +f 996//1629 1001//1640 1008//823 +f 1511//1297 1006//1637 1002//1295 +f 1007//1642 999//1638 1006//1637 +f 999//1638 1003//1643 1004//1639 +f 1004//1639 1003//1643 1001//1640 +f 1033//1631 1059//586 186//587 +f 1005//1644 1007//1642 1006//1637 +f 1003//1643 999//1638 1007//1642 +f 1003//1643 1010//1645 1001//1640 +f 1001//1640 1009//534 1008//823 +f 30//39 1037//264 16//66 +f 1637//1358 1096//89 1627//133 +f 1010//1645 1009//534 1001//1640 +f 1533//1339 689//1266 1009//534 +f 1533//1339 1009//534 1010//1645 +f 1010//1645 1003//1643 1007//1642 +f 1017//791 1533//1339 1010//1645 +f 549//865 491//1023 1153//1329 +f 1018//22 622//1177 1210//1230 +f 1011//707 1036//100 1116//112 +f 1542//1492 854//1386 853//1497 +f 2193//1646 2557//1315 2578//1647 +f 2235//143 1012//142 2237//1380 +f 1013//1648 1007//1642 1005//1644 +f 1787//1278 1013//1648 1005//1644 +f 1013//1648 1010//1645 1007//1642 +f 1010//1645 1013//1648 1017//791 +f 40//138 249//31 1436//1333 +f 1014//747 2270//778 2269//746 +f 807//1401 2237//1380 788//4 +f 1015//108 1532//177 862//216 +f 1072//1635 671//1290 567//172 +f 1549//958 807//1401 471//96 +f 807//1401 788//4 471//96 +f 1016//1118 1561//1649 1736//1097 +f 665//306 664//308 1013//1648 +f 1013//1648 664//308 1017//791 +f 622//1177 1018//22 1019//1140 +f 1020//1641 1180//38 472//712 +f 1107//1650 1031//165 387//185 +f 1097//749 1031//165 1021//23 +f 567//172 1019//1140 1018//22 +f 819//889 383//609 136//231 +f 379//886 1076//1651 2579//1652 +f 1054//1321 1022//1303 1043//1620 +f 14//62 2580//1653 1166//59 +f 186//587 1024//162 1025//161 +f 2122//1464 1338//463 1835//522 +f 914//1434 360//851 1440//1524 +f 1026//1539 1124//282 1380//1654 +f 1027//164 1028//184 1029//186 +f 1034//1655 1096//89 2581//1656 +f 1034//1655 1030//90 1096//89 +f 1031//165 1107//1650 1106//1657 +f 1106//1657 1067//1658 1032//171 +f 1090//1630 1033//1631 1064//1636 +f 1034//1655 1112//708 1035//105 +f 1030//90 1034//1655 1035//105 +f 1112//708 1011//707 1035//105 +f 1092//1659 1093//1373 1078//706 +f 984//1619 24//49 989//48 +f 1032//171 1067//1658 1072//1635 +f 1011//707 1500//709 1036//100 +f 20//83 2518//370 1037//264 +f 1030//90 1115//106 1090//1630 +f 1774//1660 1053//1661 1038//1662 +f 1060//471 1627//133 1069//1663 +f 1039//1309 1040//1308 2582//1664 +f 1217//903 391//37 1455//1665 +f 198//84 20//83 1062//19 +f 1041//1666 1068//1667 1082//1668 +f 1042//1669 1117//11 1133//55 +f 1043//1620 359//850 988//1621 +f 1052//1670 1070//1671 1087//1672 +f 1072//1635 1067//1658 1064//1636 +f 992//1617 1126//56 2583//1673 +f 1126//56 2584//1674 2583//1673 +f 1158//1675 1045//118 1044//45 +f 1158//1675 1046//61 1045//118 +f 1046//61 13//58 1045//118 +f 1047//844 1092//1659 1102//1676 +f 1434//1677 1048//151 1498//150 +f 1053//1661 1076//1651 1038//1662 +f 767//627 1049//626 969//1084 +f 358//12 984//1619 989//48 +f 1309//1678 1050//17 897//682 +f 1201//469 2449//1679 1051//1680 +f 746//1357 1034//1655 2581//1656 +f 1165//1681 1395//1682 1398//1624 +f 1096//89 1089//91 1069//1663 +f 1052//1670 1076//1651 1053//1661 +f 1084//1683 1083//403 1061//402 +f 989//48 701//1322 1054//1321 +f 1055//148 1027//164 1029//186 +f 1087//1672 1084//1683 1092//1659 +f 1056//1684 1061//402 1057//1232 +f 2304//1328 491//1023 1058//1136 +f 1115//106 1059//586 1033//1631 +f 1060//471 1069//1663 1041//1666 +f 1165//1681 1168//159 2166//158 +f 706//849 405//665 707//971 +f 1061//402 101//404 157//543 +f 157//543 1057//1232 1061//402 +f 678//349 83//348 994//783 +f 808//1408 230//673 1071//329 +f 1064//1636 1066//1685 671//1290 +f 186//587 1025//161 543//225 +f 1062//19 1037//264 30//39 +f 1061//402 1056//1684 1084//1683 +f 1028//184 1063//1686 387//185 +f 1067//1658 1090//1630 1064//1636 +f 1065//1286 650//1265 649//26 +f 1696//1687 359//850 1043//1620 +f 1033//1631 186//587 1066//1685 +f 1105//1688 1090//1630 1067//1658 +f 1089//91 1068//1667 1069//1663 +f 1070//1671 1084//1683 1087//1672 +f 1071//329 230//673 810//1409 +f 1052//1670 1087//1672 100//371 +f 1714//1622 1060//471 1713//1689 +f 1082//1668 1107//1650 387//185 +f 1052//1670 100//371 1076//1651 +f 1029//186 680//149 1055//148 +f 1032//171 1072//1635 567//172 +f 1073//957 1164//1690 798//675 +f 1068//1667 1105//1688 1107//1650 +f 1046//61 1166//59 13//58 +f 1074//69 1525//1412 110//70 +f 100//371 1087//1672 1075//472 +f 1038//1662 1076//1651 379//886 +f 1077//503 1102//1676 1078//706 +f 1077//503 1078//706 266//705 +f 1115//106 1035//105 1116//112 +f 1029//186 1079//748 680//149 +f 1031//165 1032//171 1080//21 +f 1138//1691 17//73 1685//72 +f 1202//1692 1251//1693 2585//1694 +f 1081//1695 1041//1666 1082//1668 +f 1221//1314 2174//1696 1220//241 +f 1029//186 1097//749 1079//748 +f 1170//1627 1083//403 1084//1683 +f 1070//1671 1170//1627 1084//1683 +f 110//70 1487//1697 1535//430 +f 1085//113 1381//99 1024//162 +f 1086//629 284//575 332//684 +f 1075//472 1087//1672 1047//844 +f 1087//1672 1092//1659 1047//844 +f 1535//430 853//1497 627//1236 +f 1154//1698 543//225 48//226 +f 1081//1695 1082//1668 1305//1699 +f 1190//1700 1088//1701 1297//1702 +f 867//808 924//664 800//1391 +f 1084//1683 1056//1684 1093//1373 +f 1089//91 1030//90 1090//1630 +f 1038//1662 379//886 1147//1703 +f 1136//1482 1070//1671 1137//1704 +f 1089//91 1090//1630 1105//1688 +f 897//682 1139//1247 1441//1705 +f 1091//107 1071//329 1074//69 +f 1092//1659 1084//1683 1093//1373 +f 59//233 501//1034 71//305 +f 578//420 1121//1706 653//1183 +f 1932//1707 1094//1708 1425//1709 +f 1023//130 2580//1653 2585//1694 +f 1066//1685 186//587 1154//1698 +f 1154//1698 186//587 543//225 +f 1037//264 93//111 16//66 +f 1170//1627 993//1381 1083//403 +f 855//577 1044//45 26//47 +f 1095//1336 944//1191 586//1267 +f 2532//887 379//886 2579//1652 +f 1627//133 1096//89 1069//1663 +f 1066//1685 1154//1698 671//1290 +f 737//258 1101//1710 605//1213 +f 349//834 597//1201 350//836 +f 1029//186 387//185 1097//749 +f 1098//1288 355//846 969//1084 +f 1063//1686 1082//1668 387//185 +f 1099//1711 1451//1406 1294//1712 +f 1100//1572 1101//1710 737//258 +f 604//512 583//1132 711//453 +f 605//1213 1101//1710 1108//561 +f 1108//561 1109//1713 168//419 +f 1092//1659 1078//706 1102//1676 +f 1714//1622 1103//129 1060//471 +f 1407//1714 1419//1307 2569//1517 +f 1107//1650 1105//1688 1106//1657 +f 359//850 358//12 988//1621 +f 1068//1667 1089//91 1105//1688 +f 1047//844 1102//1676 1077//503 +f 1082//1668 1068//1667 1107//1650 +f 746//1357 1111//634 1034//1655 +f 1101//1710 1123//1715 1108//561 +f 1108//561 1123//1715 1109//1713 +f 993//1381 1110//694 1083//403 +f 1106//1657 1105//1688 1067//1658 +f 1499//872 1034//1655 1111//634 +f 1034//1655 1499//872 1112//708 +f 846//1489 440//752 278//753 +f 834//668 1113//400 1114//204 +f 1832//1483 1137//1704 1053//1661 +f 1137//1704 1052//1670 1053//1661 +f 1115//106 1116//112 1059//586 +f 1117//11 1042//1669 984//1619 +f 357//160 1168//159 987//10 +f 1064//1636 1033//1631 1066//1685 +f 773//327 1118//326 1119//589 +f 1121//1706 578//420 168//419 +f 45//220 1944//1716 1998//1717 +f 1053//1661 1774//1660 1832//1483 +f 1056//1684 1057//1232 1093//1373 +f 1057//1232 219//645 1093//1373 +f 1116//112 1085//113 1059//586 +f 350//836 1125//1369 348//835 +f 1305//1699 1082//1668 1063//1686 +f 1651//1718 1305//1699 1063//1686 +f 1132//1719 1100//1572 1120//788 +f 1142//1720 653//1183 1121//1706 +f 1143//1721 1142//1720 1121//1706 +f 1321//1722 1122//1594 1473//1723 +f 2144//227 35//122 222//124 +f 1969//1724 1815//1725 1957//1726 +f 1180//38 308//779 1125//1369 +f 1059//586 1085//113 1024//162 +f 1069//1663 1068//1667 1041//1666 +f 1101//1710 1128//1727 1123//1715 +f 1123//1715 1129//1728 1109//1713 +f 1109//1713 1129//1728 168//419 +f 1129//1728 1130//1729 168//419 +f 1130//1729 1121//1706 168//419 +f 1130//1729 1143//1721 1121//1706 +f 1281//1538 1124//282 1026//1539 +f 350//836 1821//1632 1125//1369 +f 1137//1704 1070//1671 1052//1670 +f 984//1619 1042//1669 24//49 +f 828//119 1126//56 992//1617 +f 1100//1572 1127//1730 1101//1710 +f 1060//471 1041//1666 1713//1689 +f 1127//1730 1128//1727 1101//1710 +f 1128//1727 1150//1731 1123//1715 +f 1123//1715 1150//1731 1129//1728 +f 1157//636 1046//61 1158//1675 +f 1152//1732 1130//1729 1129//1728 +f 9//43 1040//1308 32//140 +f 1281//1538 1139//1247 1124//282 +f 1155//1733 1131//1734 1127//1730 +f 1100//1572 2586//1735 1127//1730 +f 1127//1730 1150//1731 1128//1727 +f 1150//1731 1152//1732 1129//1728 +f 1132//1719 1155//1733 2586//1735 +f 1039//1309 2582//1664 1133//55 +f 1075//472 1047//844 124//13 +f 328//504 1077//503 266//705 +f 1134//285 1135//1736 1646//1449 +f 1152//1732 1143//1721 1130//1729 +f 1136//1482 1137//1704 1832//1483 +f 887//1562 958//542 101//404 +f 2514//337 1138//1691 2587//1737 +f 1139//1247 1479//1246 1124//282 +f 179//254 330//481 487//739 +f 2166//158 2377//1738 1140//1739 +f 1288//926 846//1489 1366//955 +f 1131//1734 1141//1740 1127//1730 +f 1127//1730 1141//1740 1150//1731 +f 2304//1328 1142//1720 1143//1721 +f 2234//547 489//1013 1144//1281 +f 1031//165 1106//1657 1032//171 +f 1151//1741 1143//1721 1152//1732 +f 1151//1741 2304//1328 1143//1721 +f 1145//1626 1146//1742 993//1381 +f 48//226 1537//201 2588//1743 +f 2261//1744 2287//815 923//1396 +f 963//1601 964//1610 948//1602 +f 1161//1745 2304//1328 1151//1741 +f 379//886 1183//336 1147//1703 +f 1651//1718 1063//1686 1028//184 +f 1480//1456 360//851 815//1431 +f 1148//488 1149//1746 378//103 +f 1141//1740 1159//1747 1150//1731 +f 1150//1731 1156//1748 1152//1732 +f 1160//1749 1151//1741 1152//1732 +f 1161//1745 1178//1750 2304//1328 +f 2304//1328 1178//1750 1153//1329 +f 1164//1690 1148//488 798//675 +f 1154//1698 48//226 995//1163 +f 1155//1733 1250//1751 1131//1734 +f 1131//1734 1250//1751 1141//1740 +f 1250//1751 1169//1752 1141//1740 +f 1150//1731 1159//1747 1156//1748 +f 1156//1748 1160//1749 1152//1732 +f 278//753 277//101 1149//1746 +f 1145//1626 1070//1671 1136//1482 +f 338//363 90//362 639//970 +f 79//7 1076//1651 100//371 +f 1148//488 1164//1690 1149//1746 +f 671//1290 1154//1698 995//1163 +f 1157//636 1158//1675 2584//1674 +f 1141//1740 1169//1752 1159//1747 +f 1160//1749 1161//1745 1151//1741 +f 1178//1750 1162//863 1153//1329 +f 923//1396 1163//814 1497//79 +f 1164//1690 1171//954 1149//1746 +f 1168//159 1165//1681 1398//1624 +f 1641//1532 1473//1723 1337//1533 +f 1046//61 14//62 1166//59 +f 867//808 2295//252 924//664 +f 626//631 1865//630 1167//318 +f 1156//1748 1185//1753 1160//1749 +f 22//95 23//6 806//139 +f 348//835 1014//747 349//834 +f 1168//159 1398//1624 987//10 +f 1432//875 1697//874 1480//1456 +f 862//216 1634//228 840//1480 +f 1169//1752 1181//374 1159//1747 +f 1172//1754 1178//1750 1161//1745 +f 1178//1750 1174//864 1162//863 +f 1070//1671 1145//1626 1170//1627 +f 1821//1632 2577//1634 1125//1369 +f 266//705 218//644 224//655 +f 1181//374 95//373 1159//1747 +f 1159//1747 95//373 1156//1748 +f 1156//1748 95//373 1185//1753 +f 1160//1749 1172//1754 1161//1745 +f 1171//954 846//1489 278//753 +f 1149//1746 1171//954 278//753 +f 1019//1140 564//1152 622//1177 +f 1250//1751 1189//1755 1169//1752 +f 1185//1753 1172//1754 1160//1749 +f 400//912 1178//1750 1172//1754 +f 1178//1750 1173//789 1174//864 +f 1174//864 1173//789 448//790 +f 4//25 1065//1286 649//26 +f 26//47 1773//198 1175//1432 +f 813//152 1048//151 77//197 +f 1176//950 974//1531 1482//861 +f 1930//1756 1016//1118 1177//1096 +f 95//373 395//825 1185//1753 +f 1178//1750 400//912 1173//789 +f 1366//955 1179//842 414//841 +f 1180//38 1020//1641 308//779 +f 1189//1755 1181//374 1169//1752 +f 1185//1753 410//929 1172//1754 +f 410//929 400//912 1172//1754 +f 1078//706 219//645 218//644 +f 1171//954 1366//955 846//1489 +f 2377//1738 2166//158 359//850 +f 379//886 1182//369 1183//336 +f 400//912 389//824 1173//789 +f 1241//253 474//485 1240//610 +f 631//421 981//560 168//419 +f 1398//1624 1104//1516 1184//1515 +f 877//1 1636//928 1188//1757 +f 395//825 410//929 1185//1753 +f 1083//403 887//1562 101//404 +f 1042//1669 1133//55 346//54 +f 248//620 229//667 253//711 +f 1518//1758 1655//1759 1483//1436 +f 874//1457 1186//30 651//193 +f 1187//401 2386//1760 1654//1021 +f 1648//218 877//1 1188//1757 +f 1710//873 1181//374 1189//1755 +f 6//35 991//34 509//1063 +f 1371//826 1370//1761 1239//848 +f 779//1371 44//219 1656//221 +f 804//1398 1190//1700 1298//1762 +f 3//15 1050//17 1190//1700 +f 1191//1763 1104//1516 1398//1624 +f 1513//1470 1226//1764 2491//1765 +f 1050//17 1309//1678 1190//1700 +f 804//1398 3//15 1190//1700 +f 2464//605 195//606 2442//1157 +f 1232//1766 1366//955 414//841 +f 1299//1767 1192//732 1279//1768 +f 1193//1769 319//795 1367//1770 +f 1368//786 288//757 1367//1770 +f 1274//1771 88//354 66//266 +f 1383//1430 2589//1772 1400//310 +f 438//940 1194//840 1179//842 +f 1699//1174 1924//1773 1195//1774 +f 2009//1261 1972//1775 1221//1314 +f 399//911 1288//926 1345//1776 +f 1242//1208 134//16 3//15 +f 1196//922 1197//952 466//944 +f 1280//1777 1237//1778 1219//780 +f 1215//1779 1369//817 310//772 +f 1198//1780 1973//1269 655//1270 +f 1219//780 1199//771 292//764 +f 1700//798 1314//1781 1302//770 +f 1213//1375 32//140 1419//1307 +f 1225//812 1200//1782 1314//1781 +f 1212//1783 1201//469 1051//1680 +f 32//140 1040//1308 1419//1307 +f 1950//458 1460//457 912//1584 +f 2234//547 666//837 2364//175 +f 1251//1693 1202//1692 1203//1374 +f 1215//1779 1234//1784 1369//817 +f 1761//492 1204//181 1760//1785 +f 45//220 2149//1554 1655//1759 +f 1086//629 437//949 798//675 +f 1205//1786 2493//1787 2590//1788 +f 1450//222 15//63 1207//1789 +f 383//609 474//485 136//231 +f 1208//603 1209//470 1201//469 +f 1344//1790 1244//896 399//911 +f 1804//293 1319//1791 76//267 +f 1229//920 397//908 1327//1792 +f 1883//505 2067//183 818//807 +f 1210//1230 681//1161 1021//23 +f 1279//1768 1192//732 1255//1793 +f 2130//1252 644//1251 1211//1794 +f 1212//1783 1208//603 1201//469 +f 32//140 1213//1375 2591//1795 +f 1214//1796 1234//1784 1215//1779 +f 1314//1781 1200//1782 1280//1777 +f 1216//1797 1231//1798 1217//903 +f 1277//1799 1237//1778 1280//1777 +f 1345//1776 1370//1761 1344//1790 +f 968//696 2011//1513 1478//647 +f 1251//1693 2592//1800 1218//1801 +f 1586//1802 1251//1693 1218//1801 +f 1301//155 1373//157 1262//1803 +f 1348//1804 1255//1793 1349//716 +f 1277//1799 1271//904 1235//891 +f 1219//780 1243//1805 1295//781 +f 1882//1806 1257//1807 1867//1808 +f 1220//241 2009//1261 1221//1314 +f 1314//1781 1280//1777 1219//780 +f 2140//1809 2129//1810 1256//1811 +f 1924//1773 1594//1812 1222//1813 +f 1223//810 365//859 1224//811 +f 1314//1781 1700//798 1225//812 +f 455//546 1230//545 1229//920 +f 1370//1761 1233//897 1239//848 +f 804//1398 1242//1208 3//15 +f 1513//1470 1388//852 1311//1814 +f 1513//1470 1311//1814 1226//1764 +f 1227//1815 2491//1765 1226//1764 +f 1311//1814 1227//1815 1226//1764 +f 1267//1263 2364//175 1307//1816 +f 1228//1397 1242//1208 804//1398 +f 1214//1796 1244//896 1344//1790 +f 1212//1783 1310//1817 1480//1456 +f 1229//920 1230//545 1196//922 +f 2593//1818 1231//1798 2537//963 +f 1229//920 1196//922 397//908 +f 1526//987 232//676 574//1158 +f 924//664 1335//794 800//1391 +f 1232//1766 414//841 1233//897 +f 1279//1768 1352//1819 1299//1767 +f 1674//238 1022//1303 1054//1321 +f 1232//1766 1233//897 1370//1761 +f 1698//604 1212//1783 1480//1456 +f 1344//1790 1370//1761 1234//1784 +f 1235//891 1236//890 1237//1778 +f 2315//1520 885//1556 1238//1491 +f 1233//897 368//866 1239//848 +f 1240//610 662//251 1241//253 +f 1370//1761 1369//817 1234//1784 +f 2460//1120 135//502 1228//1397 +f 562//649 658//832 873//650 +f 2449//1679 2429//1820 1311//1814 +f 1088//1701 1441//1705 1297//1702 +f 1228//1397 135//502 1242//1208 +f 1237//1778 1236//890 1243//1805 +f 1236//890 1244//896 1214//1796 +f 397//908 1277//1799 1276//1821 +f 1192//732 244//687 1349//716 +f 769//974 2402//1346 687//1304 +f 1388//852 1051//1680 1311//1814 +f 31//132 1586//1802 1626//1822 +f 86//355 88//354 1247//378 +f 1245//1823 1374//170 1246//1824 +f 1246//1824 542//169 1025//161 +f 103//376 1247//378 1248//377 +f 1249//1192 2021//582 1889//1193 +f 31//132 1023//130 1251//1693 +f 1155//1733 1666//1825 1250//1751 +f 780//1376 2592//1800 1203//1374 +f 1193//1769 287//733 1192//732 +f 1261//1826 1377//1827 1252//1828 +f 1236//890 388//892 1244//896 +f 1304//829 365//859 1223//810 +f 1253//268 76//267 1319//1791 +f 1431//683 1050//17 1263//951 +f 1163//814 1254//813 1397//763 +f 1279//1768 1255//1793 1348//1804 +f 1256//1811 2129//1810 1257//1807 +f 1441//1705 1258//1829 1297//1702 +f 392//885 1259//907 365//859 +f 2463//468 1209//470 1260//661 +f 1270//1830 1261//1826 1252//1828 +f 1219//780 1237//1778 1243//1805 +f 1273//1831 1301//155 1262//1803 +f 1273//1831 1272//1832 1377//1827 +f 1263//951 1697//874 1431//683 +f 397//908 1276//1821 1327//1792 +f 1264//1264 1267//1263 1347//986 +f 948//1602 1265//1833 974//1531 +f 2375//1499 1287//1834 1266//1835 +f 1229//920 1327//1792 1259//907 +f 1267//1263 1348//1804 1347//986 +f 1496//591 1617//1836 2131//1837 +f 2174//1696 1221//1314 1268//1316 +f 645//435 1921//1838 1269//1839 +f 1248//377 1247//378 1379//1840 +f 1270//1830 1252//1828 2291//1841 +f 397//908 1271//904 1277//1799 +f 1262//1803 1292//1842 1272//1832 +f 1273//1831 1262//1803 1272//1832 +f 1274//1771 1253//268 1313//1843 +f 990//1070 996//1629 1275//767 +f 1200//1782 1276//1821 1277//1799 +f 1278//174 320//796 1279//1768 +f 2087//1844 2017//1845 1361//1846 +f 1248//377 1379//1840 1287//1834 +f 1313//1843 1326//1847 1379//1840 +f 2291//1841 1252//1828 1382//1848 +f 1261//1826 1270//1830 2175//1849 +f 1650//167 1377//1827 1261//1826 +f 2463//468 2449//1679 1201//469 +f 2034//1850 2135//449 2097//1301 +f 2115//1178 2459//1851 2456//1170 +f 2204//1852 1605//1853 882//65 +f 2342//592 1496//591 2131//1837 +f 1286//1854 1357//1855 1496//591 +f 1200//1782 1277//1799 1280//1777 +f 1354//1856 2145//1857 1888//1858 +f 1262//1803 1245//1823 1363//1859 +f 1258//1829 1281//1538 2161//1537 +f 1808//1860 1783//1861 1282//1862 +f 2408//1863 1258//1829 2161//1537 +f 2034//1850 2097//1301 104//352 +f 1283//1344 1284//1343 793//1384 +f 1285//1864 1114//204 1187//401 +f 1606//1865 2145//1857 1636//928 +f 1306//1866 1286//1854 1496//591 +f 782//1377 554//1142 920//1124 +f 1248//377 1287//1834 2375//1499 +f 1377//1827 1272//1832 1252//1828 +f 1247//378 1274//1771 1313//1843 +f 450//521 1263//951 1050//17 +f 1345//1776 1288//926 1366//955 +f 1289//1867 1286//1854 1306//1866 +f 1289//1867 1300//1868 1286//1854 +f 1300//1868 1357//1855 1286//1854 +f 1347//986 1349//716 232//676 +f 1382//1848 1252//1828 1290//1869 +f 1300//1868 1473//1723 1641//1532 +f 45//220 1998//1717 2149//1554 +f 561//1154 2544//1155 220//648 +f 437//949 1086//629 332//684 +f 1650//167 1261//1826 1911//1548 +f 1291//1870 1518//1758 1643//1871 +f 1272//1832 1292//1842 1290//1869 +f 1262//1803 1363//1859 1292//1842 +f 784//1129 1293//1128 2356//1210 +f 1099//1711 1294//1712 1436//1333 +f 1257//1807 2129//1810 1866//1872 +f 1235//891 1237//1778 1277//1799 +f 1295//781 1215//1779 1199//771 +f 1296//1873 1297//1702 1258//1829 +f 1312//1874 1253//268 1319//1791 +f 2411//1875 1298//1762 1296//1873 +f 1299//1767 319//795 1193//1769 +f 1289//1867 1321//1722 1300//1868 +f 1321//1722 1473//1723 1300//1868 +f 1301//155 1273//1831 1377//1827 +f 1315//1876 1323//1877 1546//1334 +f 1546//1334 1323//1877 717//1332 +f 1308//1878 1436//1333 717//1332 +f 1308//1878 1099//1711 1436//1333 +f 1299//1767 1352//1819 319//795 +f 1302//770 1314//1781 292//764 +f 1262//1803 1374//170 1245//1823 +f 1994//214 1303//213 821//876 +f 1252//1828 1272//1832 1290//1869 +f 854//1386 1334//1571 439//616 +f 319//795 1304//829 1367//1770 +f 1306//1866 1322//1879 1289//1867 +f 1322//1879 1321//1722 1289//1867 +f 1349//716 1255//1793 1192//732 +f 1278//174 352//797 320//796 +f 1305//1699 1651//1718 1727//1880 +f 88//354 1274//1771 1247//378 +f 1586//1802 31//132 1251//1693 +f 1441//1705 1281//1538 1258//1829 +f 1330//1881 1322//1879 1306//1866 +f 1307//1816 1279//1768 1267//1263 +f 1374//170 542//169 1246//1824 +f 320//796 1352//1819 1279//1768 +f 943//1365 822//1427 243//697 +f 1323//1877 1308//1878 717//1332 +f 367//860 1959//1530 1176//950 +f 1190//1700 1309//1678 1088//1701 +f 1310//1817 1212//1783 1051//1680 +f 2429//1820 1227//1815 1311//1814 +f 1253//268 1312//1874 1313//1843 +f 1314//1781 1219//780 292//764 +f 310//772 1199//771 1215//1779 +f 779//1371 1291//1870 1643//1871 +f 959//1454 1340//1882 1315//1876 +f 1340//1882 1323//1877 1315//1876 +f 1446//1883 1099//1711 1308//1878 +f 1316//1884 1947//437 1317//439 +f 1223//810 1224//811 1318//785 +f 1319//1791 1804//293 1320//1885 +f 2330//1886 1321//1722 1322//1879 +f 1307//1816 2364//175 1278//174 +f 1323//1877 1324//1887 1308//1878 +f 1446//1883 1451//1406 1099//1711 +f 1214//1796 1215//1779 1295//781 +f 1347//986 1526//987 1325//1577 +f 2510//173 32//140 2591//1795 +f 883//1549 1650//167 1911//1548 +f 1278//174 1279//1768 1307//1816 +f 2009//1261 1984//1888 1972//1775 +f 1779//127 1969//1724 1808//1860 +f 1326//1847 1313//1843 1312//1874 +f 1278//174 351//176 352//797 +f 365//859 1259//907 1327//1792 +f 2594//1889 552//332 2548//1215 +f 2128//1890 792//1382 1902//1891 +f 1312//1874 1319//1791 1328//1892 +f 1328//1892 1319//1791 1320//1885 +f 1122//1594 1321//1722 2330//1886 +f 1243//1805 1214//1796 1295//781 +f 2201//1592 931//1591 2340//1893 +f 1284//1343 1978//1056 46//223 +f 2009//1261 1220//241 58//250 +f 1340//1882 959//1454 2294//1606 +f 1340//1882 1326//1847 2595//1894 +f 1323//1877 2595//1894 1324//1887 +f 365//859 1327//1792 1224//811 +f 951//1209 958//542 949//1604 +f 2005//1895 505//1057 1978//1056 +f 1189//1755 1250//1751 1709//1896 +f 1345//1776 1232//1766 1370//1761 +f 1356//1897 1329//98 1334//1571 +f 2407//1898 2330//1886 1330//1881 +f 1419//1307 2596//1899 1213//1375 +f 1337//1533 1372//1523 1409//1534 +f 2294//1606 2158//1900 1340//1882 +f 1324//1887 1328//1892 1308//1878 +f 1328//1892 1446//1883 1308//1878 +f 1328//1892 1341//1901 1446//1883 +f 1236//890 1214//1796 1243//1805 +f 1225//812 1276//1821 1200//1782 +f 1299//1767 1193//1769 1192//732 +f 15//63 882//65 1574//1502 +f 1837//1902 1822//1310 1331//847 +f 34//153 1301//155 1377//1827 +f 1114//204 1285//1864 1332//1903 +f 1333//1904 1245//1823 1246//1824 +f 1363//1859 1245//1823 1333//1904 +f 1365//1385 1334//1571 854//1386 +f 1365//1385 1356//1897 1334//1571 +f 1381//99 1329//98 1356//1897 +f 816//1392 800//1391 1335//794 +f 2407//1898 1360//1905 2330//1886 +f 2330//1886 1360//1905 1122//1594 +f 1336//1522 1372//1523 1337//1533 +f 1214//1796 1344//1790 1234//1784 +f 1338//463 1339//465 1389//474 +f 2158//1900 1362//1906 1340//1882 +f 1362//1906 1326//1847 1340//1882 +f 1341//1901 1509//1907 1446//1883 +f 890//202 1114//204 1332//1903 +f 1320//1885 1342//1908 1509//1907 +f 1085//113 1036//100 1381//99 +f 2203//1909 1923//1910 1806//1911 +f 2045//1912 1343//1913 1584//1914 +f 1190//1700 1297//1702 1296//1873 +f 1327//1792 1276//1821 1225//812 +f 1247//378 1313//1843 1379//1840 +f 1344//1790 399//911 1345//1776 +f 2294//1606 2310//1915 2158//1900 +f 1852//1916 1875//1917 2425//1614 +f 1450//222 506//64 15//63 +f 1743//1460 1346//1462 2077//1918 +f 1347//986 1348//1804 1349//716 +f 1376//1919 1350//1429 1254//813 +f 505//1057 1351//1920 1930//1756 +f 1224//811 1327//1792 1225//812 +f 1144//1281 666//837 2234//547 +f 1028//184 2597//1921 1651//1718 +f 320//796 319//795 1352//1819 +f 1332//1903 1409//1534 1372//1523 +f 1285//1864 1654//1021 1409//1534 +f 1332//1903 1285//1864 1409//1534 +f 1187//401 1654//1021 1285//1864 +f 2057//1922 2181//1923 2180//1924 +f 1326//1847 1312//1874 1324//1887 +f 1324//1887 1312//1874 1328//1892 +f 1353//405 1354//1856 1886//1925 +f 2096//239 910//1367 105//418 +f 1376//1919 1383//1430 1350//1429 +f 2450//1926 1355//1927 902//1579 +f 1363//1859 1365//1385 1364//1387 +f 1333//1904 1356//1897 1365//1385 +f 1641//1532 1357//1855 1300//1868 +f 1358//900 908//1478 1359//1477 +f 2407//1898 2146//284 1360//1905 +f 2146//284 1122//1594 1360//1905 +f 1361//1846 2017//1845 1849//1928 +f 1266//1835 1287//1834 2158//1900 +f 2158//1900 1287//1834 1362//1906 +f 2287//815 1382//1848 1254//813 +f 1254//813 1382//1848 1376//1919 +f 1363//1859 1364//1387 2589//1772 +f 1333//1904 1365//1385 1363//1859 +f 1356//1897 1246//1824 1381//99 +f 1345//1776 1366//955 1232//1766 +f 1367//1770 1304//829 1368//786 +f 287//733 1367//1770 288//757 +f 1028//184 2598//1929 2597//1921 +f 1369//817 1370//1761 1371//826 +f 2313//1930 1649//206 1911//1548 +f 1368//786 1304//829 1223//810 +f 625//29 1167//318 826//317 +f 890//202 1332//1903 1372//1523 +f 1262//1803 1373//157 1374//170 +f 1809//1931 1375//805 1751//804 +f 1328//1892 1320//1885 1341//1901 +f 1341//1901 1320//1885 1509//1907 +f 2275//1932 1382//1848 2287//815 +f 1290//1869 1383//1430 1376//1919 +f 1246//1824 1356//1897 1333//1904 +f 1664//27 625//29 826//317 +f 34//153 1377//1827 1650//167 +f 1231//1798 2598//1929 2599//1933 +f 1058//1136 653//1183 1142//1720 +f 1378//1327 505//1057 1736//1097 +f 1291//1870 1655//1759 1518//1758 +f 1450//222 1578//1618 46//223 +f 2196//1934 2057//1922 1094//1708 +f 1287//1834 1379//1840 1362//1906 +f 1362//1906 1379//1840 1326//1847 +f 2156//1512 1903//1935 895//1323 +f 1371//826 1239//848 337//799 +f 1267//1263 1279//1768 1348//1804 +f 1380//1654 1124//282 2146//284 +f 1180//38 1217//903 2593//1818 +f 1381//99 1246//1824 1025//161 +f 1382//1848 1290//1869 1376//1919 +f 1290//1869 1292//1842 1383//1430 +f 1292//1842 1363//1859 1383//1430 +f 2097//1301 1668//1936 52//237 +f 1758//1937 1512//1938 1689//1939 +f 1738//1940 1576//1941 1737//1942 +f 1022//1303 1669//1302 1898//1943 +f 1463//1944 2078//1945 1876//1946 +f 1384//97 1795//314 1662//1484 +f 80//125 1461//1947 1805//1485 +f 1824//1948 1420//1949 1750//1950 +f 1649//206 1385//235 62//224 +f 1386//1296 1717//1153 1562//1951 +f 1775//128 1690//1952 1387//1440 +f 1521//1953 1559//1954 1783//1861 +f 1197//952 1196//922 1230//545 +f 360//851 1310//1817 1388//852 +f 115//1955 1394//1956 2521//450 +f 1410//1957 1977//1173 2522//475 +f 2166//158 1140//1739 2167//1958 +f 2321//448 1391//1959 2167//1958 +f 1390//1218 2171//1960 2147//1961 +f 1920//434 299//436 934//768 +f 2321//448 1394//1956 1391//1959 +f 1395//1682 1165//1681 2167//1958 +f 1392//1962 2132//1963 128//490 +f 1391//1959 1396//1964 2167//1958 +f 1392//1962 1393//1965 2600//1966 +f 2132//1963 1392//1962 115//1955 +f 115//1955 2600//1966 1394//1956 +f 1399//1967 1395//1682 2167//1958 +f 1396//1964 1399//1967 2167//1958 +f 1394//1956 1402//1968 2601//1969 +f 1391//1959 2601//1969 1396//1964 +f 1397//763 1350//1429 73//309 +f 1411//1970 1392//1962 1401//1971 +f 1399//1967 1191//1763 1395//1682 +f 1398//1624 1395//1682 1191//1763 +f 1392//1962 1411//1970 1393//1965 +f 1393//1965 1404//1972 2602//1973 +f 1394//1956 2602//1973 1402//1968 +f 2176//88 1517//1974 21//86 +f 1396//1964 1403//1975 1399//1967 +f 1399//1967 1403//1975 1191//1763 +f 1403//1975 1408//1976 1191//1763 +f 1411//1970 1444//1977 2603//1978 +f 1402//1968 1403//1975 1396//1964 +f 1400//310 1625//1493 1486//1414 +f 1411//1970 1401//1971 1413//762 +f 1406//1979 1408//1976 1403//1975 +f 1402//1968 1406//1979 1403//1975 +f 1315//1876 1546//1334 825//1389 +f 911//1583 1411//1970 1413//762 +f 1393//1965 2603//1978 2604//1980 +f 1393//1965 2604//1980 1404//1972 +f 1483//1436 1655//1759 1405//862 +f 1404//1972 1406//1979 1402//1968 +f 1768//1981 1824//1948 1750//1950 +f 1088//1701 1309//1678 897//682 +f 467//761 912//1584 1413//762 +f 1407//1714 1104//1516 1408//1976 +f 1406//1979 1407//1714 1408//1976 +f 1653//1020 1409//1534 1654//1021 +f 1554//1982 1759//1983 1824//1948 +f 1579//1984 1410//1957 1952//1985 +f 941//1237 876//618 915//1535 +f 2220//1986 912//1584 467//761 +f 1471//1987 2605//1988 911//1583 +f 1471//1987 1444//1977 2605//1988 +f 1539//1989 1412//1990 1764//1991 +f 2241//1992 2243//1993 2232//1994 +f 912//1584 911//1583 1413//762 +f 2250//1995 2476//1996 2324//1997 +f 1737//1942 1576//1941 1744//1998 +f 2376//1999 2077//1918 1346//1462 +f 1430//2000 1418//2001 2180//1924 +f 1418//2001 1423//2002 2057//1922 +f 1423//2002 1414//2003 2057//1922 +f 1414//2003 1425//1709 2057//1922 +f 1460//457 1471//1987 911//1583 +f 1406//1979 1426//2004 1407//1714 +f 1415//1494 1416//2005 1816//2006 +f 1430//2000 1417//2007 1418//2001 +f 1418//2001 1443//2008 1423//2002 +f 1884//2009 1932//1707 1885//2010 +f 1424//2011 1425//1709 1414//2003 +f 1472//2012 2606//2013 2607//2014 +f 1437//2015 1472//2012 2607//2014 +f 1426//2004 1419//1307 1407//1714 +f 1759//1983 1823//2016 1420//1949 +f 1428//2017 1502//2018 2032//2019 +f 766//1364 767//627 969//1084 +f 1421//2020 1443//2008 1418//2001 +f 1417//2007 1421//2020 1418//2001 +f 1443//2008 1422//2021 1423//2002 +f 1422//2021 1449//2022 1414//2003 +f 1423//2002 1422//2021 1414//2003 +f 1207//1789 1885//2010 1425//1709 +f 1424//2011 1207//1789 1425//1709 +f 1426//2004 1427//2023 1419//1307 +f 1428//2017 1435//126 1502//2018 +f 1768//1981 1438//803 1429//1486 +f 2171//1960 1439//2024 1430//2000 +f 1422//2021 1454//2025 1449//2022 +f 1449//2022 1424//2011 1414//2003 +f 350//836 597//1201 1822//1310 +f 1472//2012 1426//2004 2606//2013 +f 897//682 1431//683 1432//875 +f 1433//78 1434//1677 2240//1231 +f 1502//2018 1435//126 1387//1440 +f 1824//1948 1759//1983 1420//1949 +f 1439//2024 1421//2020 1430//2000 +f 1430//2000 1421//2020 1417//2007 +f 1207//1789 1424//2011 1449//2022 +f 1546//1334 1436//1333 249//31 +f 1467//2026 1472//2012 2608//2027 +f 1444//1977 1467//2026 2608//2027 +f 1768//1981 1750//1950 1438//803 +f 1390//1218 2609//2028 2610//2029 +f 2171//1960 1390//1218 2610//2029 +f 1421//2020 1453//2030 1443//2008 +f 1207//1789 1967//1504 1885//2010 +f 1472//2012 1456//2031 1426//2004 +f 1426//2004 1456//2031 1427//2023 +f 1440//1524 360//851 1514//853 +f 1441//1705 1139//1247 1281//1538 +f 1486//1414 1542//1492 1535//430 +f 277//101 378//103 1149//1746 +f 67//294 2341//1338 1804//293 +f 1502//2018 1442//1439 2044//2032 +f 1465//2033 1448//2034 2609//2028 +f 1439//2024 1468//2035 1421//2020 +f 1443//2008 1453//2030 1422//2021 +f 1471//1987 1467//2026 1444//1977 +f 1315//1876 825//1389 959//1454 +f 402//877 1233//897 414//841 +f 1445//2036 906//1581 2094//2037 +f 1445//2036 376//879 2103//2038 +f 1445//2036 1792//2039 376//879 +f 1792//2039 1791//2040 376//879 +f 1446//1883 1509//1907 843//1407 +f 1465//2033 1447//2041 1448//2034 +f 1439//2024 1448//2034 1468//2035 +f 1454//2025 1578//1618 1449//2022 +f 1450//222 1207//1789 1449//2022 +f 1578//1618 1450//222 1449//2022 +f 1451//1406 1446//1883 843//1407 +f 1509//1907 1452//2042 843//1407 +f 1427//2023 780//1376 2596//1899 +f 1452//2042 805//1400 843//1407 +f 1468//2035 1453//2030 1421//2020 +f 1453//2030 1265//1833 1422//2021 +f 1422//2021 948//1602 1454//2025 +f 948//1602 1578//1618 1454//2025 +f 1829//2043 1999//2044 1455//1665 +f 1472//2012 1475//2045 1456//2031 +f 1456//2031 780//1376 1427//2023 +f 1711//2046 1844//878 1732//880 +f 1390//1218 1457//1217 1465//2033 +f 1422//2021 1265//1833 948//1602 +f 1175//1432 127//484 1458//483 +f 2405//1525 2047//2047 1459//1551 +f 2478//2048 2496//2049 2611//2050 +f 2612//2051 1550//2052 2613//2053 +f 2613//2053 1550//2052 2614//2054 +f 1461//1947 1720//2055 1462//2056 +f 1923//1910 2078//1945 1463//1944 +f 1464//2057 1792//2039 1445//2036 +f 1464//2057 1476//541 1792//2039 +f 1517//1974 1457//1217 1608//2058 +f 1465//2033 1457//1217 1447//2041 +f 1447//2041 1468//2035 1448//2034 +f 1453//2030 1469//2059 1265//1833 +f 1819//2060 729//1335 1721//1351 +f 19//80 1048//151 1434//1677 +f 19//80 808//1408 1048//151 +f 1889//1193 1466//2061 1950//458 +f 1950//458 1466//2061 2612//2051 +f 1550//2052 1495//2062 2614//2054 +f 1495//2062 2615//2063 1460//457 +f 1471//1987 2616//2064 1467//2026 +f 2094//2037 1464//2057 1445//2036 +f 1468//2035 1469//2059 1453//2030 +f 2617//2065 1471//1987 2615//2063 +f 1471//1987 2617//2065 2616//2064 +f 1467//2026 1475//2045 1472//2012 +f 1841//2066 2162//2067 2195//2068 +f 1473//1723 1336//1522 1337//1533 +f 2094//2037 1488//2069 1464//2057 +f 2405//1525 2618//2070 2619//2071 +f 21//86 1517//1974 1608//2058 +f 1468//2035 1484//1122 1469//2059 +f 1265//1833 1469//2059 974//1531 +f 1433//78 19//80 1434//1677 +f 1508//2072 1475//2045 1467//2026 +f 1475//2045 1507//2073 1456//2031 +f 1820//2074 1840//1501 2195//2068 +f 2193//1646 1820//2074 2195//2068 +f 1481//2075 1476//541 1464//2057 +f 1501//2076 1457//1217 1517//1974 +f 1457//1217 1510//2077 1447//2041 +f 11//51 2095//2078 1835//522 +f 1477//416 968//696 1478//647 +f 1479//1246 1480//1456 815//1431 +f 360//851 1480//1456 1310//1817 +f 1515//2079 1218//1801 2620//2080 +f 1507//2073 1515//2079 1456//2031 +f 1456//2031 2620//2080 780//1376 +f 1481//2075 1464//2057 1488//2069 +f 1481//2075 1731//539 1476//541 +f 1457//1217 1501//2076 1510//2077 +f 1484//1122 1482//861 1469//2059 +f 1508//2072 1507//2073 1475//2045 +f 230//673 73//309 1528//311 +f 1510//2077 1483//1436 1447//2041 +f 1447//2041 1483//1436 1468//2035 +f 1468//2035 1483//1436 1484//1122 +f 1544//2081 1802//2082 1559//1954 +f 882//65 1378//1327 1485//2083 +f 1528//311 1486//1414 1487//1697 +f 1487//1697 1486//1414 1535//430 +f 810//1409 230//673 1525//1412 +f 1466//2061 2186//2084 1550//2052 +f 1051//1680 1388//852 1310//1817 +f 1432//875 1480//1456 1479//1246 +f 2179//2085 1481//2075 1488//2069 +f 1501//2076 1519//2086 1510//2077 +f 1489//2087 1490//2088 1491//2089 +f 1492//1578 986//1169 1493//2090 +f 1088//1701 897//682 1441//1705 +f 1599//2091 1872//2092 1573//2093 +f 1452//2042 1494//2094 805//1400 +f 1506//2095 1495//2062 1550//2052 +f 1495//2062 1506//2095 1470//2096 +f 1496//591 1357//1855 1617//1836 +f 1497//79 73//309 230//673 +f 2240//1231 1434//1677 1498//150 +f 1987//1007 1527//2097 1488//2069 +f 1527//2097 2179//2085 1488//2069 +f 2179//2085 1731//539 1481//2075 +f 1499//872 372//871 1500//709 +f 1516//2098 1501//2076 1517//1974 +f 1516//2098 1519//2086 1501//2076 +f 2051//2099 2032//2019 1502//2018 +f 1786//2100 1563//211 1800//2101 +f 815//1431 914//1434 1504//1559 +f 1504//1559 1440//1524 1503//203 +f 1504//1559 1503//203 889//1560 +f 815//1431 1504//1559 1505//283 +f 815//1431 1505//283 1124//282 +f 1506//2095 1507//2073 1508//2072 +f 1470//2096 1506//2095 1508//2072 +f 1509//1907 1342//1908 1452//2042 +f 327//14 124//13 328//504 +f 439//616 372//871 371//870 +f 2578//1647 1557//2102 2621//2103 +f 1519//2086 1483//1436 1510//2077 +f 1490//2088 1622//2104 1520//2105 +f 1006//1637 1511//1297 1005//1644 +f 1491//2089 1490//2088 1512//1938 +f 1388//852 1513//1470 1514//853 +f 1499//872 1111//634 909//633 +f 1835//522 1389//474 125//473 +f 1506//2095 1551//2106 1507//2073 +f 1507//2073 1551//2106 1515//2079 +f 19//80 230//673 808//1408 +f 876//618 627//1236 439//616 +f 2176//88 1516//2098 1517//1974 +f 1643//1871 1518//1758 1516//2098 +f 1519//2086 1518//1758 1483//1436 +f 1520//2105 1521//1953 1512//1938 +f 1522//2107 1970//2108 1523//2109 +f 2209//2110 1325//1577 2622//2111 +f 1708//1503 1524//1563 1772//2112 +f 371//870 909//633 200//617 +f 1//2 858//217 802//432 +f 1540//1276 2186//2084 2185//1370 +f 1525//1412 1528//311 110//70 +f 986//1169 1325//1577 1526//987 +f 1640//2113 1821//1632 2623//2114 +f 2178//1273 2179//2085 1527//2097 +f 2179//2085 899//1410 1731//539 +f 836//1471 840//1480 1634//228 +f 110//70 1528//311 1487//1697 +f 1604//2115 1720//2055 1461//1947 +f 1529//2116 2249//2117 1530//2118 +f 1531//71 1532//177 1015//108 +f 2186//2084 1556//2119 1550//2052 +f 1218//1801 1515//2079 1551//2106 +f 1533//1339 1534//1043 689//1266 +f 1542//1492 853//1497 1535//430 +f 1536//431 627//1236 941//1237 +f 63//273 995//1163 2588//1743 +f 1336//1522 1473//1723 1122//1594 +f 1027//164 2525//621 2599//1933 +f 966//1287 210//628 1841//2066 +f 1543//2120 1568//2121 1538//2122 +f 1538//2122 1568//2121 1845//2123 +f 2224//1131 104//352 84//351 +f 1560//2124 1412//1990 1539//1989 +f 1555//1623 2186//2084 1540//1276 +f 1551//2106 1565//2125 1218//1801 +f 1541//1359 1111//634 746//1357 +f 1367//1770 287//733 1193//1769 +f 1486//1414 1625//1493 1542//1492 +f 314//339 1604//2115 1461//1947 +f 1970//2108 2190//2126 1543//2120 +f 1845//2123 1547//2127 644//1251 +f 1622//2104 1621//1545 1544//2081 +f 1545//338 1186//30 250//32 +f 1550//2052 1564//2128 1506//2095 +f 1506//2095 1564//2128 1551//2106 +f 1186//30 1546//1334 249//31 +f 1498//150 813//152 2236//166 +f 1738//1940 1577//2129 1576//1941 +f 1581//2130 1568//2121 1543//2120 +f 1547//2127 859//1507 644//1251 +f 1038//1662 1734//2131 1838//2132 +f 1548//1428 77//197 1015//108 +f 1549//958 1451//1406 807//1401 +f 1555//1623 1556//2119 2186//2084 +f 1564//2128 1550//2052 1556//2119 +f 1564//2128 1565//2125 1551//2106 +f 1640//2113 7//36 2576//1633 +f 1455//1665 2624//2133 1972//1775 +f 391//37 1640//2113 1557//2102 +f 1553//2134 1875//1917 1766//2135 +f 865//82 651//193 650//1265 +f 1436//1333 1552//1390 40//138 +f 1462//2056 1720//2055 1824//1948 +f 1842//2136 1660//2137 1692//2138 +f 1770//2139 1553//2134 2106//2140 +f 1582//2141 1845//2123 1568//2121 +f 1687//2142 1758//1937 1554//1982 +f 1555//1623 1910//2143 1556//2119 +f 1552//1390 1436//1333 1549//958 +f 391//37 1557//2102 2624//2133 +f 1565//2125 1586//1802 1218//1801 +f 1294//1712 1451//1406 1549//958 +f 1558//1468 1415//1494 2625//2144 +f 1691//2145 1686//2146 1692//2138 +f 1560//2124 1561//1649 1412//1990 +f 2190//2126 1581//2130 1543//2120 +f 1547//2127 1845//2123 1582//2141 +f 1562//1951 892//1567 1834//2147 +f 2590//1788 2626//2148 2627//2149 +f 1563//211 1570//2150 2112//212 +f 1564//2128 1585//2151 1565//2125 +f 1436//1333 1294//1712 1549//958 +f 837//144 2236//166 841//1416 +f 1812//1564 1665//1441 1726//1597 +f 646//346 2362//1268 2233//1166 +f 1560//2124 1723//2152 1566//2153 +f 2079//2154 1581//2130 2190//2126 +f 1581//2130 1567//2155 1568//2121 +f 1568//2121 1567//2155 1582//2141 +f 1569//2156 2750//2157 2627//2149 +f 1715//2158 1723//2152 1716//2159 +f 1745//2160 1744//1998 1716//2159 +f 884//1550 1575//1557 2165//1081 +f 1563//211 938//1596 1570//2150 +f 1805//1485 1768//1981 1429//1486 +f 1823//2016 1759//1983 1571//2161 +f 1670//1461 1812//1564 1524//1563 +f 2146//284 1505//283 1122//1594 +f 1738//1940 1876//1946 1577//2129 +f 1594//1812 1572//2162 1222//1813 +f 1222//1813 1572//2162 1895//2163 +f 1573//2093 1598//2164 1599//2091 +f 2079//2154 1580//2165 1581//2130 +f 1574//1502 1575//1557 1708//1503 +f 1576//1941 1577//2129 1676//2166 +f 1438//803 1750//1950 1751//804 +f 1910//2143 819//889 1584//1914 +f 1910//2143 1589//2167 1556//2119 +f 1585//2151 1564//2128 1556//2119 +f 948//1602 964//1610 1578//1618 +f 651//193 1186//30 1545//338 +f 1410//1957 1579//1984 1593//2168 +f 1599//2091 1600//2169 2079//2154 +f 1613//2170 1580//2165 2079//2154 +f 1580//2165 1567//2155 1581//2130 +f 1602//2171 1582//2141 1567//2155 +f 1582//2141 1601//2172 1547//2127 +f 1601//2172 859//1507 1547//2127 +f 1603//2173 1588//2174 859//1507 +f 881//191 2278//190 1583//1467 +f 1766//2135 1875//1917 1852//1916 +f 1670//1461 1442//1439 1812//1564 +f 1910//2143 1584//1914 1589//2167 +f 1585//2151 1626//1822 1586//1802 +f 1565//2125 1585//2151 1586//1802 +f 1216//1797 1217//903 1455//1665 +f 1652//2175 1593//2168 1579//1984 +f 1429//1486 1737//1942 1663//2176 +f 1597//2177 1596//2178 1573//2093 +f 1573//2093 1596//2178 1598//2164 +f 2079//2154 1600//2169 1613//2170 +f 1580//2165 1602//2171 1567//2155 +f 1602//2171 1601//2172 1582//2141 +f 1587//2179 859//1507 1601//2172 +f 1620//2180 1588//2174 1603//2173 +f 2204//1852 2165//1081 1605//1853 +f 1575//1557 1574//1502 1605//1853 +f 1442//1439 1670//1461 2044//2032 +f 1343//1913 1589//2167 1584//1914 +f 1589//2167 1590//2181 1556//2119 +f 1556//2119 1590//2181 1585//2151 +f 1216//1797 1455//1665 1999//2044 +f 1591//2182 1216//1797 1999//2044 +f 1592//2183 1579//1984 1952//1985 +f 1593//2168 1594//1812 1861//2184 +f 1572//2162 2337//2185 1595//2186 +f 1316//1884 1596//2178 1597//2177 +f 1598//2164 1628//2187 1599//2091 +f 1599//2091 1628//2187 1600//2169 +f 1613//2170 1645//2188 1580//2165 +f 1580//2165 1645//2188 1602//2171 +f 1610//2189 1601//2172 1602//2171 +f 1603//2173 859//1507 1587//2179 +f 1710//873 1604//2115 314//339 +f 1575//1557 1605//1853 2165//1081 +f 1623//2190 1343//1913 1606//1865 +f 1623//2190 1589//2167 1343//1913 +f 1626//1822 1585//2151 1590//2181 +f 2368//438 1595//2186 2337//2185 +f 635//845 1331//847 1822//1310 +f 1120//788 2113//1017 1607//1016 +f 1608//2058 1457//1217 729//1335 +f 2191//2191 1569//2156 1609//2192 +f 1645//2188 1631//2193 1602//2171 +f 1619//2194 1610//2189 1602//2171 +f 1601//2172 1135//1736 1587//2179 +f 1135//1736 1633//287 1587//2179 +f 1633//287 1603//2173 1587//2179 +f 1789//2195 1663//2176 1744//1998 +f 2560//1326 1705//1325 2628//2196 +f 1636//928 1623//2190 1606//1865 +f 1623//2190 1590//2181 1589//2167 +f 1591//2182 1999//2044 2629//2197 +f 1611//2198 1952//1985 1612//76 +f 1611//2198 1642//2199 1952//1985 +f 1642//2199 1592//2183 1952//1985 +f 1579//1984 1592//2183 1652//2175 +f 1593//2168 1572//2162 1594//1812 +f 1600//2169 1618//1586 1613//2170 +f 1610//2189 1135//1736 1601//2172 +f 1873//2200 1647//2201 1614//2202 +f 1647//2201 1635//2203 1614//2202 +f 1615//2204 1688//2205 1914//1424 +f 2145//1857 1606//1865 1888//1858 +f 1616//2206 1590//2181 1623//2190 +f 1727//1880 1591//2182 1905//2207 +f 1617//1836 1611//2198 1612//76 +f 1638//1022 1572//2162 1593//2168 +f 1628//2187 1644//2208 1600//2169 +f 1600//2169 1644//2208 1618//1586 +f 1613//2170 1618//1586 1645//2188 +f 1631//2193 1619//2194 1602//2171 +f 1620//2180 1659//1580 1881//407 +f 1873//2200 1881//407 1659//1580 +f 1873//2200 836//1471 1647//2201 +f 222//124 2145//1857 2144//227 +f 1703//2209 1621//1545 1622//2104 +f 1639//927 1616//2206 1623//2190 +f 1616//2206 1626//1822 1590//2181 +f 1718//2210 1591//2182 1727//1880 +f 1718//2210 2630//2211 1591//2182 +f 1718//2210 1624//2212 2630//2211 +f 1357//1855 1611//2198 1617//1836 +f 1625//1493 1364//1387 854//1386 +f 31//132 1626//1822 1627//133 +f 1357//1855 1642//2199 1611//2198 +f 1638//1022 2386//1760 1572//2162 +f 1572//2162 2386//1760 2337//2185 +f 1657//289 1629//2213 1628//2187 +f 1598//2164 1657//289 1628//2187 +f 1628//2187 1629//2213 1644//2208 +f 1644//2208 1630//41 1618//1586 +f 932//240 1619//2194 1631//2193 +f 1619//2194 1632//1474 1610//2189 +f 1646//1449 1135//1736 1610//2189 +f 1633//287 65//286 1603//2173 +f 65//286 1620//2180 1603//2173 +f 1634//228 1635//2203 1647//2201 +f 1634//228 2144//227 1635//2203 +f 222//124 1188//1757 2145//1857 +f 1188//1757 1636//928 2145//1857 +f 1636//928 1639//927 1623//2190 +f 1637//1358 1626//1822 1616//2206 +f 1653//1020 1593//2168 1652//2175 +f 1653//1020 1638//1022 1593//2168 +f 1619//2194 932//240 1632//1474 +f 65//286 1659//1580 1620//2180 +f 1639//927 1541//1359 1616//2206 +f 1541//1359 1637//1358 1616//2206 +f 1615//2204 1927//2214 1686//2146 +f 2149//1554 1405//862 1655//1759 +f 391//37 7//36 1640//2113 +f 1641//1532 1642//2199 1357//1855 +f 1641//1532 1592//2183 1642//2199 +f 1641//1532 1652//2175 1592//2183 +f 1643//1871 2177//87 779//1371 +f 1629//2213 1630//41 1644//2208 +f 1645//2188 869//229 1631//2193 +f 869//229 932//240 1631//2193 +f 1632//1474 354//843 1610//2189 +f 354//843 1646//1449 1610//2189 +f 1134//285 1633//287 1135//1736 +f 836//1471 1634//228 1647//2201 +f 1648//218 1188//1757 222//124 +f 1649//206 1650//167 883//1549 +f 230//673 1528//311 1525//1412 +f 1651//1718 1624//2212 1718//2210 +f 1400//310 1364//1387 1625//1493 +f 1409//1534 1652//2175 1641//1532 +f 1652//2175 1409//1534 1653//1020 +f 1654//1021 2386//1760 1638//1022 +f 45//220 1655//1759 1291//1870 +f 45//220 1291//1870 1656//221 +f 1656//221 1291//1870 779//1371 +f 1657//289 1598//2164 2320//290 +f 1618//1586 1658//192 1645//2188 +f 1645//2188 1658//192 869//229 +f 65//286 905//1455 1659//1580 +f 1659//1580 842//1472 1873//2200 +f 842//1472 836//1471 1873//2200 +f 1690//1952 1660//2137 2164//2215 +f 1660//2137 1968//2216 2164//2215 +f 1490//2088 1661//2217 1622//2104 +f 1358//900 893//899 908//1478 +f 1282//1862 1686//2146 1691//2145 +f 1749//2218 1662//1484 1663//2176 +f 1022//1303 1696//1687 1043//1620 +f 1764//1991 2632//2219 2631//2220 +f 1560//2124 1566//2153 1736//1097 +f 182//583 1664//27 637//793 +f 1429//1486 1438//803 1375//805 +f 1812//1564 1442//1439 1665//1441 +f 1967//1504 1708//1503 1884//2009 +f 1155//1733 1489//2087 1666//1825 +f 1489//2087 1667//2221 1666//1825 +f 52//237 1668//1936 1669//1302 +f 1674//238 52//237 1669//1302 +f 21//86 1608//2058 1731//539 +f 1575//1557 1670//1461 1524//1563 +f 1808//1860 1282//1862 1691//2145 +f 1671//2222 1879//1528 1695//1598 +f 1331//847 355//846 1672//1379 +f 1673//1320 2096//239 1674//238 +f 1540//1276 181//581 662//251 +f 1666//1825 1667//2221 1675//2223 +f 1692//2138 1660//2137 1719//2224 +f 1688//2205 1615//2204 1282//1862 +f 2376//1999 1707//1080 1676//2166 +f 411//934 1747//381 1677//2225 +f 1678//2226 1679//2227 2266//2228 +f 1680//1459 1415//1494 2278//190 +f 1677//2225 1695//1598 411//934 +f 1416//2005 1680//1459 1796//1425 +f 1415//1494 1680//1459 1416//2005 +f 1681//2229 1529//2116 2633//2230 +f 1682//1479 481//998 1683//1553 +f 1521//1953 1771//2231 1512//1938 +f 1765//2232 1521//1953 2173//2233 +f 1764//1991 2634//2234 2632//2219 +f 1384//97 1662//1484 1685//72 +f 1675//2223 1687//2142 1720//2055 +f 1692//2138 1686//2146 1842//2136 +f 1622//2104 1544//2081 1521//1953 +f 1667//2221 1687//2142 1675//2223 +f 1155//1733 1661//2217 1489//2087 +f 1816//2006 1688//2205 1282//1862 +f 1521//1953 1783//1861 1957//1726 +f 1689//1939 1512//1938 1771//2231 +f 1665//1441 1690//1952 1726//1597 +f 1691//2145 1692//2138 1779//127 +f 1838//2132 1693//2235 1839//2236 +f 1677//2225 1694//2237 1695//1598 +f 1694//2237 1671//2222 1695//1598 +f 1898//1943 1696//1687 1022//1303 +f 833//1469 1558//1468 1621//1545 +f 729//1335 1778//540 1608//2058 +f 1697//874 1769//568 1698//604 +f 1778//540 1792//2039 1476//541 +f 2635//2238 2636//2239 2611//2050 +f 1687//2142 1667//2221 1491//2089 +f 1957//1726 1783//1861 1808//1860 +f 1621//1545 1558//1468 1802//2082 +f 1924//1773 1699//1174 1861//2184 +f 1700//798 1318//785 1224//811 +f 888//1018 1701//1544 1607//1016 +f 1783//1861 1816//2006 1282//1862 +f 1702//637 1907//639 1735//1444 +f 899//1410 1956//1378 2177//87 +f 1607//1016 1661//2217 1155//1733 +f 1738//1940 1463//1944 1876//1946 +f 1524//1563 1813//1565 1772//2112 +f 1923//1910 1754//2240 1806//1911 +f 1779//127 1692//2138 1719//2224 +f 1748//2241 1694//2237 1677//2225 +f 1795//314 1805//1485 1662//1484 +f 1694//2237 1757//2242 1671//2222 +f 1661//2217 1703//2209 1622//2104 +f 1665//1441 1387//1440 1690//1952 +f 2628//2196 1705//1325 2637//2243 +f 1661//2217 1490//2088 1489//2087 +f 1801//2244 1745//2160 1684//2245 +f 1676//2166 1707//1080 1723//2152 +f 971//1292 496//1032 2223//1611 +f 94//114 80//125 1795//314 +f 1575//1557 1524//1563 1708//1503 +f 1717//1153 560//782 811//1415 +f 1491//2089 1758//1937 1687//2142 +f 1521//1953 1544//2081 1559//1954 +f 1520//2105 1622//2104 1521//1953 +f 1747//381 1748//2241 1677//2225 +f 1709//1896 1720//2055 1710//873 +f 1711//2046 1766//2135 1852//1916 +f 1854//260 1856//1568 1712//277 +f 1041//1666 1081//1695 1713//1689 +f 1081//1695 1714//1622 1713//1689 +f 1754//2240 1923//1910 1463//1944 +f 1834//2147 1694//2237 1748//2241 +f 1744//1998 1715//2158 1716//2159 +f 1662//1484 1429//1486 1663//2176 +f 1386//1296 994//783 1717//1153 +f 357//160 359//850 2166//158 +f 1651//1718 1718//2210 1727//1880 +f 1725//2246 1714//1622 1081//1695 +f 1728//2247 1725//2246 1081//1695 +f 1725//2246 127//484 1714//1622 +f 1719//2224 1660//2137 1690//1952 +f 1687//2142 1824//1948 1720//2055 +f 1687//2142 1554//1982 1824//1948 +f 1704//2248 1706//2249 2638//2250 +f 2154//1453 1732//880 1721//1351 +f 1722//1272 11//51 1835//522 +f 1723//2152 517//1079 1566//2153 +f 1704//2248 1724//2251 2639//2252 +f 1375//805 1754//2240 1737//1942 +f 2215//489 1401//1971 128//490 +f 1081//1695 1305//1699 1728//2247 +f 1728//2247 1741//2253 1725//2246 +f 1725//2246 1741//2253 127//484 +f 1690//1952 2164//2215 1726//1597 +f 938//1596 1563//211 1786//2100 +f 1305//1699 1727//1880 1728//2247 +f 1727//1880 1729//2254 1728//2247 +f 1729//2254 1741//2253 1728//2247 +f 1741//2253 1730//855 127//484 +f 1732//880 1767//2255 1711//2046 +f 1759//1983 1758//1937 1689//1939 +f 1731//539 1608//2058 1778//540 +f 1721//1351 1732//880 1819//2060 +f 1905//2207 1729//2254 1727//1880 +f 464//428 1733//232 1730//855 +f 1147//1703 1828//2256 1734//2131 +f 1734//2131 1828//2256 1818//2257 +f 1793//2258 1685//72 1749//2218 +f 517//1079 1723//2152 1707//1080 +f 1796//1425 850//1443 1735//1444 +f 1852//1916 1853//1587 1844//878 +f 1813//1565 1726//1597 1786//2100 +f 1560//2124 1736//1097 1561//1649 +f 1429//1486 1375//805 1737//1942 +f 1737//1942 1754//2240 1738//1940 +f 1739//1205 1740//2259 1869//1206 +f 1741//2253 1742//2260 1730//855 +f 1730//855 1742//2260 464//428 +f 2044//2032 1743//1460 2203//1909 +f 1576//1941 1715//2158 1744//1998 +f 1801//2244 1793//2258 2640//2261 +f 1668//1936 2097//1301 2135//449 +f 937//243 936//991 58//250 +f 1746//1388 84//351 231//674 +f 1747//381 1787//1278 1748//2241 +f 1793//2258 1749//2218 1789//2195 +f 1576//1941 1676//2166 1715//2158 +f 1739//1205 645//435 1269//1839 +f 1764//1991 2631//2220 1716//2159 +f 15//63 1574//1502 1967//1504 +f 1716//2159 1723//2152 1560//2124 +f 104//352 728//1331 105//418 +f 1563//211 2111//210 880//1542 +f 66//266 1253//268 1274//1771 +f 1750//1950 1420//1949 1751//804 +f 1823//2016 1809//1931 1751//804 +f 1420//1949 1823//2016 1751//804 +f 464//428 1752//2262 1733//232 +f 1733//232 1752//2262 1893//2263 +f 1857//2264 1753//2265 1992//2266 +f 109//429 2052//588 1119//589 +f 1562//1951 1717//1153 892//1567 +f 1544//2081 1621//1545 1802//2082 +f 2249//2117 1971//2267 1530//2118 +f 1738//1940 1754//2240 1463//1944 +f 1800//2101 880//1542 879//1541 +f 1005//1644 1511//1297 1787//1278 +f 1563//211 880//1542 1800//2101 +f 1995//699 1755//698 1836//1159 +f 1756//1569 1757//2242 1694//2237 +f 411//934 1695//1598 861//1509 +f 1758//1937 1759//1983 1554//1982 +f 1386//1296 1562//1951 1511//1297 +f 1477//416 2123//1487 243//697 +f 1884//2009 1772//2112 879//1541 +f 1760//1785 2198//2268 1761//492 +f 1710//873 1720//2055 1604//2115 +f 1685//72 1662//1484 1749//2218 +f 2052//588 1742//2260 1741//2253 +f 1762//1518 1879//1528 1763//1446 +f 1752//2262 1780//261 1776//2269 +f 1818//2257 1828//2256 2634//2234 +f 1833//2270 1818//2257 1764//1991 +f 2033//2271 1765//2232 1815//1725 +f 689//1266 498//532 1009//534 +f 1766//2135 1711//2046 1767//2255 +f 1461//1947 1462//2056 1768//1981 +f 1701//1544 888//1018 833//1469 +f 1785//2272 2198//2268 1760//1785 +f 1785//2272 1788//2273 2198//2268 +f 1788//2273 1948//2274 1848//2275 +f 2198//2268 1788//2273 1848//2275 +f 850//1443 1680//1459 827//1458 +f 1769//568 1697//874 172//566 +f 1819//2060 1732//880 1791//2040 +f 1837//1902 1331//847 1840//1501 +f 1709//1896 1675//2223 1720//2055 +f 2105//2276 2047//2047 1770//2139 +f 1521//1953 1765//2232 1771//2231 +f 879//1541 1958//1543 1884//2009 +f 1772//2112 1800//2101 879//1541 +f 1933//2277 2091//1595 1726//1597 +f 1793//2258 1789//2195 2640//2261 +f 1773//198 1714//1622 127//484 +f 1038//1662 1838//2132 1774//1660 +f 1387//1440 1435//126 1775//128 +f 1776//2269 1782//2278 1893//2263 +f 1777//2279 1760//1785 2168//2280 +f 1782//2278 1777//2279 2168//2280 +f 1777//2279 1785//2272 1760//1785 +f 1778//540 1819//2060 1791//2040 +f 1958//1543 1932//1707 1884//2009 +f 1013//1648 1787//1278 665//306 +f 1779//127 1719//2224 1775//128 +f 1748//2241 1787//1278 1834//2147 +f 1780//261 61//263 1776//2269 +f 61//263 1781//2281 1776//2269 +f 1776//2269 1781//2281 1782//2278 +f 1794//2282 1948//2274 1788//2273 +f 1643//1871 1516//2098 2176//88 +f 1120//788 1607//1016 1132//1719 +f 1796//1425 1914//1424 1816//2006 +f 1559//1954 1816//2006 1783//1861 +f 1777//2279 1784//2283 1785//2272 +f 1784//2283 1788//2273 1785//2272 +f 2018//2284 1948//2274 1794//2282 +f 938//1596 1786//2100 1726//1597 +f 1787//1278 1511//1297 1562//1951 +f 1716//2159 1560//2124 1539//1989 +f 1798//2285 1794//2282 1788//2273 +f 1745//2160 1789//2195 1744//1998 +f 694//262 1146//1742 61//263 +f 1146//1742 1781//2281 61//263 +f 1790//2286 1798//2285 1788//2273 +f 1753//2265 1857//2264 2018//2284 +f 1813//1565 1786//2100 1800//2101 +f 1791//2040 1792//2039 1778//540 +f 886//693 1146//1742 694//262 +f 1781//2281 1797//2287 1777//2279 +f 1782//2278 1781//2281 1777//2279 +f 1777//2279 1797//2287 1784//2283 +f 1788//2273 1784//2283 1790//2286 +f 1138//1691 1685//72 1793//2258 +f 1577//2129 2376//1999 1676//2166 +f 1799//2288 1794//2282 1798//2285 +f 892//1567 811//1415 1856//1568 +f 1138//1691 1793//2258 1801//2244 +f 1795//314 80//125 1805//1485 +f 892//1567 1717//1153 811//1415 +f 1796//1425 1680//1459 850//1443 +f 1749//2218 1663//2176 1789//2195 +f 993//1381 1146//1742 886//693 +f 1145//1626 1797//2287 1781//2281 +f 1799//2288 2018//2284 1794//2282 +f 1145//1626 1781//2281 1146//1742 +f 1797//2287 1825//2289 1784//2283 +f 1784//2283 1825//2289 1790//2286 +f 1790//2286 1799//2288 1798//2285 +f 1826//2290 2018//2284 1799//2288 +f 1772//2112 1813//1565 1800//2101 +f 1138//1691 1801//2244 2587//1737 +f 80//125 314//339 1461//1947 +f 1802//2082 1558//1468 1559//1954 +f 2623//2114 1820//2074 2621//2103 +f 1145//1626 1831//1481 1797//2287 +f 1831//1481 1803//2291 1797//2287 +f 1797//2287 1803//2291 1825//2289 +f 1826//2290 1753//2265 2018//2284 +f 1826//2290 1992//2266 1753//2265 +f 2302//2292 1804//293 2341//1338 +f 1715//2158 1676//2166 1723//2152 +f 1002//1295 994//783 1386//1296 +f 1805//1485 1461//1947 1768//1981 +f 2052//588 1741//2253 1939//821 +f 1709//1896 1666//1825 1675//2223 +f 1806//1911 1754//2240 1807//2293 +f 1716//2159 1539//1989 1764//1991 +f 455//546 1229//920 407//921 +f 1809//1931 1807//2293 1754//2240 +f 1145//1626 1136//1482 1831//1481 +f 1811//2294 1799//2288 1790//2286 +f 1994//214 552//332 2594//1889 +f 2233//1166 2238//2295 2366//1519 +f 1808//1860 1691//2145 1779//127 +f 1703//2209 1701//1544 1621//1545 +f 1809//1931 1754//2240 1375//805 +f 1825//2289 1810//2296 1790//2286 +f 1810//2296 1811//2294 1790//2286 +f 1811//2294 1826//2290 1799//2288 +f 1764//1991 1412//1990 1833//2270 +f 1812//1564 1726//1597 1813//1565 +f 1667//2221 1489//2087 1491//2089 +f 1189//1755 1709//1896 1710//873 +f 1250//1751 1666//1825 1709//1896 +f 1008//823 1275//767 996//1629 +f 1803//2291 1814//2297 1825//2289 +f 1428//2017 2032//2019 1815//1725 +f 1756//1569 1856//1568 1860//2298 +f 1765//2232 2173//2233 1815//1725 +f 1765//2232 2033//2271 1771//2231 +f 1521//1953 1957//1726 2173//2233 +f 1607//1016 1701//1544 1703//2209 +f 1708//1503 1772//2112 1884//2009 +f 1759//1983 1689//1939 1571//2161 +f 1416//2005 1796//1425 1816//2006 +f 1724//2251 2638//2250 2641//2299 +f 1838//2132 1818//2257 1833//2270 +f 1661//2217 1607//1016 1703//2209 +f 1571//2161 1689//1939 2006//2300 +f 1838//2132 1833//2270 1693//2235 +f 1778//540 729//1335 1819//2060 +f 1820//2074 1821//1632 1822//1310 +f 1559//1954 2625//2144 1816//2006 +f 1837//1902 1840//1501 1820//2074 +f 1442//1439 1502//2018 1387//1440 +f 1571//2161 1809//1931 1823//2016 +f 1462//2056 1824//1948 1768//1981 +f 383//609 137//506 1240//610 +f 1825//2289 1814//2297 1810//2296 +f 1843//2301 1826//2290 1811//2294 +f 1843//2301 1827//2302 1826//2290 +f 1827//2302 1992//2266 1826//2290 +f 1827//2302 1016//1118 1992//2266 +f 1828//2256 1801//2244 1684//2245 +f 1147//1703 1801//2244 1828//2256 +f 1491//2089 1512//1938 1758//1937 +f 1787//1278 1562//1951 1834//2147 +f 1829//2043 1455//1665 1972//1775 +f 1830//1465 1949//2303 1927//2214 +f 1282//1862 1615//2204 1686//2146 +f 1831//1481 1832//1483 1774//1660 +f 1831//1481 1814//2297 1803//2291 +f 1693//2235 1810//2296 1814//2297 +f 1839//2236 1693//2235 1814//2297 +f 1693//2235 1811//2294 1810//2296 +f 1693//2235 1833//2270 1811//2294 +f 1833//2270 1843//2301 1811//2294 +f 1663//2176 1737//1942 1744//1998 +f 1775//128 1719//2224 1690//1952 +f 1410//1957 1593//2168 1861//2184 +f 892//1567 1694//2237 1834//2147 +f 1132//1719 1607//1016 1155//1733 +f 1722//1272 1835//522 125//473 +f 1831//1481 1774//1660 1814//2297 +f 1412//1990 1827//2302 1843//2301 +f 1490//2088 1520//2105 1512//1938 +f 1734//2131 1818//2257 1838//2132 +f 892//1567 1756//1569 1694//2237 +f 1836//1159 873//650 801//1126 +f 1820//2074 1822//1310 1837//1902 +f 1817//2304 1706//2249 2202//2305 +f 1838//2132 1814//2297 1774//1660 +f 1838//2132 1839//2236 1814//2297 +f 1827//2302 1412//1990 1016//1118 +f 1840//1501 1672//1379 1841//2066 +f 1171//954 1164//1690 1073//957 +f 1842//2136 1686//2146 2642//2306 +f 1833//2270 1412//1990 1843//2301 +f 1711//2046 1852//1916 1844//878 +f 1428//2017 1969//1724 1435//126 +f 1845//2123 644//1251 1846//1250 +f 1624//2212 1231//1798 1216//1797 +f 859//1507 1588//2174 1847//1508 +f 2129//1810 1211//1794 1866//1872 +f 2187//92 1588//2174 1909//93 +f 1847//1508 1588//2174 2187//92 +f 1979//2307 1588//2174 1620//2180 +f 1849//1928 2187//92 1848//2275 +f 2116//2308 2187//92 1849//1928 +f 102//406 1926//2309 1850//2310 +f 134//16 1851//518 203//567 +f 1852//1916 2425//1614 1853//1587 +f 102//406 1886//1925 1926//2309 +f 1886//1925 1855//2311 1926//2309 +f 60//247 1856//1568 1854//260 +f 1855//2311 1886//1925 1880//2312 +f 1858//2313 1860//2298 1856//1568 +f 60//247 1858//2313 1856//1568 +f 1985//2314 2081//2315 1857//2264 +f 1880//2312 1606//1865 2045//1912 +f 1858//2313 1859//2316 1860//2298 +f 1859//2316 1877//2317 1860//2298 +f 1977//1173 1410//1957 1861//2184 +f 1870//257 1871//2318 60//247 +f 60//247 1871//2318 1858//2313 +f 36//178 1862//2319 655//1270 +f 1936//1417 1955//2320 481//998 +f 1522//2107 1523//2109 1899//2321 +f 2056//2322 1863//1248 1864//990 +f 2029//1130 1865//630 128//490 +f 1874//1612 1553//2134 1474//1306 +f 1516//2098 1518//1758 1519//2086 +f 1871//2318 1859//2316 1858//2313 +f 2057//1922 2180//1924 1418//2001 +f 2181//1923 2057//1922 2196//1934 +f 1866//1872 2065//2323 1867//1808 +f 1868//2324 2148//2325 2089//2326 +f 1905//2207 1918//2327 1939//821 +f 1872//2092 1938//2328 1868//2324 +f 1573//2093 1872//2092 1868//2324 +f 1869//1206 1740//2259 1870//257 +f 1740//2259 1904//2329 1871//2318 +f 1870//257 1740//2259 1871//2318 +f 1877//2317 1671//2222 1757//2242 +f 1573//2093 1868//2324 1597//2177 +f 1872//2092 1522//2107 1938//2328 +f 2134//2330 1361//1846 2081//2315 +f 1890//2331 1953//2332 2065//2323 +f 2018//2284 2081//2315 1948//2274 +f 1353//405 1881//407 1873//2200 +f 1904//2329 1896//2333 1871//2318 +f 1871//2318 1896//2333 1859//2316 +f 1896//2333 1878//1529 1877//2317 +f 1859//2316 1896//2333 1877//2317 +f 1553//2134 1874//1612 1875//1917 +f 2425//1614 1875//1917 1874//1612 +f 36//178 1973//1269 1917//2334 +f 2045//1912 819//889 818//807 +f 2122//1464 830//1463 2347//2335 +f 1841//2066 2195//2068 1840//1501 +f 2078//1945 1577//2129 1876//1946 +f 1877//2317 1878//1529 1671//2222 +f 1878//1529 1879//1528 1671//2222 +f 1855//2311 37//182 748//1361 +f 1855//2311 1880//2312 37//182 +f 37//182 1880//2312 2012//2336 +f 1881//407 1850//2310 1979//2307 +f 1881//407 102//406 1850//2310 +f 1882//1806 1867//1808 2127//2337 +f 1204//181 1883//505 1892//230 +f 1967//1504 1884//2009 1885//2010 +f 1866//1872 2087//1844 2065//2323 +f 1926//2309 2188//94 1909//93 +f 1739//1205 1269//1839 1740//2259 +f 1886//1925 1888//1858 1880//2312 +f 1257//1807 1866//1872 1867//1808 +f 1522//2107 1899//2321 1938//2328 +f 1862//2319 36//178 1887//1202 +f 1204//181 2168//2280 1760//1785 +f 1204//181 1892//230 2168//2280 +f 1880//2312 1888//1858 1606//1865 +f 1269//1839 1921//1838 1740//2259 +f 1921//1838 1904//2329 1740//2259 +f 1466//2061 1889//1193 2185//1370 +f 2116//2308 1847//1508 2187//92 +f 1944//1716 44//219 1956//1378 +f 44//219 1944//1716 45//220 +f 2065//2323 2134//2330 1891//2338 +f 1890//2331 2065//2323 1891//2338 +f 1912//2339 1953//2332 1890//2331 +f 1892//230 1733//232 1893//2263 +f 1894//2340 1912//2339 2128//1890 +f 1894//2340 1953//2332 1912//2339 +f 367//860 2200//2341 1959//1530 +f 1595//2186 1222//1813 1895//2163 +f 1595//2186 2090//2342 1222//1813 +f 1606//1865 1343//1913 2045//1912 +f 1904//2329 1897//2343 1896//2333 +f 2157//1447 1878//1529 1896//2333 +f 1897//2343 2157//1447 1896//2333 +f 884//1550 2376//1999 1346//1462 +f 36//178 1917//2334 2160//179 +f 1696//1687 1898//1943 1140//1739 +f 1735//1444 1907//639 1796//1425 +f 884//1550 2165//1081 1707//1080 +f 1912//2339 1283//1344 793//1384 +f 1908//1383 1912//2339 793//1384 +f 1899//2321 2140//1809 2141//2344 +f 2078//1945 2203//1909 2077//1918 +f 1951//180 2160//179 1900//2345 +f 645//435 1739//1205 2643//2346 +f 2075//2347 1985//2314 1992//2266 +f 1906//2348 1902//1891 792//1382 +f 2140//1809 1538//2122 1846//1250 +f 1921//1838 1903//1935 1904//2329 +f 1904//2329 1903//1935 1897//2343 +f 1939//821 1729//2254 1905//2207 +f 2160//179 1902//1891 1906//2348 +f 1913//638 1914//1424 1907//639 +f 1992//2266 1985//2314 1857//2264 +f 1903//1935 2157//1447 1897//2343 +f 1469//2059 1482//861 974//1531 +f 2140//1809 1846//1250 2129//1810 +f 1914//1424 1688//2205 1816//2006 +f 1979//2307 1850//2310 1909//93 +f 2128//1890 1908//1383 792//1382 +f 2197//2349 1864//990 333//331 +f 1198//1780 655//1270 2090//2342 +f 1588//2174 1979//2307 1909//93 +f 1561//1649 1016//1118 1412//1990 +f 1523//2109 1543//2120 1538//2122 +f 819//889 1910//2143 1555//1623 +f 1900//2345 1906//2348 1962//2350 +f 1900//2345 2200//2341 1862//2319 +f 681//1161 680//149 1079//748 +f 1872//2092 2079//2154 1522//2107 +f 2120//2351 1316//1884 1597//2177 +f 561//1154 333//331 1864//990 +f 1261//1826 2175//1849 1911//1548 +f 1934//2352 1944//1716 1195//1774 +f 1198//1780 2090//2342 1595//2186 +f 1947//437 1198//1780 1595//2186 +f 2128//1890 1912//2339 1908//1383 +f 1780//261 1752//2262 464//428 +f 1913//638 1927//2214 1914//1424 +f 1325//1577 986//1169 1492//1578 +f 2020//2353 2072//2354 1946//2355 +f 2637//2243 1705//1325 2644//2356 +f 1523//2109 2140//1809 1899//2321 +f 1947//437 1595//2186 2368//438 +f 1916//2357 2160//179 1917//2334 +f 481//998 1955//2320 1683//1553 +f 793//1384 1284//1343 2064//2358 +f 1918//2327 2056//2322 2197//2349 +f 1926//2309 1919//491 2188//94 +f 645//435 1920//434 1921//1838 +f 1920//434 1903//1935 1921//1838 +f 1222//1813 2090//2342 2072//2354 +f 1458//483 474//485 1241//253 +f 1862//2319 2200//2341 1922//2359 +f 2078//1945 1923//1910 2203//1909 +f 2067//183 1883//505 1204//181 +f 1222//1813 1934//2352 1924//1773 +f 2013//2360 1963//1573 1925//1437 +f 938//1596 2091//1595 2070//2361 +f 1926//2309 748//1361 1919//491 +f 1931//1245 922//995 528//1109 +f 1705//1325 812//1423 2644//2356 +f 1949//2303 1830//1465 1937//901 +f 1927//2214 1615//2204 1914//1424 +f 2055//2362 1916//2357 1917//2334 +f 1912//2339 1890//2331 1283//1344 +f 1890//2331 1928//1345 1283//1344 +f 1359//1477 1942//2363 1358//900 +f 1929//2364 1949//2303 1937//901 +f 1930//1756 1993//2365 2075//2347 +f 1211//1794 2017//1845 2087//1844 +f 1938//2328 1899//2321 2055//2362 +f 1104//1516 1191//1763 1408//1976 +f 528//1109 1940//2366 1931//1245 +f 1940//2366 824//1243 1931//1245 +f 1885//2010 1932//1707 1425//1709 +f 1683//1553 1942//2363 1359//1477 +f 1942//2363 1937//901 1358//900 +f 1726//1597 2164//2215 1933//2277 +f 2005//1895 1351//1920 505//1057 +f 1351//1920 1993//2365 1930//1756 +f 2132//1963 115//1955 2034//1850 +f 1934//2352 2020//2353 1944//1716 +f 1935//2367 1862//2319 1922//2359 +f 1940//2366 1936//1417 824//1243 +f 1942//2363 1929//2364 1937//901 +f 1929//2364 1982//2368 1949//2303 +f 1938//2328 2055//2362 2148//2325 +f 748//1361 37//182 1204//181 +f 1939//821 2268//330 2052//588 +f 528//1109 1965//1616 1940//2366 +f 1940//2366 1954//2369 1936//1417 +f 1936//1417 1954//2369 1955//2320 +f 1955//2320 1966//2370 1683//1553 +f 1966//2370 1941//2371 1942//2363 +f 1683//1553 1966//2370 1942//2363 +f 1942//2363 1941//2371 1929//2364 +f 1941//2371 1981//2372 1929//2364 +f 1981//2372 1943//2373 1929//2364 +f 1943//2373 1982//2368 1929//2364 +f 1944//1716 1946//2355 1998//1717 +f 1945//1422 1492//1578 812//1423 +f 2072//2354 1935//2367 1946//2355 +f 2120//2351 1198//1780 1947//437 +f 1985//2314 2134//2330 2081//2315 +f 1361//1846 1849//1928 1948//2274 +f 1965//1616 1961//2374 1940//2366 +f 1955//2320 1974//2375 1966//2370 +f 1949//2303 1982//2368 2642//2306 +f 1627//133 1626//1822 1637//1358 +f 1950//458 912//1584 2220//1986 +f 1987//1007 11//51 2178//1273 +f 1887//1202 1951//180 1862//2319 +f 1339//465 1612//76 1952//1985 +f 1867//1808 1953//2332 1894//2340 +f 1940//2366 1975//2376 1954//2369 +f 1954//2369 1975//2376 1955//2320 +f 1975//2376 1974//2375 1955//2320 +f 1195//1774 1944//1716 1956//1378 +f 1962//2350 2064//2358 1959//1530 +f 1969//1724 1957//1726 1808//1860 +f 1958//1543 880//1542 2143//2377 +f 1977//1173 1861//2184 1699//1174 +f 1966//2370 1990//2378 1941//2371 +f 1943//2373 1991//2379 1982//2368 +f 1830//1465 1913//638 832//1466 +f 2039//1175 1195//1774 1956//1378 +f 1998//1717 1935//2367 2199//1555 +f 1962//2350 1959//1530 2200//2341 +f 655//1270 1862//2319 2072//2354 +f 2237//1380 805//1400 1960//2380 +f 2120//2351 2645//2381 1198//1780 +f 1940//2366 1961//2374 1975//2376 +f 1935//2367 1922//2359 2199//1555 +f 1922//2359 2200//2341 2199//1555 +f 2200//2341 1900//2345 1962//2350 +f 2013//2360 1964//2382 1963//1573 +f 1963//1573 1964//2382 1965//1616 +f 1965//1616 1964//2382 1961//2374 +f 1974//2375 1990//2378 1966//2370 +f 1941//2371 1990//2378 1981//2372 +f 1983//2383 1842//2136 1982//2368 +f 1967//1504 1207//1789 15//63 +f 1968//2216 1660//2137 1842//2136 +f 1757//2242 1860//2298 1877//2317 +f 1969//1724 1779//127 1435//126 +f 1970//2108 1522//2107 2079//2154 +f 1971//2267 2394//2384 2412//2385 +f 1984//1888 1829//2043 1972//1775 +f 2148//2325 1917//2334 1973//1269 +f 2067//183 2012//2336 818//807 +f 1964//2382 1988//2386 1961//2374 +f 1961//2374 1986//2387 1975//2376 +f 1986//2387 1974//2375 1975//2376 +f 1976//2388 1991//2379 1943//2373 +f 1855//2311 748//1361 1926//2309 +f 1722//1272 125//473 1977//1173 +f 1978//1056 1284//1343 2005//1895 +f 1620//2180 1881//407 1979//2307 +f 1925//1437 901//1448 2013//2360 +f 1997//2389 1980//2390 1990//2378 +f 1990//2378 1980//2390 1981//2372 +f 1980//2390 1943//2373 1981//2372 +f 1991//2379 2004//2391 1982//2368 +f 2004//2391 1983//2383 1982//2368 +f 1983//2383 1968//2216 1842//2136 +f 1984//1888 1863//1248 2056//2322 +f 1339//465 1952//1985 1410//1957 +f 1993//2365 1891//2338 1985//2314 +f 2646//2392 2647//2393 2571//1575 +f 2013//2360 1996//2394 1964//2382 +f 1964//2382 2000//2395 1988//2386 +f 1988//2386 2007//2396 1961//2374 +f 1986//2387 1989//2397 1974//2375 +f 1974//2375 2023//2398 1990//2378 +f 84//351 1865//630 2224//1131 +f 2178//1273 1527//2097 1987//1007 +f 1927//2214 1913//638 1830//1465 +f 1964//2382 1996//2394 2000//2395 +f 2000//2395 2007//2396 1988//2386 +f 1961//2374 2007//2396 1986//2387 +f 1974//2375 1989//2397 2023//2398 +f 2023//2398 2019//2399 1990//2378 +f 1990//2378 2019//2399 1997//2389 +f 1976//2388 1943//2373 1980//2390 +f 1976//2388 2004//2391 1991//2379 +f 1016//1118 2075//2347 1992//2266 +f 1928//1345 1890//2331 1993//2365 +f 1890//2331 1891//2338 1993//2365 +f 1994//214 1995//699 952//215 +f 2013//2360 2001//2400 1996//2394 +f 2019//2399 2003//2401 1997//2389 +f 1946//2355 1935//2367 1998//1717 +f 1605//1853 1574//1502 882//65 +f 1905//2207 2629//2197 2648//2402 +f 2046//1589 2040//2403 2649//2404 +f 2000//2395 1996//2394 2001//2400 +f 2002//2405 1997//2389 2003//2401 +f 2002//2405 2026//2406 1980//2390 +f 1997//2389 2002//2405 1980//2390 +f 2026//2406 2015//2407 1976//2388 +f 1980//2390 2026//2406 1976//2388 +f 1976//2388 2015//2407 2004//2391 +f 2004//2391 2008//2408 1983//2383 +f 2008//2408 1968//2216 1983//2383 +f 1284//1343 1351//1920 2005//1895 +f 2064//2358 1284//1343 2010//1609 +f 1669//1302 1668//1936 1898//1943 +f 2464//605 2463//468 215//640 +f 2103//2038 376//879 1844//878 +f 2051//2099 2006//2300 2033//2271 +f 529//997 1965//1616 528//1109 +f 1354//1856 1635//2203 2145//1857 +f 1968//2216 2163//2409 2164//2215 +f 2007//2396 2022//2410 1986//2387 +f 1989//2397 2031//2411 2023//2398 +f 2015//2407 2016//2412 2004//2391 +f 2016//2412 2008//2408 2004//2391 +f 1968//2216 2008//2408 2163//2409 +f 1492//1578 1493//2090 812//1423 +f 1984//1888 2009//1261 1863//1248 +f 1866//1872 1211//1794 2087//1844 +f 1959//1530 2010//1609 963//1601 +f 2032//2019 2051//2099 2033//2271 +f 2011//1513 770//833 1478//647 +f 2012//2336 1880//2312 2045//1912 +f 644//1251 1847//1508 2116//2308 +f 1899//2321 2141//2344 1916//2357 +f 1211//1794 644//1251 2116//2308 +f 2013//2360 2040//2403 2001//2400 +f 2000//2395 2022//2410 2007//2396 +f 2022//2410 2014//2413 1986//2387 +f 1986//2387 2014//2413 1989//2397 +f 2026//2406 2027//2414 2015//2407 +f 2027//2414 2024//2415 2015//2407 +f 2015//2407 2024//2415 2016//2412 +f 899//1410 1977//1173 2039//1175 +f 2178//1273 1977//1173 899//1410 +f 2017//1845 2116//2308 1849//1928 +f 1806//1911 2006//2300 2051//2099 +f 2081//2315 2018//2284 1857//2264 +f 1886//1925 1354//1856 1888//1858 +f 2000//2395 2037//2416 2022//2410 +f 2019//2399 2023//2398 2003//2401 +f 1944//1716 2020//2353 1946//2355 +f 1807//2293 2006//2300 1806//1911 +f 1807//2293 1571//2161 2006//2300 +f 1918//2327 1905//2207 2648//2402 +f 2021//582 181//581 1889//1193 +f 2037//2416 2042//2417 2022//2410 +f 2022//2410 2031//2411 2014//2413 +f 2031//2411 1989//2397 2014//2413 +f 2031//2411 2025//2418 2023//2398 +f 2024//2415 2028//2419 2016//2412 +f 2028//2419 2008//2408 2016//2412 +f 2010//1609 1284//1343 46//223 +f 1689//1939 1771//2231 2006//2300 +f 1850//2310 1926//2309 1909//93 +f 1934//2352 2072//2354 2020//2353 +f 2025//2418 2003//2401 2023//2398 +f 2002//2405 2043//2420 2026//2406 +f 2026//2406 2043//2420 2027//2414 +f 1933//2277 2163//2409 2008//2408 +f 2028//2419 1933//2277 2008//2408 +f 1861//2184 1594//1812 1924//1773 +f 2044//2032 2051//2099 1502//2018 +f 1939//821 1918//2327 2080//822 +f 2397//53 2095//2078 11//51 +f 2132//1963 2029//1130 128//490 +f 2042//2417 2059//2421 2022//2410 +f 2059//2421 2060//2422 2022//2410 +f 2060//2422 2030//2423 2022//2410 +f 2022//2410 2030//2423 2031//2411 +f 2030//2423 2025//2418 2031//2411 +f 1284//1343 1928//1345 1351//1920 +f 1809//1931 1571//2161 1807//2293 +f 2032//2019 2033//2271 1815//1725 +f 2128//1890 1867//1808 1894//2340 +f 2135//449 2034//1850 115//1955 +f 2001//2400 2038//2424 2000//2395 +f 2000//2395 2038//2424 2037//2416 +f 2027//2414 2035//2425 2024//2415 +f 2024//2415 2035//2425 2028//2419 +f 2036//2426 2037//2416 2038//2424 +f 2037//2416 2036//2426 2042//2417 +f 2030//2423 2069//2427 2025//2418 +f 2069//2427 2050//2428 2003//2401 +f 2025//2418 2069//2427 2003//2401 +f 2050//2428 2002//2405 2003//2401 +f 1951//180 1900//2345 1862//2319 +f 1699//1174 1195//1774 2039//1175 +f 2046//1589 2048//2429 2040//2403 +f 2036//2426 2041//2430 2042//2417 +f 2042//2417 2041//2430 2059//2421 +f 2060//2422 2069//2427 2030//2423 +f 2043//2420 2066//2431 2027//2414 +f 2035//2425 2054//2432 2028//2419 +f 1918//2327 1829//2043 2650//2433 +f 895//1323 1903//1935 1920//434 +f 2203//1909 2051//2099 2044//2032 +f 1916//2357 1902//1891 2160//179 +f 2012//2336 2045//1912 818//807 +f 2058//1526 2047//2047 2651//2434 +f 2046//1589 2651//2434 2048//2429 +f 2049//2435 2652//2436 2050//2428 +f 2002//2405 2652//2436 2043//2420 +f 2027//2414 2066//2431 2035//2425 +f 2070//2361 1933//2277 2028//2419 +f 2203//1909 1806//1911 2051//2099 +f 1893//2263 1782//2278 2168//2280 +f 1742//2260 2052//588 464//428 +f 2048//2429 2107//2437 2653//2438 +f 2107//2437 2654//2439 2653//2438 +f 2041//2430 2053//2440 2059//2421 +f 2060//2422 2053//2440 2069//2427 +f 2035//2425 2063//2441 2054//2432 +f 2070//2361 2028//2419 2054//2432 +f 2055//2362 1899//2321 1916//2357 +f 2197//2349 2056//2322 1864//990 +f 2057//1922 1425//1709 1094//1708 +f 2058//1526 1459//1551 2047//2047 +f 2001//2400 2654//2439 2038//2424 +f 2059//2421 2053//2440 2060//2422 +f 2053//2440 2061//2442 2069//2427 +f 2066//2431 2062//2443 2035//2425 +f 2062//2443 2063//2441 2035//2425 +f 2063//2441 2070//2361 2054//2432 +f 1614//2202 1635//2203 1354//1856 +f 1962//2350 1906//2348 2064//2358 +f 1953//2332 1867//1808 2065//2323 +f 2043//2420 2086//2444 2066//2431 +f 1378//1327 1736//1097 1485//2083 +f 1485//2083 1736//1097 1566//2153 +f 1918//2327 2650//2433 2056//2322 +f 1614//2202 1354//1856 1353//405 +f 37//182 2012//2336 2067//183 +f 2107//2437 2108//2445 2038//2424 +f 2038//2424 2108//2445 2036//2426 +f 2041//2430 2068//2446 2053//2440 +f 2061//2442 2083//2447 2069//2427 +f 2069//2427 2083//2447 2050//2428 +f 2049//2435 2086//2444 2043//2420 +f 2066//2431 2085//2448 2062//2443 +f 2452//1162 2218//1498 896//1283 +f 1570//2150 938//1596 2070//2361 +f 1873//2200 1614//2202 1353//405 +f 2071//1576 2191//2191 2102//2449 +f 2072//2354 1862//2319 1935//2367 +f 2108//2445 2073//2450 2036//2426 +f 2073//2450 2068//2446 2041//2430 +f 2036//2426 2073//2450 2041//2430 +f 2068//2446 2074//2451 2053//2440 +f 2083//2447 2093//2452 2050//2428 +f 2093//2452 2049//2435 2050//2428 +f 1771//2231 2033//2271 2006//2300 +f 11//51 1722//1272 2178//1273 +f 1930//1756 2075//2347 1016//1118 +f 2053//2440 2109//2453 2061//2442 +f 2086//2444 2085//2448 2066//2431 +f 2112//212 2070//2361 2063//2441 +f 2112//212 1570//2150 2070//2361 +f 2045//1912 1584//1914 819//889 +f 2135//449 2655//2454 1668//1936 +f 2074//2451 2126//2455 2053//2440 +f 2053//2440 2126//2455 2109//2453 +f 2061//2442 2098//2456 2083//2447 +f 2085//2448 2076//2457 2062//2443 +f 2076//2457 2063//2441 2062//2443 +f 1222//1813 2072//2354 1934//2352 +f 2077//1918 2376//1999 2078//1945 +f 1872//2092 1599//2091 2079//2154 +f 1918//2327 2197//2349 2080//822 +f 2081//2315 1361//1846 1948//2274 +f 1612//76 2082//464 2338//77 +f 1948//2274 1849//1928 1848//2275 +f 2098//2456 2093//2452 2083//2447 +f 2093//2452 2084//2458 2086//2444 +f 2049//2435 2093//2452 2086//2444 +f 2084//2458 2100//2459 2085//2448 +f 2086//2444 2084//2458 2085//2448 +f 1553//2134 1770//2139 1474//1306 +f 2082//464 1338//463 2338//77 +f 2087//1844 2134//2330 2065//2323 +f 2047//2047 2105//2276 2048//2429 +f 2048//2429 2105//2276 2107//2437 +f 2061//2442 2109//2453 2098//2456 +f 2100//2459 2152//2460 2085//2448 +f 2085//2448 2152//2460 2076//2457 +f 2076//2457 2088//2461 2063//2441 +f 2063//2441 2088//2461 2112//212 +f 1597//2177 2089//2326 2120//2351 +f 792//1382 793//1384 2064//2358 +f 2090//2342 655//1270 2072//2354 +f 1933//2277 2070//2361 2091//1595 +f 2074//2451 2138//2462 2126//2455 +f 2098//2456 2092//2463 2093//2452 +f 2152//2460 2088//2461 2076//2457 +f 2134//2330 2087//1844 1361//1846 +f 966//1287 1672//1379 1098//1288 +f 1488//2069 12//52 1987//1007 +f 1488//2069 2094//2037 12//52 +f 1835//522 2095//2078 830//1463 +f 2096//239 728//1331 2097//1301 +f 1670//1461 1743//1460 2044//2032 +f 2109//2453 2092//2463 2098//2456 +f 2084//2458 2099//2464 2100//2459 +f 2372//1405 2373//2465 2656//2466 +f 2128//1890 2127//2337 1867//1808 +f 1965//1616 2101//1566 1963//1573 +f 792//1382 2064//2358 1906//2348 +f 137//506 662//251 1240//610 +f 2482//2467 2071//1576 2102//2449 +f 2103//2038 906//1581 1445//2036 +f 844//1488 2123//1487 2104//415 +f 2104//415 2124//2468 844//1488 +f 1959//1530 2064//2358 2010//1609 +f 2105//2276 2106//2140 2751//2469 +f 2107//2437 2752//2470 2108//2445 +f 2125//2471 2073//2450 2108//2445 +f 2118//2472 2125//2471 2108//2445 +f 2125//2471 2068//2446 2073//2450 +f 2068//2446 2138//2462 2074//2451 +f 2126//2455 2092//2463 2109//2453 +f 2092//2463 2110//2473 2093//2452 +f 2088//2461 2111//210 2112//212 +f 888//1018 2113//1017 2114//787 +f 1410//1957 1389//474 1339//465 +f 797//1121 2459//1851 2115//1178 +f 1815//1725 1969//1724 1428//2017 +f 1211//1794 2116//2308 2017//1845 +f 517//1079 1485//2083 1566//2153 +f 2657//2474 2498//2475 2658//2476 +f 1893//2263 1752//2262 1776//2269 +f 2107//2437 2751//2469 2752//2470 +f 2110//2473 2099//2464 2084//2458 +f 2093//2452 2110//2473 2084//2458 +f 2099//2464 2151//2477 2100//2459 +f 2100//2459 2151//2477 2152//2460 +f 2152//2460 2119//2478 2088//2461 +f 1392//1962 128//490 1401//1971 +f 2141//2344 2127//2337 1916//2357 +f 1221//1314 1972//1775 1557//2102 +f 1316//1884 2120//2351 1947//437 +f 2121//2479 2122//1464 2347//2335 +f 2122//1464 2121//2479 1338//463 +f 2117//2480 2658//2476 2559//1324 +f 2123//1487 1477//416 2104//415 +f 844//1488 2124//2468 210//628 +f 1523//2109 1970//2108 1543//2120 +f 1264//1264 1347//986 1325//1577 +f 2150//2481 2068//2446 2125//2471 +f 2150//2481 2138//2462 2068//2446 +f 2126//2455 2138//2462 2092//2463 +f 2138//2462 2659//2482 2092//2463 +f 2092//2463 2159//2483 2110//2473 +f 2119//2478 2111//210 2088//2461 +f 2127//2337 2128//1890 1916//2357 +f 2129//1810 2130//1252 1211//1794 +f 884//1550 1707//1080 2376//1999 +f 210//628 2124//2468 1841//2066 +f 1846//1250 2130//1252 2129//1810 +f 2331//75 2131//1837 1612//76 +f 2219//2484 998//1279 2262//1419 +f 1927//2214 1949//2303 1686//2146 +f 2132//1963 2034//1850 2029//1130 +f 2110//2473 2133//2485 2099//2464 +f 2099//2464 2133//2485 2151//2477 +f 1891//2338 2134//2330 1985//2314 +f 1924//1773 1934//2352 1195//1774 +f 1993//2365 1985//2314 2075//2347 +f 2321//448 1898//1943 2655//2454 +f 2136//2486 2248//2487 2323//2488 +f 2162//2067 2124//2468 2104//415 +f 2105//2276 1770//2139 2106//2140 +f 2150//2481 2660//2489 2138//2462 +f 2137//2490 2159//2483 2659//2482 +f 2110//2473 2142//2491 2133//2485 +f 2139//2492 2111//210 2119//2478 +f 1868//2324 2089//2326 1597//2177 +f 1612//76 2131//1837 1617//1836 +f 2140//1809 2127//2337 2141//2344 +f 1755//698 220//648 873//650 +f 2194//2493 2162//2067 2104//415 +f 2162//2067 1841//2066 2124//2468 +f 1672//1379 966//1287 1841//2066 +f 2159//2483 2142//2491 2110//2473 +f 2139//2492 2143//2377 2111//210 +f 2143//2377 880//1542 2111//210 +f 2089//2326 2148//2325 1973//1269 +f 1353//405 1886//1925 102//406 +f 2144//227 2145//1857 1635//2203 +f 2089//2326 1973//1269 2645//2381 +f 2454//2494 2453//2495 2146//284 +f 2147//1961 2137//2490 2660//2489 +f 2133//2485 2153//2496 2151//2477 +f 2152//2460 2139//2492 2119//2478 +f 2055//2362 1917//2334 2148//2325 +f 2140//1809 1882//1806 2127//2337 +f 1928//1345 1993//2365 1351//1920 +f 1998//1717 2199//1555 2149//1554 +f 2405//1525 401//1305 2618//2070 +f 2140//1809 1256//1811 1882//1806 +f 2170//2497 2125//2471 2118//2472 +f 2170//2497 2150//2481 2125//2471 +f 2159//2483 2172//2498 2142//2491 +f 2172//2498 2133//2485 2142//2491 +f 2151//2477 2153//2496 2152//2460 +f 2152//2460 2153//2496 2139//2492 +f 1767//2255 1732//880 2154//1453 +f 1330//1881 188//590 2155//2499 +f 2156//1512 2157//1447 1903//1935 +f 2156//1512 939//1445 2157//1447 +f 2158//1900 2310//1915 1266//1835 +f 2192//242 317//414 316//646 +f 2194//2493 2104//415 317//414 +f 2106//2140 1767//2255 2118//2472 +f 2170//2497 2147//1961 2150//2481 +f 2172//2498 2159//2483 2137//2490 +f 1572//2162 1595//2186 1895//2163 +f 2160//179 1906//2348 1900//2345 +f 2029//1130 2034//1850 2224//1131 +f 2082//464 1612//76 1339//465 +f 2161//1537 1026//1539 1380//1654 +f 2195//2068 2162//2067 2194//2493 +f 906//1581 2103//2038 1844//878 +f 2106//2140 1766//2135 1767//2255 +f 2154//1453 2118//2472 1767//2255 +f 2154//1453 2170//2497 2118//2472 +f 2172//2498 2182//2500 2133//2485 +f 2183//2501 2153//2496 2133//2485 +f 2182//2500 2183//2501 2133//2485 +f 2183//2501 2184//2502 2153//2496 +f 2184//2502 2139//2492 2153//2496 +f 2139//2492 2184//2502 2143//2377 +f 1882//1806 1256//1811 1257//1807 +f 1868//2324 1938//2328 2148//2325 +f 2453//2495 2161//1537 1380//1654 +f 1380//1654 2146//284 2453//2495 +f 1930//1756 1177//1096 505//1057 +f 1553//2134 1766//2135 2106//2140 +f 2147//1961 2661//2503 2137//2490 +f 172//566 450//521 134//16 +f 2163//2409 1933//2277 2164//2215 +f 2204//1852 517//1079 2165//1081 +f 2166//158 2167//1958 1165//1681 +f 1892//230 1893//2263 2168//2280 +f 2154//1453 2169//1219 2170//2497 +f 1390//1218 2147//1961 2170//2497 +f 2171//1960 2172//2498 2661//2503 +f 2171//1960 1430//2000 2172//2498 +f 2180//1924 2172//2498 1430//2000 +f 2180//1924 2182//2500 2172//2498 +f 1919//491 1761//492 2198//2268 +f 2204//1852 1485//2083 517//1079 +f 1957//1726 1815//1725 2173//2233 +f 2174//1696 317//414 2192//242 +f 2174//1696 2194//2493 317//414 +f 2312//2504 1911//1548 2175//1849 +f 2403//2505 2491//1765 1227//1815 +f 2169//1219 1390//1218 2170//2497 +f 2176//88 2177//87 1643//1871 +f 2178//1273 899//1410 2179//2085 +f 2180//1924 2181//1923 2182//2500 +f 2181//1923 2183//2501 2182//2500 +f 2184//2502 1094//1708 2143//2377 +f 1094//1708 1958//1543 2143//2377 +f 2185//1370 2186//2084 1466//2061 +f 2187//92 2198//2268 1848//2275 +f 2187//92 2188//94 2198//2268 +f 2189//1280 692//956 777//838 +f 1970//2108 2079//2154 2190//2126 +f 2352//1347 1569//2156 2647//2393 +f 937//243 316//646 764//1030 +f 937//243 2192//242 316//646 +f 1220//241 2174//1696 2192//242 +f 1268//1316 2194//2493 2174//1696 +f 1268//1316 2193//1646 2195//2068 +f 2194//2493 1268//1316 2195//2068 +f 1845//2123 1846//1250 1538//2122 +f 1916//2357 2128//1890 1902//1891 +f 2196//1934 2183//2501 2181//1923 +f 333//331 2080//822 2197//2349 +f 2188//94 1919//491 2198//2268 +f 2199//1555 2200//2341 367//860 +f 2450//1926 2201//1592 2340//1893 +f 2202//2305 1706//2249 1915//2506 +f 1743//1460 2077//1918 2203//1909 +f 1939//821 1741//2253 1729//2254 +f 2196//1934 2184//2502 2183//2501 +f 2184//2502 2196//1934 1094//1708 +f 1094//1708 1932//1707 1958//1543 +f 1523//2109 1538//2122 2140//1809 +f 882//65 1485//2083 2204//1852 +f 2239//2507 2662//2508 2663//2509 +f 2205//2510 2499//2511 2206//2512 +f 2753//2513 2451//2514 2754//2515 +f 2205//2510 2207//2516 2499//2511 +f 2238//2295 2233//1166 2666//2517 +f 2398//2518 2393//2519 2248//2487 +f 2465//2520 2306//1014 2667//2521 +f 2208//2522 2211//2523 2213//2524 +f 2326//274 2328//2525 145//275 +f 2229//2526 2475//2527 2230//2528 +f 2393//2519 2227//2529 2474//2530 +f 2328//2525 2325//2531 2433//519 +f 2394//2384 2474//2530 2229//2526 +f 2483//2532 2209//2110 2622//2111 +f 2265//2533 2485//2534 2210//2535 +f 2482//2467 2668//2536 2071//1576 +f 2208//2522 2214//2537 2211//2523 +f 2212//2538 2206//2512 2499//2511 +f 2438//1552 2314//2539 2228//2540 +f 2211//2523 2214//2537 2213//2524 +f 1413//762 1401//1971 2215//489 +f 2214//2537 2669//2541 2213//2524 +f 2663//2509 2206//2512 2670//2542 +f 1320//1885 1804//293 2302//2292 +f 2215//489 2216//28 467//761 +f 1298//1762 2411//1875 2217//2543 +f 856//375 2374//1500 138//476 +f 817//1433 896//1283 2218//1498 +f 648//1044 2219//2484 2325//2531 +f 2021//582 2220//1986 2573//1608 +f 2465//2520 2667//2521 2671//2544 +f 1249//1192 1950//458 2220//1986 +f 2021//582 1249//1192 2220//1986 +f 2221//1593 2201//1592 2251//2545 +f 2400//2546 2222//1253 1901//1254 +f 2400//2546 2241//1992 2222//1253 +f 2241//1992 2214//2537 2208//2522 +f 2223//1611 496//1032 2327//1045 +f 2034//1850 104//352 2224//1131 +f 2438//1552 2225//973 2314//2539 +f 2672//2547 2205//2510 2662//2508 +f 645//435 2222//1253 299//436 +f 2258//2548 2263//2549 2673//2550 +f 2212//2538 2499//2511 2470//2551 +f 2266//2228 2136//2486 2323//2488 +f 2398//2518 2227//2529 2393//2519 +f 2206//2512 2346//2552 2670//2542 +f 2225//973 2402//1346 769//974 +f 2206//2512 2212//2538 2346//2552 +f 2228//2540 2314//2539 2674//2553 +f 2229//2526 2230//2528 2412//2385 +f 1494//2094 2286//2554 2267//2555 +f 1187//401 2231//2556 2386//1760 +f 2222//1253 2232//1994 1678//2226 +f 2448//2557 2666//2517 2362//1268 +f 489//1013 2234//547 158//548 +f 2235//143 2237//1380 2236//166 +f 333//331 561//1154 552//332 +f 1153//1329 1162//863 549//865 +f 109//429 694//262 1780//261 +f 2237//1380 1960//2380 2240//1231 +f 2308//2558 2207//2516 2205//2510 +f 2308//2558 2366//1519 2207//2516 +f 2207//2516 2366//1519 2238//2295 +f 2253//2559 2238//2295 2448//2557 +f 2207//2516 2238//2295 2253//2559 +f 2230//2528 2264//2560 2675//2561 +f 2225//973 2434//972 2314//2539 +f 2213//2524 2257//2562 2239//2507 +f 2136//2486 2293//2563 2248//2487 +f 2252//2564 1433//78 2240//1231 +f 2277//2565 2400//2546 1901//1254 +f 2400//2546 2379//2566 2241//1992 +f 2379//2566 2214//2537 2241//1992 +f 2346//2552 2212//2538 2322//2567 +f 2379//2566 2676//2568 2214//2537 +f 2242//2569 2257//2562 2669//2541 +f 1679//2227 2232//1994 2243//1993 +f 2237//1380 2240//1231 2236//166 +f 1960//2380 2252//2564 2240//1231 +f 1433//78 2252//2564 2254//2570 +f 2244//1521 2205//2510 2672//2547 +f 2244//1521 2308//2558 2205//2510 +f 2222//1253 1678//2226 263//730 +f 2246//1282 998//1279 2219//2484 +f 1724//2251 2641//2299 2245//2571 +f 1530//2118 1971//2267 2412//2385 +f 648//1044 2246//1282 2219//2484 +f 2225//973 2438//1552 2247//1353 +f 2297//2572 2210//2535 2677//2573 +f 1960//2380 805//1400 2252//2564 +f 2261//1744 923//1396 2256//2574 +f 2249//2117 2248//2487 1971//2267 +f 1529//2116 2324//1997 2249//2117 +f 2343//2575 2324//1997 1529//2116 +f 2201//1592 2250//1995 2251//2545 +f 1596//2178 2320//290 1598//2164 +f 805//1400 1494//2094 2252//2564 +f 2252//2564 1494//2094 2267//2555 +f 2267//2555 2274//2576 2252//2564 +f 2252//2564 2274//2576 2254//2570 +f 2448//2557 2228//2540 2253//2559 +f 2250//1995 2343//2575 2251//2545 +f 2297//2572 2258//2548 2633//2230 +f 2461//2577 2476//1996 2678//2578 +f 2274//2576 2255//2579 2254//2570 +f 2254//2570 2255//2579 2256//2574 +f 2315//1520 2257//2562 2242//2569 +f 2315//1520 2244//1521 2257//2562 +f 2456//1170 986//1169 2115//1178 +f 1681//2229 2258//2548 2260//2580 +f 1681//2229 2260//2580 2221//1593 +f 2297//2572 2680//2581 2679//2582 +f 2484//1438 2462//2583 2755//2584 +f 2462//2583 2450//1926 2755//2584 +f 2255//2579 2281//2585 2256//2574 +f 2256//2574 2281//2585 2261//1744 +f 2232//1994 1679//2227 1678//2226 +f 6//35 2259//1300 5//33 +f 2260//2580 2226//1574 2285//2586 +f 1330//1881 2380//2587 2407//1898 +f 2281//2585 2288//2588 2261//1744 +f 1678//2226 2323//2488 2476//1996 +f 2325//2531 2219//2484 2439//1421 +f 2219//2484 2262//1419 2439//1421 +f 2260//2580 2258//2548 2673//2550 +f 2280//2589 931//1591 2285//2586 +f 686//1012 1144//1281 489//1013 +f 2274//2576 2289//2590 2255//2579 +f 2255//2579 2289//2590 2281//2585 +f 2479//2591 2681//2592 2515//340 +f 2677//2573 2210//2535 2682//2593 +f 2264//2560 2683//2594 2684//2595 +f 2275//1932 2288//2588 2281//2585 +f 2291//1841 1382//1848 2275//1932 +f 2323//2488 1678//2226 2266//2228 +f 1821//1632 350//836 1822//1310 +f 1325//1577 2209//2110 1264//1264 +f 2267//2555 2286//2554 2274//2576 +f 1119//589 2268//330 552//332 +f 2325//2531 2439//1421 2378//2596 +f 809//1411 1901//1254 2643//2346 +f 2270//778 1020//1641 472//712 +f 2269//746 2270//778 472//712 +f 697//116 2300//1607 4//25 +f 2291//1841 2175//1849 1270//1830 +f 2300//1607 957//81 4//25 +f 2685//2597 2279//2598 2686//2599 +f 2301//2600 158//548 2272//1262 +f 2687//2601 2273//1403 2688//2602 +f 2286//2554 2303//2603 2274//2576 +f 2303//2603 2289//2590 2274//2576 +f 2289//2590 2282//2604 2281//2585 +f 2290//2605 2275//1932 2281//2585 +f 2290//2605 2291//1841 2275//1932 +f 2322//2567 2276//2606 2478//2048 +f 809//1411 2277//2565 1901//1254 +f 2276//2606 2496//2049 2478//2048 +f 1258//1829 2408//1863 1296//1873 +f 1415//1494 1583//1467 2278//190 +f 2375//1499 856//375 1248//377 +f 2689//2607 2280//2589 2668//2536 +f 2479//2591 2296//1404 2756//2608 +f 2281//2585 2282//2604 2290//2605 +f 2325//2531 2378//2596 2433//519 +f 2283//1008 502//364 63//273 +f 2284//1038 623//269 2345//236 +f 2344//1536 2284//1038 2345//236 +f 2285//2586 2226//1574 2071//1576 +f 2280//2589 2285//2586 2071//1576 +f 2354//2609 2230//2528 2475//2527 +f 2352//1347 2561//1349 2690//2610 +f 2271//2611 2686//2599 401//1305 +f 1342//1908 2286//2554 1452//2042 +f 2344//1536 512//1039 2284//1038 +f 2287//815 2261//1744 2288//2588 +f 2256//2574 923//1396 2254//2570 +f 2279//2598 2685//2597 2689//2607 +f 2271//2611 401//1305 2405//1525 +f 2311//2612 2289//2590 2303//2603 +f 2311//2612 2282//2604 2289//2590 +f 2290//2605 2175//1849 2291//1841 +f 923//1396 1433//78 2254//2570 +f 2292//2613 2242//2569 2676//2568 +f 2292//2613 2691//2614 2242//2569 +f 2293//2563 2398//2518 2248//2487 +f 2366//1519 795//1102 2233//1166 +f 1298//1762 2384//1399 804//1398 +f 954//1605 2310//1915 2294//1606 +f 2282//2604 2312//2504 2290//2605 +f 2290//2605 2312//2504 2175//1849 +f 662//251 924//664 2295//252 +f 2692//2615 2502//2616 2693//2617 +f 2265//2533 2210//2535 2679//2582 +f 885//1556 2315//1520 2242//2569 +f 771//301 707//971 405//665 +f 2298//1033 2299//1318 28//117 +f 1657//289 2317//288 2298//1033 +f 2299//1318 2305//2618 2309//1546 +f 2300//1607 2310//1915 954//1605 +f 1205//1786 2688//2602 2694//2619 +f 489//1013 158//548 2301//2600 +f 2302//2292 2303//2603 2286//2554 +f 2302//2292 2311//2612 2303//2603 +f 1596//2178 2332//2620 2320//290 +f 2372//1405 2693//2617 2695//2621 +f 1058//1136 1142//1720 2304//1328 +f 2317//288 2305//2618 2298//1033 +f 697//116 2309//1546 2300//1607 +f 2264//2560 2696//2622 2683//2594 +f 2302//2292 2286//2554 1342//1908 +f 2306//1014 489//1013 2301//2600 +f 2307//1490 2308//2558 2244//1521 +f 2307//1490 2366//1519 2308//2558 +f 2309//1546 2336//2623 2300//1607 +f 2336//2623 2310//1915 2300//1607 +f 1267//1263 2272//1262 2364//175 +f 2341//1338 2311//2612 2302//2292 +f 2282//2604 2313//1930 2312//2504 +f 2313//1930 1911//1548 2312//2504 +f 2314//2539 2697//2624 2451//2514 +f 2474//2530 2227//2529 2475//2527 +f 2307//1490 2315//1520 1238//1491 +f 2320//290 2319//2625 2317//288 +f 2316//2626 2339//2627 2317//288 +f 2317//288 2339//2627 2305//2618 +f 1540//1276 661//507 1555//1623 +f 1311//1814 1051//1680 2449//1679 +f 1320//1885 2302//2292 1342//1908 +f 2318//2628 2282//2604 2311//2612 +f 2282//2604 2318//2628 2313//1930 +f 2465//2520 2671//2544 2451//2514 +f 2276//2606 2212//2538 2470//2551 +f 2248//2487 2393//2519 1971//2267 +f 2332//2620 2319//2625 2320//290 +f 2319//2625 2316//2626 2317//288 +f 2328//2525 2433//519 145//275 +f 2452//1162 2462//2583 2218//1498 +f 2167//1958 1140//1739 2321//448 +f 2318//2628 2311//2612 2341//1338 +f 2394//2384 2229//2526 2412//2385 +f 2353//2629 2346//2552 2322//2567 +f 2339//2627 2334//2630 2305//2618 +f 2323//2488 2248//2487 2324//1997 +f 1385//235 1649//206 2313//1930 +f 1316//1884 1317//439 2332//2620 +f 2305//2618 2351//2631 2309//1546 +f 2351//2631 2335//2632 2309//1546 +f 2309//1546 2335//2632 2336//2623 +f 1756//1569 1860//2298 1757//2242 +f 2327//1045 2325//2531 2328//2525 +f 2326//274 2327//1045 2328//2525 +f 2155//2499 188//590 2342//592 +f 2329//2633 2318//2628 2341//1338 +f 2318//2628 1385//235 2313//1930 +f 2330//1886 1322//1879 1330//1881 +f 2331//75 2342//592 2131//1837 +f 1317//439 2348//2634 2332//2620 +f 2348//2634 2349//2635 2332//2620 +f 2332//2620 2349//2635 2319//2625 +f 2319//2625 2339//2627 2316//2626 +f 2339//2627 2333//2636 2334//2630 +f 2335//2632 2358//2637 2336//2623 +f 2358//2637 2310//1915 2336//2623 +f 2358//2637 1266//1835 2310//1915 +f 2386//1760 2381//2638 2337//2185 +f 1039//1309 1184//1515 1419//1307 +f 2121//2479 2365//2639 2331//75 +f 2338//77 2121//2479 2331//75 +f 2319//2625 2349//2635 2339//2627 +f 2349//2635 2350//2640 2339//2627 +f 2339//2627 2350//2640 2333//2636 +f 2450//1926 2340//1893 1355//1927 +f 2251//2545 2343//2575 1681//2229 +f 2361//1029 2329//2633 2341//1338 +f 2329//2633 2344//1536 2318//2628 +f 2318//2628 2344//1536 1385//235 +f 822//1427 943//1365 766//1364 +f 2331//75 2365//2639 2342//592 +f 2370//1420 885//1556 2691//2614 +f 2333//2636 2351//2631 2305//2618 +f 2334//2630 2333//2636 2305//2618 +f 902//1579 2271//2611 2570//1527 +f 1681//2229 2343//2575 1529//2116 +f 1330//1881 1306//1866 188//590 +f 2360//1059 2329//2633 2361//1029 +f 2344//1536 2345//236 1385//235 +f 2346//2552 2227//2529 2698//2641 +f 2347//2335 2365//2639 2121//2479 +f 2348//2634 2357//2642 2349//2635 +f 2388//2643 2350//2640 2349//2635 +f 2350//2640 2389//2644 2333//2636 +f 2351//2631 2391//2645 2335//2632 +f 2335//2632 2391//2645 2358//2637 +f 2301//2600 2272//1262 2209//2110 +f 2682//2593 2210//2535 2562//1348 +f 2352//1347 2690//2610 1569//2156 +f 2360//1059 2344//1536 2329//2633 +f 2353//2629 2475//2527 2227//2529 +f 2353//2629 2354//2609 2475//2527 +f 2347//2335 2355//2646 2365//2639 +f 2356//1210 848//1211 2011//1513 +f 1540//1276 1889//1193 181//581 +f 2357//2642 2388//2643 2349//2635 +f 2389//2644 2392//2647 2333//2636 +f 2391//2645 2382//2648 2358//2637 +f 2359//2649 1266//1835 2358//2637 +f 2382//2648 2359//2649 2358//2637 +f 1266//1835 2359//2649 2375//1499 +f 1296//1873 1298//1762 1190//1700 +f 1496//591 188//590 1306//1866 +f 525//1058 2360//1059 2361//1029 +f 2362//1268 2363//1241 2448//2557 +f 2272//1262 158//548 2364//175 +f 2346//2552 2353//2629 2227//2529 +f 2327//1045 648//1044 2325//2531 +f 2385//2650 2342//592 2365//2639 +f 2355//2646 2385//2650 2365//2639 +f 2385//2650 2155//2499 2342//592 +f 2307//1490 847//1103 2366//1519 +f 2351//2631 2369//2651 2391//2645 +f 2367//2652 2346//2552 2503//2653 +f 2146//284 2407//1898 2454//2494 +f 2368//438 2348//2634 1317//439 +f 2388//2643 2389//2644 2350//2640 +f 2333//2636 2392//2647 2369//2651 +f 2333//2636 2369//2651 2351//2631 +f 576//1540 2370//1420 2371//596 +f 2695//2621 2498//2475 2657//2474 +f 2297//2572 1529//2116 1530//2118 +f 2337//2185 2381//2638 2348//2634 +f 2368//438 2337//2185 2348//2634 +f 2348//2634 2381//2638 2357//2642 +f 2359//2649 2374//1500 2375//1499 +f 2376//1999 1577//2129 2078//1945 +f 1140//1739 2377//1738 1696//1687 +f 2378//2596 2379//2566 2400//2546 +f 2378//2596 2292//2613 2379//2566 +f 2095//2078 2401//2654 830//1463 +f 2414//2655 2347//2335 830//1463 +f 2401//2654 2414//2655 830//1463 +f 2414//2655 2355//2646 2347//2335 +f 2380//2587 2155//2499 2385//2650 +f 2155//2499 2380//2587 1330//1881 +f 29//40 1630//41 1629//2213 +f 2357//2642 2381//2638 2386//1760 +f 2388//2643 2489//2656 2389//2644 +f 2383//2657 2359//2649 2382//2648 +f 2383//2657 2374//1500 2359//2649 +f 2384//1399 2460//1120 1228//1397 +f 2417//2658 2757//2659 2699//2660 +f 2386//1760 2231//2556 2357//2642 +f 2387//2661 2489//2656 2388//2643 +f 2489//2656 2390//2662 2389//2644 +f 2389//2644 2390//2662 2392//2647 +f 2391//2645 2383//2657 2382//2648 +f 2221//1593 2251//2545 1681//2229 +f 2322//2567 2212//2538 2276//2606 +f 2451//2514 2753//2513 2758//2663 +f 2243//1993 2241//1992 2208//2522 +f 2417//2658 2380//2587 2757//2659 +f 2322//2567 2354//2609 2353//2629 +f 1494//2094 1452//2042 2286//2554 +f 1038//1662 1147//1703 1734//2131 +f 2357//2642 2387//2661 2388//2643 +f 2396//2664 2392//2647 2390//2662 +f 2392//2647 2396//2664 2369//2651 +f 2404//2665 2383//2657 2391//2645 +f 2393//2519 2474//2530 2394//2384 +f 1971//2267 2393//2519 2394//2384 +f 2395//1600 2327//1045 2326//274 +f 2396//2664 2404//2665 2369//2651 +f 2369//2651 2404//2665 2391//2645 +f 2262//1419 998//1279 835//595 +f 2397//53 2401//2654 2095//2078 +f 2231//2556 2387//2661 2357//2642 +f 1629//2213 1657//289 29//40 +f 2503//2653 2346//2552 2698//2641 +f 809//1411 2399//520 2277//2565 +f 2399//520 2400//2546 2277//2565 +f 1698//604 1208//603 1212//1783 +f 2426//2666 2414//2655 2401//2654 +f 2416//2667 2701//2668 2702//2669 +f 2355//2646 2701//2668 2699//2660 +f 2399//520 2378//2596 2400//2546 +f 2262//1419 835//595 2370//1420 +f 2338//77 1338//463 2121//2479 +f 2491//1765 2390//2662 2489//2656 +f 2491//1765 2396//2664 2390//2662 +f 2247//1353 2402//1346 2225//973 +f 2263//2549 2352//1347 2646//2392 +f 685//255 178//573 165//572 +f 2491//1765 2403//2505 2396//2664 +f 2403//2505 2404//2665 2396//2664 +f 2420//2670 2419//2671 2383//2657 +f 2383//2657 2419//2671 2374//1500 +f 576//1540 885//1556 2370//1420 +f 2426//2666 2401//2654 2703//2672 +f 359//850 1696//1687 2377//1738 +f 2404//2665 2420//2670 2383//2657 +f 2296//1404 2516//342 2692//2615 +f 1264//1264 2209//2110 2272//1262 +f 1770//2139 2047//2047 2619//2071 +f 12//52 2406//2673 2397//53 +f 2704//2674 2426//2666 2703//2672 +f 2380//2587 2417//2658 2407//1898 +f 2417//2658 2454//2494 2407//1898 +f 2161//1537 2453//2495 2408//1863 +f 745//412 2409//411 2410//425 +f 39//168 1374//170 1373//157 +f 2478//2048 2264//2560 2230//2528 +f 906//1581 2413//2675 2094//2037 +f 2413//2675 2406//2673 2094//2037 +f 2094//2037 2406//2673 12//52 +f 2454//2494 2705//2676 2408//1863 +f 2408//1863 2411//1875 1296//1873 +f 2420//2670 2404//2665 2403//2505 +f 2419//2671 138//476 2374//1500 +f 2476//1996 2323//2488 2324//1997 +f 2297//2572 1530//2118 2680//2581 +f 2422//1582 2430//2677 906//1581 +f 2430//2677 2413//2675 906//1581 +f 2430//2677 2706//2678 2413//2675 +f 2423//2679 2406//2673 2413//2675 +f 2415//2680 2707//2681 2708//2682 +f 2414//2655 2707//2681 2702//2669 +f 2417//2658 2709//2683 2454//2494 +f 467//761 1664//27 2220//1986 +f 2221//1593 2260//2580 2285//2586 +f 2406//2673 2710//2684 2704//2674 +f 2468//2685 2447//2686 2426//2666 +f 2415//2680 2497//2687 2416//2667 +f 2711//2688 2418//2689 2712//2690 +f 2417//2658 2712//2690 2709//2683 +f 2424//2691 2411//1875 2705//2676 +f 1227//1815 2429//1820 2403//2505 +f 2429//1820 2420//2670 2403//2505 +f 2443//508 138//476 2419//2671 +f 2713//2692 2468//2685 2710//2684 +f 2420//2670 2437//2693 2419//2671 +f 2437//2693 2443//508 2419//2671 +f 2222//1253 2241//1992 2232//1994 +f 1853//1587 2421//1613 2422//1582 +f 2421//1613 2430//2677 2422//1582 +f 2430//2677 2714//2694 2706//2678 +f 2426//2666 2428//2695 2708//2682 +f 2424//2691 2217//2543 2411//1875 +f 496//1032 744//1088 648//1044 +f 931//1591 2221//1593 2285//2586 +f 2425//1614 2421//1613 1853//1587 +f 2427//2696 2715//2697 2447//2686 +f 2427//2696 2428//2695 2715//2697 +f 2455//2698 2415//2680 2428//2695 +f 2716//2699 1915//2506 2717//2700 +f 2718//2701 2711//2688 2717//2700 +f 2418//2689 2436//2702 2424//2691 +f 2217//2543 2384//1399 1298//1762 +f 2455//2698 2428//2695 2427//2696 +f 2457//2703 2217//2543 2719//2704 +f 2305//2618 2299//1318 2298//1033 +f 2449//1679 2420//2670 2429//1820 +f 2340//1893 931//1591 2280//2589 +f 2720//2705 2432//2706 2714//2694 +f 2468//2685 2713//2692 2721//2707 +f 2432//2706 2722//2708 2721//2707 +f 2457//2703 2384//1399 2217//2543 +f 2433//519 2378//2596 2399//520 +f 2449//1679 2437//2693 2420//2670 +f 1355//1927 2340//1893 2271//2611 +f 2675//2561 2264//2560 2684//2595 +f 2314//2539 2434//972 2697//2624 +f 2444//2709 2432//2706 2720//2705 +f 2444//2709 2435//2710 2432//2706 +f 2435//2710 2431//2711 2722//2708 +f 2436//2702 2457//2703 2719//2704 +f 2457//2703 2458//1402 2384//1399 +f 376//879 1791//2040 1732//880 +f 29//40 2298//1033 28//117 +f 2437//2693 2441//2712 2443//508 +f 2443//508 2442//1157 139//477 +f 2228//2540 2448//2557 2438//1552 +f 2439//1421 2370//1420 2292//2613 +f 2440//2713 2430//2677 2421//1613 +f 2469//1171 2457//2703 2436//2702 +f 2321//448 1140//1739 1898//1943 +f 2332//2620 1596//2178 1316//1884 +f 2449//1679 2441//2712 2437//2693 +f 2441//2712 2442//1157 2443//508 +f 139//477 195//606 173//562 +f 2445//2714 2444//2709 2440//2713 +f 2445//2714 2446//2715 2444//2709 +f 2446//2715 2723//2716 2444//2709 +f 2492//2717 2435//2710 2444//2709 +f 2472//2718 2447//2686 2724//2719 +f 2288//2588 2275//1932 2287//815 +f 2448//2557 2363//1241 2438//1552 +f 2449//1679 2463//468 2441//2712 +f 2463//468 2442//1157 2441//2712 +f 1355//1927 2271//2611 902//1579 +f 2250//1995 2201//1592 2450//1926 +f 2466//913 2725//2720 2726//2721 +f 2456//1170 2458//1402 2457//2703 +f 2462//2583 2476//1996 2450//1926 +f 2451//2514 2758//2663 2674//2553 +f 2452//1162 263//730 2727//2722 +f 2453//2495 2454//2494 2408//1863 +f 2486//2723 2440//2713 2725//2720 +f 2486//2723 2445//2714 2440//2713 +f 2472//2718 2427//2696 2447//2686 +f 2427//2696 2495//2724 2455//2698 +f 2488//2725 2418//2689 2718//2701 +f 2488//2725 2477//2726 2418//2689 +f 2477//2726 2436//2702 2418//2689 +f 2456//1170 2457//2703 2469//1171 +f 2459//1851 2458//1402 2456//1170 +f 2458//1402 2459//1851 2460//1120 +f 2462//2583 2727//2722 2678//2578 +f 2694//2619 2372//1405 2656//2466 +f 2463//468 2464//605 2442//1157 +f 2434//972 769//974 2465//2520 +f 769//974 2306//1014 2465//2520 +f 1874//1612 2466//913 2726//2721 +f 2487//2727 2445//2714 2486//2723 +f 2467//2728 2492//2717 2723//2716 +f 2467//2728 2728//2729 2492//2717 +f 2472//2718 2724//2719 2431//2711 +f 2477//2726 2469//1171 2436//2702 +f 145//275 2399//520 809//1411 +f 2470//2551 2496//2049 2276//2606 +f 2636//2239 2729//2730 2696//2622 +f 2013//2360 901//1448 2649//2404 +f 2480//2731 2446//2715 2445//2714 +f 2480//2731 2467//2728 2446//2715 +f 2467//2728 2730//2732 2728//2729 +f 2481//2733 2427//2696 2472//2718 +f 2481//2733 2495//2724 2427//2696 +f 2473//440 856//375 138//476 +f 2378//2596 2439//1421 2292//2613 +f 263//730 1678//2226 2461//2577 +f 2445//2714 2487//2727 2480//2731 +f 2324//1997 2248//2487 2249//2117 +f 2322//2567 2478//2048 2354//2609 +f 2474//2530 2475//2527 2229//2526 +f 2476//1996 2250//1995 2450//1926 +f 2250//1995 2324//1997 2343//2575 +f 1609//2192 2467//2728 2480//2731 +f 1493//2090 2477//2726 2488//2725 +f 2461//2577 1678//2226 2476//1996 +f 2487//2727 2102//2449 2480//2731 +f 2626//2148 1206//2734 2730//2732 +f 1493//2090 2469//1171 2477//2726 +f 2354//2609 2478//2048 2230//2528 +f 2479//2591 2729//2730 2681//2592 +f 2306//1014 769//974 686//1012 +f 2191//2191 2480//2731 2102//2449 +f 2191//2191 1609//2192 2480//2731 +f 2472//2718 1724//2251 2481//2733 +f 2481//2733 1724//2251 2495//2724 +f 812//1423 1493//2090 2488//2725 +f 1474//1306 2466//913 1874//1612 +f 2487//2727 2731//2735 2102//2449 +f 986//1169 2469//1171 1493//2090 +f 2460//1120 2459//1851 797//1121 +f 2301//2600 2209//2110 2483//2532 +f 2218//1498 2462//2583 2484//1438 +f 2265//2533 2273//1403 2687//2601 +f 2279//2598 2732//2736 2533//915 +f 2487//2727 2733//2737 2731//2735 +f 2732//2736 2279//2598 2733//2737 +f 1724//2251 2245//2571 2495//2724 +f 812//1423 2488//2725 1915//2506 +f 2491//1765 2489//2656 2490//2738 +f 2489//2656 2387//2661 2490//2738 +f 2387//2661 2231//2556 2490//2738 +f 2231//2556 1187//401 2490//2738 +f 1187//401 1113//400 2490//2738 +f 1113//400 1513//1470 2490//2738 +f 1513//1470 2491//1765 2490//2738 +f 2471//2739 2431//2711 2492//2717 +f 2415//2680 2455//2698 2734//2740 +f 2471//2739 2472//2718 2431//2711 +f 1206//2734 2472//2718 2471//2739 +f 2493//1787 2735//2741 1206//2734 +f 2472//2718 2735//2741 2639//2252 +f 2373//2465 1704//2248 2493//1787 +f 2373//2465 2494//2742 1704//2248 +f 2117//2480 2494//2742 2373//2465 +f 2431//2711 2435//2710 2492//2717 +f 2245//2571 2202//2305 2736//2743 +f 2415//2680 2737//2744 2738//2745 +f 1817//2304 2202//2305 2245//2571 +f 2470//2551 2499//2511 2496//2049 +f 2737//2744 2734//2740 2736//2743 +f 1915//2506 2716//2699 2738//2745 +f 2502//2616 2739//2746 2498//2475 +f 1945//1422 1705//1325 2498//2475 +f 2665//2747 2740//2748 2741//2749 +f 2451//2514 2501//2750 2740//2748 +f 2502//2616 82//341 2759//2751 +f 82//341 2501//2750 2451//2514 +f 2266//2228 1679//2227 2243//1993 +f 2451//2514 2760//2752 2759//2751 +f 2483//2532 1945//1422 2739//2746 +f 2741//2749 2500//2753 2635//2238 +f 2742//2754 2503//2653 2743//2755 +f 2503//2653 2744//2756 2743//2755 +f 2745//2757 2503//2653 2742//2754 +f 2208//2522 2746//2758 2745//2757 +f 2398//2518 2293//2563 2136//2486 +f 2208//2522 2213//2524 2747//2759 +f 2746//2758 2208//2522 2747//2759 +f 2398//2518 2136//2486 2744//2756 +f 345//42 2504//44 1046//61 +f 2505//57 1042//1669 346//54 +f 2504//44 9//43 2749//141 +f 1685//72 2506//74 18//85 +f 2506//74 20//83 18//85 +f 24//49 1042//1669 2507//104 +f 2505//57 2507//104 1042//1669 +f 2508//110 1039//1309 1117//11 +f 828//119 2509//121 1126//56 +f 14//62 2510//173 1202//1692 +f 1183//336 1182//369 2512//194 +f 2511//195 2512//194 1182//369 +f 25//120 2507//104 2509//121 +f 2507//104 25//120 24//49 +f 483//279 2513//281 72//307 +f 2512//194 1138//1691 2514//337 +f 1138//1691 2512//194 17//73 +f 2479//2591 2516//342 2296//1404 +f 2516//342 2479//2591 2515//340 +f 63//273 2517//365 995//1163 +f 20//83 17//73 2518//370 +f 2511//195 2518//370 17//73 +f 2519//394 124//13 2//8 +f 318//67 2520//447 624//68 +f 2521//450 2135//449 115//1955 +f 2519//394 1075//472 124//13 +f 125//473 2522//475 1977//1173 +f 2523//559 164//558 165//572 +f 2524//601 194//600 692//956 +f 2525//621 1027//164 201//163 +f 2526//624 219//645 209//625 +f 218//644 2526//624 225//553 +f 221//359 2523//559 165//572 +f 247//654 2527//656 225//553 +f 2527//656 218//644 225//553 +f 2528//670 1260//661 1209//470 +f 2528//670 233//678 1260//661 +f 2529//680 235//672 208//614 +f 240//691 2529//680 234//671 +f 2530//801 322//737 295//765 +f 325//802 2530//801 295//765 +f 2531//809 1241//253 2295//252 +f 2517//365 347//830 995//1163 +f 2531//809 867//808 180//576 +f 1182//369 2532//887 93//111 +f 401//1305 2279//2598 2534//914 +f 2533//915 2534//914 2279//2598 +f 2535//918 283//320 194//600 +f 2536//931 415//898 374//818 +f 756//599 2535//918 194//600 +f 2536//931 374//818 422//916 +f 248//620 2537//963 1231//1798 +f 2538//1025 652//1233 794//1026 +f 720//1002 2539//1028 754//1040 +f 2540//1090 784//1129 596//1091 +f 586//1267 2542//1094 698//1064 +f 2542//1094 586//1267 2541//1093 +f 2543//1150 557//1113 566//1148 +f 2543//1150 531//1114 557//1113 +f 2544//1155 936//991 562//649 +f 576//1540 2546//1181 857//1108 +f 2546//1181 576//1540 2545//1180 +f 944//1191 2541//1093 586//1267 +f 570//1089 2547//1200 647//391 +f 2548//1215 561//1154 220//648 +f 390//433 2520//447 114//9 +f 2546//1181 535//1100 857//1108 +f 2542//1094 585//1076 730//1065 +f 2549//1255 647//391 495//393 +f 2550//1257 731//1055 492//1024 +f 2513//281 980//335 72//307 +f 2551//1271 631//421 577//1182 +f 2552//1274 495//393 2553//1275 +f 720//1002 2553//1275 495//393 +f 2554//1277 72//307 980//335 +f 570//1089 2549//1255 759//1160 +f 2552//1274 759//1160 2549//1255 +f 2555//1294 677//741 591//1036 +f 2534//914 2466//913 1474//1306 +f 638//399 2556//1311 2555//1294 +f 2556//1311 638//399 593//398 +f 2540//1090 570//1089 683//1127 +f 719//1143 2553//1275 720//1002 +f 2557//1315 2193//1646 1268//1316 +f 2558//1317 731//1055 577//1182 +f 2117//2480 2560//1326 2494//2742 +f 2560//1326 2117//2480 2559//1324 +f 2547//1200 547//1133 647//391 +f 2556//1311 2269//746 677//741 +f 2210//2535 2561//1349 2562//1348 +f 2561//1349 2210//2535 2485//2534 +f 925//1054 2551//1271 731//1055 +f 2550//1257 743//1053 731//1055 +f 2363//1241 756//599 2563//1363 +f 2524//601 2563//1363 756//599 +f 2247//1353 2563//1363 692//956 +f 2558//1317 652//1233 2538//1025 +f 652//1233 2558//1317 577//1182 +f 2564//1368 1209//470 1208//603 +f 2371//596 2545//1180 576//1540 +f 2565//1372 548//397 638//399 +f 647//391 2565//1372 638//399 +f 2539//1028 775//1366 754//1040 +f 2566//1418 481//998 891//1000 +f 2567//1435 866//1426 969//1084 +f 2566//1418 891//1000 824//1243 +f 865//82 2568//1514 651//193 +f 1184//1515 2569//1517 1419//1307 +f 2568//1514 874//1457 651//193 +f 2570//1527 2058//1526 902//1579 +f 2571//1575 2191//2191 2071//1576 +f 2572//1585 942//1558 913//1413 +f 231//674 2572//1585 913//1413 +f 2573//1608 182//583 2021//582 +f 2567//1435 519//1083 784//1129 +f 2574//1615 950//1590 975//1603 +f 2574//1615 713//658 955//1350 +f 2554//1277 979//774 664//308 +f 2575//1625 1184//1515 1039//1309 +f 987//10 1398//1624 2508//110 +f 2575//1625 2508//110 1398//1624 +f 2564//1368 238//669 1209//470 +f 2576//1633 7//36 2577//1634 +f 1180//38 2577//1634 7//36 +f 1221//1314 1557//2102 2557//1315 +f 2578//1647 2557//1315 1557//2102 +f 2579//1652 1076//1651 79//7 +f 2580//1653 1023//130 1166//59 +f 2581//1656 1096//89 1637//1358 +f 2518//370 1182//369 1037//264 +f 2582//1664 1040//1308 9//43 +f 992//1617 2583//1673 1044//45 +f 2584//1674 1158//1675 2583//1673 +f 1044//45 2583//1673 1158//1675 +f 746//1357 2581//1656 1637//1358 +f 2585//1694 1251//1693 1023//130 +f 2580//1653 1202//1692 2585//1694 +f 1202//1692 2580//1653 14//62 +f 93//111 2532//887 79//7 +f 2579//1652 79//7 2532//887 +f 1407//1714 2569//1517 1104//1516 +f 2586//1735 1155//1733 1127//1730 +f 1132//1719 2586//1735 1100//1572 +f 2582//1664 9//43 1133//55 +f 1183//336 2514//337 1147//1703 +f 2587//1737 1147//1703 2514//337 +f 48//226 2588//1743 995//1163 +f 1157//636 2584//1674 1126//56 +f 2577//1634 1180//38 1125//1369 +f 2589//1772 1364//1387 1400//310 +f 2590//1788 2493//1787 1206//2734 +f 2591//1795 1213//1375 1203//1374 +f 2592//1800 780//1376 1218//1801 +f 1180//38 2593//1818 472//712 +f 2537//963 472//712 2593//1818 +f 2592//1800 1251//1693 1203//1374 +f 2544//1155 562//649 220//648 +f 1202//1692 2510//173 1203//1374 +f 2591//1795 1203//1374 2510//173 +f 1755//698 2548//1215 220//648 +f 2548//1215 1755//698 2594//1889 +f 1340//1882 2595//1894 1323//1877 +f 2595//1894 1326//1847 1324//1887 +f 2596//1899 780//1376 1213//1375 +f 2597//1921 1624//2212 1651//1718 +f 1363//1859 2589//1772 1383//1430 +f 2598//1929 1624//2212 2597//1921 +f 1624//2212 2598//1929 1231//1798 +f 1028//184 1027//164 2598//1929 +f 2599//1933 2598//1929 1027//164 +f 2593//1818 1217//903 1231//1798 +f 2521//450 1394//1956 2321//448 +f 1410//1957 2522//475 1389//474 +f 1392//1962 2600//1966 115//1955 +f 2600//1966 1393//1965 1394//1956 +f 1394//1956 2601//1969 1391//1959 +f 2601//1969 1402//1968 1396//1964 +f 1393//1965 2602//1973 1394//1956 +f 2602//1973 1404//1972 1402//1968 +f 1411//1970 2603//1978 1393//1965 +f 1444//1977 1437//2015 2603//1978 +f 2604//1980 2603//1978 1437//2015 +f 2604//1980 1437//2015 1404//1972 +f 2605//1988 1411//1970 911//1583 +f 2605//1988 1444//1977 1411//1970 +f 2606//2013 1406//1979 2607//2014 +f 1404//1972 2607//2014 1406//1979 +f 1437//2015 2607//2014 1404//1972 +f 2606//2013 1426//2004 1406//1979 +f 2608//2027 1472//2012 1437//2015 +f 1444//1977 2608//2027 1437//2015 +f 2609//2028 1448//2034 2610//2029 +f 1439//2024 2610//2029 1448//2034 +f 2171//1960 2610//2029 1439//2024 +f 1465//2033 2609//2028 1390//1218 +f 1427//2023 2596//1899 1419//1307 +f 2478//2048 2611//2050 2264//2560 +f 1950//458 2612//2051 120//456 +f 2613//2053 120//456 2612//2051 +f 120//456 2614//2054 1460//457 +f 2614//2054 120//456 2613//2053 +f 2612//2051 1466//2061 1550//2052 +f 2614//2054 1495//2062 1460//457 +f 2615//2063 1471//1987 1460//457 +f 2616//2064 1508//2072 1467//2026 +f 1470//2096 2617//2065 1495//2062 +f 2615//2063 1495//2062 2617//2065 +f 1470//2096 1508//2072 2617//2065 +f 2616//2064 2617//2065 1508//2072 +f 2618//2070 1770//2139 2619//2071 +f 1770//2139 2618//2070 1474//1306 +f 1515//2079 2620//2080 1456//2031 +f 2620//2080 1218//1801 780//1376 +f 2193//1646 2621//2103 1820//2074 +f 2621//2103 2193//1646 2578//1647 +f 2622//2111 1325//1577 1945//1422 +f 2623//2114 1821//1632 1820//2074 +f 63//273 2588//1743 1537//201 +f 248//620 1231//1798 2525//621 +f 2599//1933 2525//621 1231//1798 +f 1640//2113 2576//1633 1821//1632 +f 2624//2133 1557//2102 1972//1775 +f 391//37 2624//2133 1455//1665 +f 1558//1468 2625//2144 1559//1954 +f 1205//1786 2590//1788 2627//2149 +f 2590//1788 1206//2734 2626//2148 +f 2627//2149 2626//2148 1609//2192 +f 1569//2156 2627//2149 1609//2192 +f 2494//2742 2628//2196 1704//2248 +f 2628//2196 2494//2742 2560//1326 +f 1591//2182 2629//2197 1905//2207 +f 2630//2211 1216//1797 1591//2182 +f 2630//2211 1624//2212 1216//1797 +f 1684//2245 1745//2160 2632//2219 +f 2631//2220 2632//2219 1745//2160 +f 2633//2230 1529//2116 2297//2572 +f 1828//2256 1684//2245 2634//2234 +f 2632//2219 2634//2234 1684//2245 +f 2496//2049 2635//2238 2611//2050 +f 2635//2238 2500//2753 2636//2239 +f 2611//2050 2636//2239 2264//2560 +f 1704//2248 2628//2196 1706//2249 +f 2637//2243 1706//2249 2628//2196 +f 1704//2248 2638//2250 1724//2251 +f 2639//2252 1724//2251 2472//2718 +f 1801//2244 2640//2261 1745//2160 +f 2631//2220 1745//2160 1716//2159 +f 1818//2257 2634//2234 1764//1991 +f 2640//2261 1789//2195 1745//2160 +f 2587//1737 1801//2244 1147//1703 +f 1640//2113 2621//2103 1557//2102 +f 2621//2103 1640//2113 2623//2114 +f 1994//214 2594//1889 1755//698 +f 2638//2250 1706//2249 2641//2299 +f 1817//2304 2641//2299 1706//2249 +f 2625//2144 1415//1494 1816//2006 +f 2642//2306 1686//2146 1949//2303 +f 645//435 2643//2346 1901//1254 +f 1706//2249 2637//2243 1915//2506 +f 2644//2356 1915//2506 2637//2243 +f 2644//2356 812//1423 1915//2506 +f 2642//2306 1982//2368 1842//2136 +f 2645//2381 1973//1269 1198//1780 +f 2226//1574 2646//2392 2571//1575 +f 2646//2392 2352//1347 2647//2393 +f 2571//1575 2647//2393 2191//2191 +f 1999//2044 2648//2402 2629//2197 +f 2648//2402 1999//2044 1829//2043 +f 2649//2404 2040//2403 2013//2360 +f 1918//2327 2648//2402 1829//2043 +f 2650//2433 1829//2043 1984//1888 +f 2058//1526 2651//2434 2046//1589 +f 2651//2434 2047//2047 2048//2429 +f 2652//2436 2002//2405 2050//2428 +f 2652//2436 2049//2435 2043//2420 +f 2048//2429 2653//2438 2040//2403 +f 2654//2439 2040//2403 2653//2438 +f 2040//2403 2654//2439 2001//2400 +f 2654//2439 2107//2437 2038//2424 +f 2650//2433 1984//1888 2056//2322 +f 2655//2454 1898//1943 1668//1936 +f 2656//2466 2373//2465 2493//1787 +f 2373//2465 2657//2474 2117//2480 +f 2658//2476 2117//2480 2657//2474 +f 2498//2475 2559//1324 2658//2476 +f 2559//1324 2498//2475 1705//1325 +f 2659//2482 2159//2483 2092//2463 +f 2321//448 2655//2454 2135//449 +f 2660//2489 2137//2490 2138//2462 +f 2137//2490 2659//2482 2138//2462 +f 2089//2326 2645//2381 2120//2351 +f 2147//1961 2660//2489 2150//2481 +f 2618//2070 401//1305 1474//1306 +f 2661//2503 2172//2498 2137//2490 +f 2171//1960 2661//2503 2147//1961 +f 2647//2393 1569//2156 2191//2191 +f 2662//2508 2206//2512 2663//2509 +f 2206//2512 2662//2508 2205//2510 +f 2207//2516 2761//2760 2499//2511 +f 2665//2747 2762//2761 2664//2762 +f 2238//2295 2666//2517 2448//2557 +f 2667//2521 2306//1014 2301//2600 +f 2483//2532 2622//2111 1945//1422 +f 2668//2536 2280//2589 2071//1576 +f 2669//2541 2257//2562 2213//2524 +f 2239//2507 2670//2542 2367//2652 +f 2670//2542 2239//2507 2663//2509 +f 2573//1608 2220//1986 1664//27 +f 2667//2521 2483//2532 2671//2544 +f 2483//2532 2667//2521 2301//2600 +f 2257//2562 2662//2508 2239//2507 +f 2662//2508 2257//2562 2672//2547 +f 2673//2550 2263//2549 2226//1574 +f 2670//2542 2346//2552 2367//2652 +f 2674//2553 2314//2539 2451//2514 +f 2666//2517 2233//1166 2362//1268 +f 2230//2528 2675//2561 2412//2385 +f 2676//2568 2242//2569 2214//2537 +f 2242//2569 2669//2541 2214//2537 +f 2244//1521 2672//2547 2257//2562 +f 2641//2299 1817//2304 2245//2571 +f 2297//2572 2677//2573 2258//2548 +f 2633//2230 2258//2548 1681//2229 +f 2678//2578 2476//1996 2462//2583 +f 2412//2385 2679//2582 2680//2581 +f 2679//2582 2412//2385 2265//2533 +f 2260//2580 2673//2550 2226//1574 +f 2501//2750 82//341 2681//2592 +f 2515//340 2681//2592 82//341 +f 2258//2548 2682//2593 2263//2549 +f 2682//2593 2258//2548 2677//2573 +f 2683//2594 2265//2533 2684//2595 +f 2265//2533 2683//2594 2273//1403 +f 809//1411 2643//2346 1739//1205 +f 2340//1893 2685//2597 2271//2611 +f 2686//2599 2271//2611 2685//2597 +f 2485//2534 2688//2602 1205//1786 +f 2688//2602 2485//2534 2687//2601 +f 2279//2598 2668//2536 2482//2467 +f 2668//2536 2279//2598 2689//2607 +f 2485//2534 1205//1786 2561//1349 +f 2690//2610 2561//1349 1205//1786 +f 2686//2599 2279//2598 401//1305 +f 2685//2597 2280//2589 2689//2607 +f 2280//2589 2685//2597 2340//1893 +f 2292//2613 2676//2568 2379//2566 +f 2691//2614 885//1556 2242//2569 +f 2296//1404 2693//2617 2372//1405 +f 2693//2617 2296//1404 2692//2615 +f 2679//2582 2210//2535 2297//2572 +f 2273//1403 2372//1405 2688//2602 +f 2694//2619 2688//2602 2372//1405 +f 2502//2616 2498//2475 2693//2617 +f 2695//2621 2693//2617 2498//2475 +f 2696//2622 2479//2591 2683//2594 +f 2273//1403 2683//2594 2756//2608 +f 2697//2624 2465//2520 2451//2514 +f 2671//2544 2483//2532 2760//2752 +f 2370//1420 2691//2614 2292//2613 +f 2570//1527 2271//2611 2405//1525 +f 2698//2641 2227//2529 2398//2518 +f 2263//2549 2682//2593 2352//1347 +f 2562//1348 2352//1347 2682//2593 +f 2690//2610 1205//1786 2750//2157 +f 2372//1405 2657//2474 2373//2465 +f 2657//2474 2372//1405 2695//2621 +f 2699//2660 2385//2650 2355//2646 +f 2207//2516 2253//2559 2761//2760 +f 2700//2763 2664//2762 2253//2559 +f 2503//2653 2698//2641 2398//2518 +f 2701//2668 2355//2646 2702//2669 +f 2414//2655 2702//2669 2355//2646 +f 2416//2667 2699//2660 2701//2668 +f 2699//2660 2416//2667 2417//2658 +f 2263//2549 2646//2392 2226//1574 +f 2703//2672 2401//2654 2397//53 +f 82//341 2502//2616 2516//342 +f 2692//2615 2516//342 2502//2616 +f 2619//2071 2047//2047 2405//1525 +f 2406//2673 2704//2674 2397//53 +f 2703//2672 2397//53 2704//2674 +f 2705//2676 2411//1875 2408//1863 +f 2680//2581 1530//2118 2412//2385 +f 2706//2678 2423//2679 2413//2675 +f 2707//2681 2414//2655 2708//2682 +f 2426//2666 2708//2682 2414//2655 +f 2415//2680 2416//2667 2707//2681 +f 2702//2669 2707//2681 2416//2667 +f 2709//2683 2424//2691 2454//2494 +f 2710//2684 2468//2685 2704//2674 +f 2426//2666 2704//2674 2468//2685 +f 2416//2667 2711//2688 2417//2658 +f 2712//2690 2417//2658 2711//2688 +f 2418//2689 2709//2683 2712//2690 +f 2709//2683 2418//2689 2424//2691 +f 2424//2691 2705//2676 2454//2494 +f 2423//2679 2713//2692 2406//2673 +f 2710//2684 2406//2673 2713//2692 +f 2714//2694 2432//2706 2706//2678 +f 2423//2679 2706//2678 2432//2706 +f 2708//2682 2428//2695 2415//2680 +f 2715//2697 2426//2666 2447//2686 +f 2715//2697 2428//2695 2426//2666 +f 2497//2687 2717//2700 2416//2667 +f 2717//2700 2497//2687 2716//2699 +f 1915//2506 2718//2701 2717//2700 +f 2718//2701 2418//2689 2711//2688 +f 2717//2700 2711//2688 2416//2667 +f 2719//2704 2217//2543 2424//2691 +f 2440//2713 2714//2694 2430//2677 +f 2714//2694 2440//2713 2720//2705 +f 2713//2692 2432//2706 2721//2707 +f 2432//2706 2713//2692 2423//2679 +f 2431//2711 2721//2707 2722//2708 +f 2721//2707 2431//2711 2468//2685 +f 2412//2385 2675//2561 2265//2533 +f 2684//2595 2265//2533 2675//2561 +f 2697//2624 2434//972 2465//2520 +f 2444//2709 2720//2705 2440//2713 +f 2435//2710 2722//2708 2432//2706 +f 2436//2702 2719//2704 2424//2691 +f 2723//2716 2492//2717 2444//2709 +f 2724//2719 2447//2686 2468//2685 +f 2725//2720 2421//1613 2726//2721 +f 2421//1613 2725//2720 2440//2713 +f 2253//2559 2228//2540 2700//2763 +f 2674//2553 2700//2763 2228//2540 +f 2452//1162 2727//2722 2462//2583 +f 2486//2723 2725//2720 2466//913 +f 2488//2725 2718//2701 1915//2506 +f 263//730 2461//2577 2727//2722 +f 2678//2578 2727//2722 2461//2577 +f 1205//1786 2694//2619 2493//1787 +f 2656//2466 2493//1787 2694//2619 +f 1874//1612 2726//2721 2421//1613 +f 2467//2728 2723//2716 2446//2715 +f 2728//2729 2471//2739 2492//2717 +f 2724//2719 2468//2685 2431//2711 +f 2264//2560 2636//2239 2696//2622 +f 2636//2239 2500//2753 2729//2730 +f 2696//2622 2729//2730 2479//2591 +f 2649//2404 901//1448 2046//1589 +f 1206//2734 2728//2729 2730//2732 +f 2728//2729 1206//2734 2471//2739 +f 1609//2192 2730//2732 2467//2728 +f 2730//2732 1609//2192 2626//2148 +f 2500//2753 2501//2750 2729//2730 +f 2681//2592 2729//2730 2501//2750 +f 2731//2735 2482//2467 2102//2449 +f 2265//2533 2687//2601 2485//2534 +f 2732//2736 2466//913 2533//915 +f 2466//913 2732//2736 2486//2723 +f 2279//2598 2482//2467 2733//2737 +f 2731//2735 2733//2737 2482//2467 +f 2486//2723 2732//2736 2487//2727 +f 2733//2737 2487//2727 2732//2736 +f 2734//2740 2455//2698 2495//2724 +f 2735//2741 2472//2718 1206//2734 +f 2493//1787 2639//2252 2735//2741 +f 2639//2252 2493//1787 1704//2248 +f 2245//2571 2736//2743 2495//2724 +f 2737//2744 1915//2506 2738//2745 +f 1915//2506 2737//2744 2202//2305 +f 2202//2305 2737//2744 2736//2743 +f 2737//2744 2415//2680 2734//2740 +f 2736//2743 2734//2740 2495//2724 +f 2497//2687 2415//2680 2716//2699 +f 2738//2745 2716//2699 2415//2680 +f 2739//2746 1945//1422 2498//2475 +f 2499//2511 2762//2761 2741//2749 +f 2665//2747 2754//2515 2740//2748 +f 2741//2749 2740//2748 2500//2753 +f 2740//2748 2501//2750 2500//2753 +f 2483//2532 2739//2746 2502//2616 +f 2499//2511 2741//2749 2496//2049 +f 2635//2238 2496//2049 2741//2749 +f 2243//1993 2742//2754 2266//2228 +f 2743//2755 2266//2228 2742//2754 +f 2744//2756 2136//2486 2743//2755 +f 2266//2228 2743//2755 2136//2486 +f 2208//2522 2742//2754 2243//1993 +f 2742//2754 2208//2522 2745//2757 +f 2367//2652 2745//2757 2746//2758 +f 2745//2757 2367//2652 2503//2653 +f 2747//2759 2213//2524 2239//2507 +f 2367//2652 2746//2758 2239//2507 +f 2747//2759 2239//2507 2746//2758 +f 2398//2518 2744//2756 2503//2653 +f 2748//50 24//49 25//120 +f 2749//141 32//140 14//62 +f 942//1558 2748//50 25//120 +f 2750//2157 1205//1786 2627//2149 +f 2105//2276 2751//2469 2107//2437 +f 2752//2470 2118//2472 2108//2445 +f 2751//2469 2118//2472 2752//2470 +f 2118//2472 2751//2469 2106//2140 +f 2664//2762 2753//2513 2665//2747 +f 2754//2515 2665//2747 2753//2513 +f 2484//1438 2755//2584 902//1579 +f 2755//2584 2450//1926 902//1579 +f 2756//2608 2296//1404 2273//1403 +f 2757//2659 2385//2650 2699//2660 +f 2753//2513 2700//2763 2758//2663 +f 2700//2763 2753//2513 2664//2762 +f 2757//2659 2380//2587 2385//2650 +f 2758//2663 2700//2763 2674//2553 +f 2759//2751 82//341 2451//2514 +f 2483//2532 2502//2616 2760//2752 +f 2759//2751 2760//2752 2502//2616 +f 2504//44 2749//141 14//62 +f 2761//2760 2664//2762 2499//2511 +f 2762//2761 2499//2511 2664//2762 +f 2756//2608 2683//2594 2479//2591 +f 2671//2544 2760//2752 2451//2514 +f 2690//2610 2750//2157 1569//2156 +f 2761//2760 2253//2559 2664//2762 +f 2762//2761 2665//2747 2741//2749 +f 2754//2515 2451//2514 2740//2748 +f 977//1207 2763//1352 809//1411 +f 145//275 2763//1352 64//276 diff --git a/L12/resources/normal_frag.glsl b/L12/resources/normal_frag.glsl new file mode 100644 index 0000000..fc76efb --- /dev/null +++ b/L12/resources/normal_frag.glsl @@ -0,0 +1,11 @@ +#version 120 + +varying vec3 vNor; + +void main() +{ + vec3 normal = normalize(vNor); + // Map normal in the range [-1, 1] to color in range [0, 1]; + vec3 color = 0.5*normal + 0.5; + gl_FragColor = vec4(color, 1.0); +} diff --git a/L12/resources/normal_vert.glsl b/L12/resources/normal_vert.glsl new file mode 100644 index 0000000..5ace583 --- /dev/null +++ b/L12/resources/normal_vert.glsl @@ -0,0 +1,12 @@ +#version 120 +attribute vec4 aPos; +attribute vec3 aNor; +uniform mat4 P; +uniform mat4 MV; +varying vec3 vNor; + +void main() +{ + gl_Position = P * MV * aPos; + vNor = (MV * vec4(aNor, 0.0)).xyz; +} diff --git a/L12/resources/simple_frag.glsl b/L12/resources/simple_frag.glsl new file mode 100644 index 0000000..013f708 --- /dev/null +++ b/L12/resources/simple_frag.glsl @@ -0,0 +1,8 @@ +#version 120 + +varying vec3 fragColor; + +void main() +{ + gl_FragColor = vec4(fragColor, 1.0); +} diff --git a/L12/resources/simple_vert.glsl b/L12/resources/simple_vert.glsl new file mode 100644 index 0000000..d6cc5b4 --- /dev/null +++ b/L12/resources/simple_vert.glsl @@ -0,0 +1,11 @@ +#version 120 + +uniform mat4 P; +uniform mat4 MV; +varying vec3 fragColor; + +void main() +{ + gl_Position = P * MV * gl_Vertex; + fragColor = gl_Color.rgb; +} diff --git a/L12/src/Camera.cpp b/L12/src/Camera.cpp new file mode 100644 index 0000000..bf3b9c6 --- /dev/null +++ b/L12/src/Camera.cpp @@ -0,0 +1,68 @@ +#define _USE_MATH_DEFINES +#include +#include +#include +#include "Camera.h" +#include "MatrixStack.h" + +Camera::Camera() : + aspect(1.0f), + fovy((float)(45.0*M_PI/180.0)), + znear(0.1f), + zfar(1000.0f), + rotations(0.0, 0.0), + translations(0.0f, 0.0f, -5.0f), + rfactor(0.01f), + tfactor(0.001f), + sfactor(0.005f) +{ +} + +Camera::~Camera() +{ +} + +void Camera::mouseClicked(float x, float y, bool shift, bool ctrl, bool alt) +{ + mousePrev.x = x; + mousePrev.y = y; + if(shift) { + state = Camera::TRANSLATE; + } else if(ctrl) { + state = Camera::SCALE; + } else { + state = Camera::ROTATE; + } +} + +void Camera::mouseMoved(float x, float y) +{ + glm::vec2 mouseCurr(x, y); + glm::vec2 dv = mouseCurr - mousePrev; + switch(state) { + case Camera::ROTATE: + rotations += rfactor * dv; + break; + case Camera::TRANSLATE: + translations.x -= translations.z * tfactor * dv.x; + translations.y += translations.z * tfactor * dv.y; + break; + case Camera::SCALE: + translations.z *= (1.0f - sfactor * dv.y); + break; + } + mousePrev = mouseCurr; +} + +void Camera::applyProjectionMatrix(std::shared_ptr P) const +{ + // Modify provided MatrixStack + P->multMatrix(glm::perspective(fovy, aspect, znear, zfar)); +} + +void Camera::applyViewMatrix(std::shared_ptr MV) const +{ + MV->translate(translations); + MV->rotate(rotations.y, glm::vec3(1.0f, 0.0f, 0.0f)); + MV->rotate(rotations.x, glm::vec3(0.0f, 1.0f, 0.0f)); +} diff --git a/L12/src/Camera.h b/L12/src/Camera.h new file mode 100644 index 0000000..3a1efef --- /dev/null +++ b/L12/src/Camera.h @@ -0,0 +1,50 @@ +#pragma once +#ifndef __Camera__ +#define __Camera__ + +#include + +#define GLM_FORCE_RADIANS +#include + +class MatrixStack; + +class Camera +{ +public: + enum { + ROTATE = 0, + TRANSLATE, + SCALE + }; + + Camera(); + virtual ~Camera(); + void setInitDistance(float z) { translations.z = -std::abs(z); } + void setAspect(float a) { aspect = a; }; + void setFovy(float f) { fovy = f; }; + void setZnear(float z) { znear = z; }; + void setZfar(float z) { zfar = z; }; + void setRotationFactor(float f) { rfactor = f; }; + void setTranslationFactor(float f) { tfactor = f; }; + void setScaleFactor(float f) { sfactor = f; }; + void mouseClicked(float x, float y, bool shift, bool ctrl, bool alt); + void mouseMoved(float x, float y); + void applyProjectionMatrix(std::shared_ptr P) const; + void applyViewMatrix(std::shared_ptr MV) const; + +private: + float aspect; + float fovy; + float znear; + float zfar; + glm::vec2 rotations; + glm::vec3 translations; + glm::vec2 mousePrev; + int state; + float rfactor; + float tfactor; + float sfactor; +}; + +#endif diff --git a/L12/src/GLSL.cpp b/L12/src/GLSL.cpp new file mode 100644 index 0000000..2969872 --- /dev/null +++ b/L12/src/GLSL.cpp @@ -0,0 +1,152 @@ +// +// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book +// Created by zwood on 2/21/10. +// Modified by sueda 10/15/15. +// + +#include "GLSL.h" +#include +#include +#include +#include + +using namespace std; + +namespace GLSL { + +const char * errorString(GLenum err) +{ + switch(err) { + case GL_NO_ERROR: + return "No error"; + case GL_INVALID_ENUM: + return "Invalid enum"; + case GL_INVALID_VALUE: + return "Invalid value"; + case GL_INVALID_OPERATION: + return "Invalid operation"; + case GL_STACK_OVERFLOW: + return "Stack overflow"; + case GL_STACK_UNDERFLOW: + return "Stack underflow"; + case GL_OUT_OF_MEMORY: + return "Out of memory"; + default: + return "No error"; + } +} + +void checkVersion() +{ + int major, minor; + major = minor = 0; + const char *verstr = (const char *)glGetString(GL_VERSION); + + if((verstr == NULL) || (sscanf(verstr, "%d.%d", &major, &minor) != 2)) { + printf("Invalid GL_VERSION format %d.%d\n", major, minor); + } + if(major < 2) { + printf("This shader example will not work due to the installed Opengl version, which is %d.%d.\n", major, minor); + exit(0); + } +} + +void checkError(const char *str) +{ + GLenum glErr = glGetError(); + if(glErr != GL_NO_ERROR) { + if(str) { + printf("%s: ", str); + } + printf("GL_ERROR = %s.\n", errorString(glErr)); + assert(false); + } +} + +void printShaderInfoLog(GLuint shader) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + GLchar *infoLog = 0; + + checkError(GET_FILE_LINE); + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength); + checkError(GET_FILE_LINE); + + if(infologLength > 0) { + infoLog = (GLchar *)malloc(infologLength); + if(infoLog == NULL) { + puts("ERROR: Could not allocate InfoLog buffer"); + exit(1); + } + glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog); + checkError(GET_FILE_LINE); + printf("Shader InfoLog:\n%s\n\n", infoLog); + free(infoLog); + } +} + +void printProgramInfoLog(GLuint program) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + GLchar *infoLog = 0; + + checkError(GET_FILE_LINE); + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infologLength); + checkError(GET_FILE_LINE); + + if(infologLength > 0) { + infoLog = (GLchar *)malloc(infologLength); + if(infoLog == NULL) { + puts("ERROR: Could not allocate InfoLog buffer"); + exit(1); + } + glGetProgramInfoLog(program, infologLength, &charsWritten, infoLog); + checkError(GET_FILE_LINE); + printf("Program InfoLog:\n%s\n\n", infoLog); + free(infoLog); + } +} + +char *textFileRead(const char *fn) +{ + FILE *fp; + char *content = NULL; + int count = 0; + if(fn != NULL) { + fp = fopen(fn,"rt"); + if(fp != NULL) { + fseek(fp, 0, SEEK_END); + count = (int)ftell(fp); + rewind(fp); + if(count > 0) { + content = (char *)malloc(sizeof(char) * (count+1)); + count = (int)fread(content,sizeof(char),count,fp); + content[count] = '\0'; + } + fclose(fp); + } else { + printf("error loading %s\n", fn); + } + } + return content; +} + +int textFileWrite(const char *fn, const char *s) +{ + FILE *fp; + int status = 0; + if(fn != NULL) { + fp = fopen(fn,"w"); + if(fp != NULL) { + if(fwrite(s,sizeof(char),strlen(s),fp) == strlen(s)) { + status = 1; + } + fclose(fp); + } + } + return(status); +} + +} diff --git a/L12/src/GLSL.h b/L12/src/GLSL.h new file mode 100644 index 0000000..f945fdd --- /dev/null +++ b/L12/src/GLSL.h @@ -0,0 +1,40 @@ +// +// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book +// Created by zwood on 2/21/10. +// Modified by sueda 10/15/15. +// + +#pragma once +#ifndef __GLSL__ +#define __GLSL__ + +#define GLEW_STATIC +#include + +/////////////////////////////////////////////////////////////////////////////// +// For printing out the current file and line number // +/////////////////////////////////////////////////////////////////////////////// +#include + +template +std::string NumberToString(T x) +{ + std::ostringstream ss; + ss << x; + return ss.str(); +} + +#define GET_FILE_LINE (std::string(__FILE__) + ":" + NumberToString(__LINE__)).c_str() +/////////////////////////////////////////////////////////////////////////////// + +namespace GLSL { + + void checkVersion(); + void checkError(const char *str = 0); + void printProgramInfoLog(GLuint program); + void printShaderInfoLog(GLuint shader); + int textFileWrite(const char *filename, const char *s); + char *textFileRead(const char *filename); +} + +#endif diff --git a/L12/src/MatrixStack.cpp b/L12/src/MatrixStack.cpp new file mode 100644 index 0000000..eaa6e6c --- /dev/null +++ b/L12/src/MatrixStack.cpp @@ -0,0 +1,114 @@ +#include "MatrixStack.h" + +#include +#include +#include + +#define GLM_FORCE_RADIANS +#include +#include + +using namespace std; + +MatrixStack::MatrixStack() +{ + mstack = make_shared< stack >(); + mstack->push(glm::mat4(1.0)); +} + +MatrixStack::~MatrixStack() +{ +} + +void MatrixStack::pushMatrix() +{ + const glm::mat4 &top = mstack->top(); + mstack->push(top); + assert(mstack->size() < 100); +} + +void MatrixStack::popMatrix() +{ + assert(!mstack->empty()); + mstack->pop(); + // There should always be one matrix left. + assert(!mstack->empty()); +} + +void MatrixStack::loadIdentity() +{ + glm::mat4 &top = mstack->top(); + top = glm::mat4(1.0); +} + +void MatrixStack::translate(const glm::vec3 &t) +{ + glm::mat4 &top = mstack->top(); + top *= glm::translate(t); +} + +void MatrixStack::translate(float x, float y, float z) +{ + translate(glm::vec3(x, y, z)); +} + +void MatrixStack::scale(const glm::vec3 &s) +{ + glm::mat4 &top = mstack->top(); + top *= glm::scale(s); +} + +void MatrixStack::scale(float x, float y, float z) +{ + scale(glm::vec3(x, y, z)); +} + +void MatrixStack::scale(float s) +{ + scale(glm::vec3(s, s, s)); +} + +void MatrixStack::rotate(float angle, const glm::vec3 &axis) +{ + glm::mat4 &top = mstack->top(); + top *= glm::rotate(angle, axis); +} + +void MatrixStack::rotate(float angle, float x, float y, float z) +{ + rotate(angle, glm::vec3(x, y, z)); +} + +void MatrixStack::multMatrix(const glm::mat4 &matrix) +{ + glm::mat4 &top = mstack->top(); + top *= matrix; +} + +const glm::mat4 &MatrixStack::topMatrix() const +{ + return mstack->top(); +} + +void MatrixStack::print(const glm::mat4 &mat, const char *name) +{ + if(name) { + printf("%s = [\n", name); + } + for(int i = 0; i < 4; ++i) { + for(int j = 0; j < 4; ++j) { + // mat[j] returns the jth column + printf("%- 5.2f ", mat[j][i]); + } + printf("\n"); + } + if(name) { + printf("];"); + } + printf("\n"); +} + +void MatrixStack::print(const char *name) const +{ + print(mstack->top(), name); +} diff --git a/L12/src/MatrixStack.h b/L12/src/MatrixStack.h new file mode 100644 index 0000000..66278ce --- /dev/null +++ b/L12/src/MatrixStack.h @@ -0,0 +1,50 @@ +#pragma once +#ifndef _MatrixStack_H_ +#define _MatrixStack_H_ + +#include +#include +#include + +class MatrixStack +{ +public: + MatrixStack(); + virtual ~MatrixStack(); + + // glPushMatrix(): Copies the current matrix and adds it to the top of the stack + void pushMatrix(); + // glPopMatrix(): Removes the top of the stack and sets the current matrix to be the matrix that is now on top + void popMatrix(); + + // glLoadIdentity(): Sets the top matrix to be the identity + void loadIdentity(); + // glMultMatrix(): Right multiplies the top matrix + void multMatrix(const glm::mat4 &matrix); + + // glTranslate(): Right multiplies the top matrix by a translation matrix + void translate(const glm::vec3 &trans); + void translate(float x, float y, float z); + // glScale(): Right multiplies the top matrix by a scaling matrix + void scale(const glm::vec3 &scale); + void scale(float x, float y, float z); + // glScale(): Right multiplies the top matrix by a scaling matrix + void scale(float size); + // glRotate(): Right multiplies the top matrix by a rotation matrix (angle in radians) + void rotate(float angle, const glm::vec3 &axis); + void rotate(float angle, float x, float y, float z); + + // glGet(GL_MODELVIEW_MATRIX): Gets the top matrix + const glm::mat4 &topMatrix() const; + + // Prints out the specified matrix + static void print(const glm::mat4 &mat, const char *name = 0); + // Prints out the top matrix + void print(const char *name = 0) const; + +private: + std::shared_ptr< std::stack > mstack; + +}; + +#endif diff --git a/L12/src/Program.cpp b/L12/src/Program.cpp new file mode 100644 index 0000000..1e85538 --- /dev/null +++ b/L12/src/Program.cpp @@ -0,0 +1,126 @@ +#include "Program.h" + +#include +#include + +#include "GLSL.h" + +using namespace std; + +Program::Program() : + vShaderName(""), + fShaderName(""), + pid(0), + verbose(true) +{ + +} + +Program::~Program() +{ + +} + +void Program::setShaderNames(const string &v, const string &f) +{ + vShaderName = v; + fShaderName = f; +} + +bool Program::init() +{ + GLint rc; + + // Create shader handles + GLuint VS = glCreateShader(GL_VERTEX_SHADER); + GLuint FS = glCreateShader(GL_FRAGMENT_SHADER); + + // Read shader sources + const char *vshader = GLSL::textFileRead(vShaderName.c_str()); + const char *fshader = GLSL::textFileRead(fShaderName.c_str()); + glShaderSource(VS, 1, &vshader, NULL); + glShaderSource(FS, 1, &fshader, NULL); + + // Compile vertex shader + glCompileShader(VS); + glGetShaderiv(VS, GL_COMPILE_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printShaderInfoLog(VS); + cout << "Error compiling vertex shader " << vShaderName << endl; + } + return false; + } + + // Compile fragment shader + glCompileShader(FS); + glGetShaderiv(FS, GL_COMPILE_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printShaderInfoLog(FS); + cout << "Error compiling fragment shader " << fShaderName << endl; + } + return false; + } + + // Create the program and link + pid = glCreateProgram(); + glAttachShader(pid, VS); + glAttachShader(pid, FS); + glLinkProgram(pid); + glGetProgramiv(pid, GL_LINK_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printProgramInfoLog(pid); + cout << "Error linking shaders " << vShaderName << " and " << fShaderName << endl; + } + return false; + } + + GLSL::checkError(GET_FILE_LINE); + return true; +} + +void Program::bind() +{ + glUseProgram(pid); +} + +void Program::unbind() +{ + glUseProgram(0); +} + +void Program::addAttribute(const string &name) +{ + attributes[name] = glGetAttribLocation(pid, name.c_str()); +} + +void Program::addUniform(const string &name) +{ + uniforms[name] = glGetUniformLocation(pid, name.c_str()); +} + +GLint Program::getAttribute(const string &name) const +{ + map::const_iterator attribute = attributes.find(name.c_str()); + if(attribute == attributes.end()) { + if(isVerbose()) { + cout << name << " is not an attribute variable" << endl; + } + return -1; + } + return attribute->second; +} + +GLint Program::getUniform(const string &name) const +{ + map::const_iterator uniform = uniforms.find(name.c_str()); + if(uniform == uniforms.end()) { + if(isVerbose()) { + cout << name << " is not a uniform variable" << endl; + } + return -1; + } + return uniform->second; +} diff --git a/L12/src/Program.h b/L12/src/Program.h new file mode 100644 index 0000000..51e58bb --- /dev/null +++ b/L12/src/Program.h @@ -0,0 +1,44 @@ +#pragma once +#ifndef __Program__ +#define __Program__ + +#include +#include + +#define GLEW_STATIC +#include + +/** + * An OpenGL Program (vertex and fragment shaders) + */ +class Program +{ +public: + Program(); + virtual ~Program(); + + void setVerbose(bool v) { verbose = v; } + bool isVerbose() const { return verbose; } + + void setShaderNames(const std::string &v, const std::string &f); + virtual bool init(); + virtual void bind(); + virtual void unbind(); + + void addAttribute(const std::string &name); + void addUniform(const std::string &name); + GLint getAttribute(const std::string &name) const; + GLint getUniform(const std::string &name) const; + +protected: + std::string vShaderName; + std::string fShaderName; + +private: + GLuint pid; + std::map attributes; + std::map uniforms; + bool verbose; +}; + +#endif diff --git a/L12/src/Shape.cpp b/L12/src/Shape.cpp new file mode 100644 index 0000000..27fe662 --- /dev/null +++ b/L12/src/Shape.cpp @@ -0,0 +1,166 @@ +#include "Shape.h" +#include +#include + +#include "GLSL.h" +#include "Program.h" + +#define GLM_FORCE_RADIANS +#include + +#define TINYOBJLOADER_IMPLEMENTATION +#include "tiny_obj_loader.h" + +using namespace std; + +Shape::Shape() : + posBufID(0), + norBufID(0), + texBufID(0) +{ +} + +Shape::~Shape() +{ +} + +void Shape::loadMesh(const string &meshName) +{ + // Load geometry + tinyobj::attrib_t attrib; + std::vector shapes; + std::vector materials; + string errStr; + bool rc = tinyobj::LoadObj(&attrib, &shapes, &materials, &errStr, meshName.c_str()); + if(!rc) { + cerr << errStr << endl; + } else { + // Some OBJ files have different indices for vertex positions, normals, + // and texture coordinates. For example, a cube corner vertex may have + // three different normals. Here, we are going to duplicate all such + // vertices. + // Loop over shapes + for(size_t s = 0; s < shapes.size(); s++) { + // Loop over faces (polygons) + size_t index_offset = 0; + for(size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) { + size_t fv = shapes[s].mesh.num_face_vertices[f]; + // Loop over vertices in the face. + for(size_t v = 0; v < fv; v++) { + // access to vertex + tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v]; + posBuf.push_back(attrib.vertices[3*idx.vertex_index+0]); + posBuf.push_back(attrib.vertices[3*idx.vertex_index+1]); + posBuf.push_back(attrib.vertices[3*idx.vertex_index+2]); + if(!attrib.normals.empty()) { + norBuf.push_back(attrib.normals[3*idx.normal_index+0]); + norBuf.push_back(attrib.normals[3*idx.normal_index+1]); + norBuf.push_back(attrib.normals[3*idx.normal_index+2]); + } + if(!attrib.texcoords.empty()) { + texBuf.push_back(attrib.texcoords[2*idx.texcoord_index+0]); + texBuf.push_back(attrib.texcoords[2*idx.texcoord_index+1]); + } + } + index_offset += fv; + // per-face material (IGNORE) + shapes[s].mesh.material_ids[f]; + } + } + } +} + +void Shape::fitToUnitBox() +{ + // Scale the vertex positions so that they fit within [-1, +1] in all three dimensions. + glm::vec3 vmin(posBuf[0], posBuf[1], posBuf[2]); + glm::vec3 vmax(posBuf[0], posBuf[1], posBuf[2]); + for(int i = 0; i < (int)posBuf.size(); i += 3) { + glm::vec3 v(posBuf[i], posBuf[i+1], posBuf[i+2]); + vmin.x = min(vmin.x, v.x); + vmin.y = min(vmin.y, v.y); + vmin.z = min(vmin.z, v.z); + vmax.x = max(vmax.x, v.x); + vmax.y = max(vmax.y, v.y); + vmax.z = max(vmax.z, v.z); + } + glm::vec3 center = 0.5f*(vmin + vmax); + glm::vec3 diff = vmax - vmin; + float diffmax = diff.x; + diffmax = max(diffmax, diff.y); + diffmax = max(diffmax, diff.z); + float scale = 1.0f / diffmax; + for(int i = 0; i < (int)posBuf.size(); i += 3) { + posBuf[i ] = (posBuf[i ] - center.x) * scale; + posBuf[i+1] = (posBuf[i+1] - center.y) * scale; + posBuf[i+2] = (posBuf[i+2] - center.z) * scale; + } +} + +void Shape::init() +{ + // Send the position array to the GPU + glGenBuffers(1, &posBufID); + glBindBuffer(GL_ARRAY_BUFFER, posBufID); + glBufferData(GL_ARRAY_BUFFER, posBuf.size()*sizeof(float), &posBuf[0], GL_STATIC_DRAW); + + // Send the normal array to the GPU + if(!norBuf.empty()) { + glGenBuffers(1, &norBufID); + glBindBuffer(GL_ARRAY_BUFFER, norBufID); + glBufferData(GL_ARRAY_BUFFER, norBuf.size()*sizeof(float), &norBuf[0], GL_STATIC_DRAW); + } + + // Send the texture array to the GPU + if(!texBuf.empty()) { + glGenBuffers(1, &texBufID); + glBindBuffer(GL_ARRAY_BUFFER, texBufID); + glBufferData(GL_ARRAY_BUFFER, texBuf.size()*sizeof(float), &texBuf[0], GL_STATIC_DRAW); + } + + // Unbind the arrays + glBindBuffer(GL_ARRAY_BUFFER, 0); + + GLSL::checkError(GET_FILE_LINE); +} + +void Shape::draw(const shared_ptr prog) const +{ + // Bind position buffer + int h_pos = prog->getAttribute("aPos"); + glEnableVertexAttribArray(h_pos); + glBindBuffer(GL_ARRAY_BUFFER, posBufID); + glVertexAttribPointer(h_pos, 3, GL_FLOAT, GL_FALSE, 0, (const void *)0); + + // Bind normal buffer + int h_nor = prog->getAttribute("aNor"); + if(h_nor != -1 && norBufID != 0) { + glEnableVertexAttribArray(h_nor); + glBindBuffer(GL_ARRAY_BUFFER, norBufID); + glVertexAttribPointer(h_nor, 3, GL_FLOAT, GL_FALSE, 0, (const void *)0); + } + + // Bind texcoords buffer + int h_tex = prog->getAttribute("aTex"); + if(h_tex != -1 && texBufID != 0) { + glEnableVertexAttribArray(h_tex); + glBindBuffer(GL_ARRAY_BUFFER, texBufID); + glVertexAttribPointer(h_tex, 2, GL_FLOAT, GL_FALSE, 0, (const void *)0); + } + + // Draw + int count = posBuf.size()/3; // number of indices to be rendered + glDrawArrays(GL_TRIANGLES, 0, count); + + // Disable and unbind + if(h_tex != -1) { + glDisableVertexAttribArray(h_tex); + } + if(h_nor != -1) { + glDisableVertexAttribArray(h_nor); + } + glDisableVertexAttribArray(h_pos); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + GLSL::checkError(GET_FILE_LINE); +} diff --git a/L12/src/Shape.h b/L12/src/Shape.h new file mode 100644 index 0000000..297476c --- /dev/null +++ b/L12/src/Shape.h @@ -0,0 +1,37 @@ +#pragma once +#ifndef _SHAPE_H_ +#define _SHAPE_H_ + +#include +#include +#include + +class Program; + +/** + * A shape defined by a list of triangles + * - posBuf should be of length 3*ntris + * - norBuf should be of length 3*ntris (if normals are available) + * - texBuf should be of length 2*ntris (if texture coords are available) + * posBufID, norBufID, and texBufID are OpenGL buffer identifiers. + */ +class Shape +{ +public: + Shape(); + virtual ~Shape(); + void loadMesh(const std::string &meshName); + void fitToUnitBox(); + void init(); + void draw(const std::shared_ptr prog) const; + +private: + std::vector posBuf; + std::vector norBuf; + std::vector texBuf; + unsigned posBufID; + unsigned norBufID; + unsigned texBufID; +}; + +#endif diff --git a/L12/src/main.cpp b/L12/src/main.cpp new file mode 100644 index 0000000..6f2f4e5 --- /dev/null +++ b/L12/src/main.cpp @@ -0,0 +1,299 @@ +#include +#include + +#define GLEW_STATIC +#include +#include + +#define GLM_FORCE_RADIANS +#include +#include +#include +#include + +#include "Camera.h" +#include "GLSL.h" +#include "Program.h" +#include "MatrixStack.h" +#include "Shape.h" + +using namespace std; + +bool keyToggles[256] = {false}; // only for English keyboards! + +GLFWwindow *window; // Main application window +string RESOURCE_DIR = ""; // Where the resources are loaded from + +shared_ptr progNormal; +shared_ptr progSimple; +shared_ptr camera; +shared_ptr bunny; + +static void error_callback(int error, const char *description) +{ + cerr << description << endl; +} + +static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) +{ + if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, GL_TRUE); + } +} + +static void char_callback(GLFWwindow *window, unsigned int key) +{ + keyToggles[key] = !keyToggles[key]; +} + +static void cursor_position_callback(GLFWwindow* window, double xmouse, double ymouse) +{ + int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT); + if(state == GLFW_PRESS) { + camera->mouseMoved(xmouse, ymouse); + } +} + +void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) +{ + // Get the current mouse position. + double xmouse, ymouse; + glfwGetCursorPos(window, &xmouse, &ymouse); + // Get current window size. + int width, height; + glfwGetWindowSize(window, &width, &height); + if(action == GLFW_PRESS) { + bool shift = mods & GLFW_MOD_SHIFT; + bool ctrl = mods & GLFW_MOD_CONTROL; + bool alt = mods & GLFW_MOD_ALT; + camera->mouseClicked(xmouse, ymouse, shift, ctrl, alt); + } +} + +static void init() +{ + GLSL::checkVersion(); + + // Set background color + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + // Enable z-buffer test + glEnable(GL_DEPTH_TEST); + + keyToggles[(unsigned)'c'] = true; + + // For drawing the bunny + progNormal = make_shared(); + progNormal->setShaderNames(RESOURCE_DIR + "normal_vert.glsl", RESOURCE_DIR + "normal_frag.glsl"); + progNormal->setVerbose(true); + progNormal->init(); + progNormal->addUniform("P"); + progNormal->addUniform("MV"); + progNormal->addAttribute("aPos"); + progNormal->addAttribute("aNor"); + progNormal->setVerbose(false); + + // For drawing the frames + progSimple = make_shared(); + progSimple->setShaderNames(RESOURCE_DIR + "simple_vert.glsl", RESOURCE_DIR + "simple_frag.glsl"); + progSimple->setVerbose(true); + progSimple->init(); + progSimple->addUniform("P"); + progSimple->addUniform("MV"); + progSimple->setVerbose(false); + + bunny = make_shared(); + bunny->loadMesh(RESOURCE_DIR + "bunny.obj"); + bunny->init(); + + camera = make_shared(); + + // Initialize time. + glfwSetTime(0.0); + + // If there were any OpenGL errors, this will print something. + // You can intersperse this line in your code to find the exact location + // of your OpenGL error. + GLSL::checkError(GET_FILE_LINE); +} + +void render() +{ + // Update time. + double t = glfwGetTime(); + + // Get current frame buffer size. + int width, height; + glfwGetFramebufferSize(window, &width, &height); + glViewport(0, 0, width, height); + + // Use the window size for camera. + glfwGetWindowSize(window, &width, &height); + camera->setAspect((float)width/(float)height); + + // Clear buffers + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if(keyToggles[(unsigned)'c']) { + glEnable(GL_CULL_FACE); + } else { + glDisable(GL_CULL_FACE); + } + if(keyToggles[(unsigned)'l']) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } else { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + + auto P = make_shared(); + auto MV = make_shared(); + + // Apply camera transforms + P->pushMatrix(); + camera->applyProjectionMatrix(P); + MV->pushMatrix(); + camera->applyViewMatrix(MV); + + // Draw origin frame + progSimple->bind(); + glUniformMatrix4fv(progSimple->getUniform("P"), 1, GL_FALSE, glm::value_ptr(P->topMatrix())); + glUniformMatrix4fv(progSimple->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix())); + glLineWidth(2); + glBegin(GL_LINES); + glColor3f(1, 0, 0); + glVertex3f(0, 0, 0); + glVertex3f(1, 0, 0); + glColor3f(0, 1, 0); + glVertex3f(0, 0, 0); + glVertex3f(0, 1, 0); + glColor3f(0, 0, 1); + glVertex3f(0, 0, 0); + glVertex3f(0, 0, 1); + glEnd(); + glLineWidth(1); + progSimple->unbind(); + GLSL::checkError(GET_FILE_LINE); + + // Draw the bunnies + progNormal->bind(); + // Send projection matrix (same for all bunnies) + glUniformMatrix4fv(progNormal->getUniform("P"), 1, GL_FALSE, glm::value_ptr(P->topMatrix())); + + // The center of the bunny is at (-0.2802, 0.932, 0.0851) + glm::vec3 center(-0.2802, 0.932, 0.0851); + + // Alpha is the linear interpolation parameter between 0 and 1 + float alpha = std::fmod(0.5f*t, 1.0f); + + // The axes of rotatio for the source and target bunnies + glm::vec3 axis0, axis1; + axis0.x = keyToggles[(unsigned)'x'] ? 1.0 : 0.0f; + axis0.y = keyToggles[(unsigned)'y'] ? 1.0 : 0.0f; + axis0.z = keyToggles[(unsigned)'z'] ? 1.0 : 0.0f; + axis1.x = keyToggles[(unsigned)'X'] ? 1.0 : 0.0f; + axis1.y = keyToggles[(unsigned)'Y'] ? 1.0 : 0.0f; + axis1.z = keyToggles[(unsigned)'Z'] ? 1.0 : 0.0f; + + glm::quat q0, q1; + if(glm::length(axis0) == 0) { + q0 = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); + } else { + axis0 = glm::normalize(axis0); + q0 = glm::angleAxis((float)(90.0f/180.0f*M_PI), axis0); + } + if(glm::length(axis1) == 0) { + q1 = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); + } else { + axis1 = glm::normalize(axis1); + q1 = glm::angleAxis((float)(90.0f/180.0f*M_PI), axis1); + } + + glm::vec3 p0(-1.0f, 0.0f, 0.0f); + glm::vec3 p1( 1.0f, 0.0f, 0.0f); + + // Draw the bunny three times: left, right, and interpolated. + // left: use p0 for position and q0 for orientation + // right: use p1 for position and q1 for orientation + + // LEFT + MV->pushMatrix(); + glUniformMatrix4fv(progNormal->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix())); + MV->popMatrix(); + bunny->draw(progNormal); + + // RIGHT + MV->pushMatrix(); + glUniformMatrix4fv(progNormal->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix())); + MV->popMatrix(); + bunny->draw(progNormal); + + // INTERPOLATED + MV->pushMatrix(); + glUniformMatrix4fv(progNormal->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix())); + MV->popMatrix(); + bunny->draw(progNormal); + + progNormal->unbind(); + + // Pop stacks + MV->popMatrix(); + P->popMatrix(); + + GLSL::checkError(GET_FILE_LINE); +} + +int main(int argc, char **argv) +{ + if(argc < 2) { + cout << "Please specify the resource directory." << endl; + return 0; + } + RESOURCE_DIR = argv[1] + string("/"); + + // Set error callback. + glfwSetErrorCallback(error_callback); + // Initialize the library. + if(!glfwInit()) { + return -1; + } + // Create a windowed mode window and its OpenGL context. + window = glfwCreateWindow(640, 480, "YOUR NAME", NULL, NULL); + if(!window) { + glfwTerminate(); + return -1; + } + // Make the window's context current. + glfwMakeContextCurrent(window); + // Initialize GLEW. + glewExperimental = true; + if(glewInit() != GLEW_OK) { + cerr << "Failed to initialize GLEW" << endl; + return -1; + } + glGetError(); // A bug in glewInit() causes an error that we can safely ignore. + cout << "OpenGL version: " << glGetString(GL_VERSION) << endl; + cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl; + // Set vsync. + glfwSwapInterval(1); + // Set keyboard callback. + glfwSetKeyCallback(window, key_callback); + // Set char callback. + glfwSetCharCallback(window, char_callback); + // Set cursor position callback. + glfwSetCursorPosCallback(window, cursor_position_callback); + // Set mouse button callback. + glfwSetMouseButtonCallback(window, mouse_button_callback); + // Initialize scene. + init(); + // Loop until the user closes the window. + while(!glfwWindowShouldClose(window)) { + // Render scene. + render(); + // Swap front and back buffers. + glfwSwapBuffers(window); + // Poll for and process events. + glfwPollEvents(); + } + // Quit program. + glfwDestroyWindow(window); + glfwTerminate(); + return 0; +} diff --git a/L12/src/tiny_obj_loader.h b/L12/src/tiny_obj_loader.h new file mode 100644 index 0000000..b975601 --- /dev/null +++ b/L12/src/tiny_obj_loader.h @@ -0,0 +1,1922 @@ +/* +The MIT License (MIT) + +Copyright (c) 2012-2016 Syoyo Fujita and many contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// +// version 1.0.3 : Support parsing texture options(#85) +// version 1.0.2 : Improve parsing speed by about a factor of 2 for large +// files(#105) +// version 1.0.1 : Fixes a shape is lost if obj ends with a 'usemtl'(#104) +// version 1.0.0 : Change data structure. Change license from BSD to MIT. +// + +// +// Use this in *one* .cc +// #define TINYOBJLOADER_IMPLEMENTATION +// #include "tiny_obj_loader.h" +// + +#ifndef TINY_OBJ_LOADER_H_ +#define TINY_OBJ_LOADER_H_ + +#include +#include +#include + +namespace tinyobj { + +// https://en.wikipedia.org/wiki/Wavefront_.obj_file says ... +// +// -blendu on | off # set horizontal texture blending +// (default on) +// -blendv on | off # set vertical texture blending +// (default on) +// -boost float_value # boost mip-map sharpness +// -mm base_value gain_value # modify texture map values (default +// 0 1) +// # base_value = brightness, +// gain_value = contrast +// -o u [v [w]] # Origin offset (default +// 0 0 0) +// -s u [v [w]] # Scale (default +// 1 1 1) +// -t u [v [w]] # Turbulence (default +// 0 0 0) +// -texres resolution # texture resolution to create +// -clamp on | off # only render texels in the clamped +// 0-1 range (default off) +// # When unclamped, textures are +// repeated across a surface, +// # when clamped, only texels which +// fall within the 0-1 +// # range are rendered. +// -bm mult_value # bump multiplier (for bump maps +// only) +// +// -imfchan r | g | b | m | l | z # specifies which channel of the file +// is used to +// # create a scalar or bump texture. +// r:red, g:green, +// # b:blue, m:matte, l:luminance, +// z:z-depth.. +// # (the default for bump is 'l' and +// for decal is 'm') +// bump -imfchan r bumpmap.tga # says to use the red channel of +// bumpmap.tga as the bumpmap +// +// For reflection maps... +// +// -type sphere # specifies a sphere for a "refl" +// reflection map +// -type cube_top | cube_bottom | # when using a cube map, the texture +// file for each +// cube_front | cube_back | # side of the cube is specified +// separately +// cube_left | cube_right + +typedef enum { + TEXTURE_TYPE_NONE, // default + TEXTURE_TYPE_SPHERE, + TEXTURE_TYPE_CUBE_TOP, + TEXTURE_TYPE_CUBE_BOTTOM, + TEXTURE_TYPE_CUBE_FRONT, + TEXTURE_TYPE_CUBE_BACK, + TEXTURE_TYPE_CUBE_LEFT, + TEXTURE_TYPE_CUBE_RIGHT +} texture_type_t; + +typedef struct { + texture_type_t type; // -type (default TEXTURE_TYPE_NONE) + float sharpness; // -boost (default 1.0?) + float brightness; // base_value in -mm option (default 0) + float contrast; // gain_value in -mm option (default 1) + float origin_offset[3]; // -o u [v [w]] (default 0 0 0) + float scale[3]; // -s u [v [w]] (default 1 1 1) + float turbulence[3]; // -t u [v [w]] (default 0 0 0) + // int texture_resolution; // -texres resolution (default = ?) TODO + bool clamp; // -clamp (default false) + char imfchan; // -imfchan (the default for bump is 'l' and for decal is 'm') + bool blendu; // -blendu (default on) + bool blendv; // -blendv (default on) + float bump_multiplier; // -bm (for bump maps only, default 1.0) +} texture_option_t; + +typedef struct { + std::string name; + + float ambient[3]; + float diffuse[3]; + float specular[3]; + float transmittance[3]; + float emission[3]; + float shininess; + float ior; // index of refraction + float dissolve; // 1 == opaque; 0 == fully transparent + // illumination model (see http://www.fileformat.info/format/material/) + int illum; + + int dummy; // Suppress padding warning. + + std::string ambient_texname; // map_Ka + std::string diffuse_texname; // map_Kd + std::string specular_texname; // map_Ks + std::string specular_highlight_texname; // map_Ns + std::string bump_texname; // map_bump, bump + std::string displacement_texname; // disp + std::string alpha_texname; // map_d + + texture_option_t ambient_texopt; + texture_option_t diffuse_texopt; + texture_option_t specular_texopt; + texture_option_t specular_highlight_texopt; + texture_option_t bump_texopt; + texture_option_t displacement_texopt; + texture_option_t alpha_texopt; + + // PBR extension + // http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr + float roughness; // [0, 1] default 0 + float metallic; // [0, 1] default 0 + float sheen; // [0, 1] default 0 + float clearcoat_thickness; // [0, 1] default 0 + float clearcoat_roughness; // [0, 1] default 0 + float anisotropy; // aniso. [0, 1] default 0 + float anisotropy_rotation; // anisor. [0, 1] default 0 + float pad0; + float pad1; + std::string roughness_texname; // map_Pr + std::string metallic_texname; // map_Pm + std::string sheen_texname; // map_Ps + std::string emissive_texname; // map_Ke + std::string normal_texname; // norm. For normal mapping. + + texture_option_t roughness_texopt; + texture_option_t metallic_texopt; + texture_option_t sheen_texopt; + texture_option_t emissive_texopt; + texture_option_t normal_texopt; + + int pad2; + + std::map unknown_parameter; +} material_t; + +typedef struct { + std::string name; + + std::vector intValues; + std::vector floatValues; + std::vector stringValues; +} tag_t; + +// Index struct to support different indices for vtx/normal/texcoord. +// -1 means not used. +typedef struct { + int vertex_index; + int normal_index; + int texcoord_index; +} index_t; + +typedef struct { + std::vector indices; + std::vector num_face_vertices; // The number of vertices per + // face. 3 = polygon, 4 = quad, + // ... Up to 255. + std::vector material_ids; // per-face material ID + std::vector tags; // SubD tag +} mesh_t; + +typedef struct { + std::string name; + mesh_t mesh; +} shape_t; + +// Vertex attributes +typedef struct { + std::vector vertices; // 'v' + std::vector normals; // 'vn' + std::vector texcoords; // 'vt' +} attrib_t; + +typedef struct callback_t_ { + // W is optional and set to 1 if there is no `w` item in `v` line + void (*vertex_cb)(void *user_data, float x, float y, float z, float w); + void (*normal_cb)(void *user_data, float x, float y, float z); + + // y and z are optional and set to 0 if there is no `y` and/or `z` item(s) in + // `vt` line. + void (*texcoord_cb)(void *user_data, float x, float y, float z); + + // called per 'f' line. num_indices is the number of face indices(e.g. 3 for + // triangle, 4 for quad) + // 0 will be passed for undefined index in index_t members. + void (*index_cb)(void *user_data, index_t *indices, int num_indices); + // `name` material name, `material_id` = the array index of material_t[]. -1 + // if + // a material not found in .mtl + void (*usemtl_cb)(void *user_data, const char *name, int material_id); + // `materials` = parsed material data. + void (*mtllib_cb)(void *user_data, const material_t *materials, + int num_materials); + // There may be multiple group names + void (*group_cb)(void *user_data, const char **names, int num_names); + void (*object_cb)(void *user_data, const char *name); + + callback_t_() + : vertex_cb(NULL), + normal_cb(NULL), + texcoord_cb(NULL), + index_cb(NULL), + usemtl_cb(NULL), + mtllib_cb(NULL), + group_cb(NULL), + object_cb(NULL) {} +} callback_t; + +class MaterialReader { + public: + MaterialReader() {} + virtual ~MaterialReader(); + + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, + std::string *err) = 0; +}; + +class MaterialFileReader : public MaterialReader { + public: + explicit MaterialFileReader(const std::string &mtl_basedir) + : m_mtlBaseDir(mtl_basedir) {} + virtual ~MaterialFileReader() {} + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, std::string *err); + + private: + std::string m_mtlBaseDir; +}; + +class MaterialStreamReader : public MaterialReader { + public: + explicit MaterialStreamReader(std::istream &inStream) + : m_inStream(inStream) {} + virtual ~MaterialStreamReader() {} + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, std::string *err); + + private: + std::istream &m_inStream; +}; + +/// Loads .obj from a file. +/// 'attrib', 'shapes' and 'materials' will be filled with parsed shape data +/// 'shapes' will be filled with parsed shape data +/// Returns true when loading .obj become success. +/// Returns warning and error message into `err` +/// 'mtl_basedir' is optional, and used for base directory for .mtl file. +/// In default(`NULL'), .mtl file is searched from an application's working directory. +/// 'triangulate' is optional, and used whether triangulate polygon face in .obj +/// or not. +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *err, + const char *filename, const char *mtl_basedir = NULL, + bool triangulate = true); + +/// Loads .obj from a file with custom user callback. +/// .mtl is loaded as usual and parsed material_t data will be passed to +/// `callback.mtllib_cb`. +/// Returns true when loading .obj/.mtl become success. +/// Returns warning and error message into `err` +/// See `examples/callback_api/` for how to use this function. +bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback, + void *user_data = NULL, + MaterialReader *readMatFn = NULL, + std::string *err = NULL); + +/// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve +/// std::istream for materials. +/// Returns true when loading .obj become success. +/// Returns warning and error message into `err` +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *err, + std::istream *inStream, MaterialReader *readMatFn = NULL, + bool triangulate = true); + +/// Loads materials into std::map +void LoadMtl(std::map *material_map, + std::vector *materials, std::istream *inStream); + +} // namespace tinyobj + +#ifdef TINYOBJLOADER_IMPLEMENTATION +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace tinyobj { + +MaterialReader::~MaterialReader() {} + +#define TINYOBJ_SSCANF_BUFFER_SIZE (4096) + +struct vertex_index { + int v_idx, vt_idx, vn_idx; + vertex_index() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} + explicit vertex_index(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {} + vertex_index(int vidx, int vtidx, int vnidx) + : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {} +}; + +struct tag_sizes { + tag_sizes() : num_ints(0), num_floats(0), num_strings(0) {} + int num_ints; + int num_floats; + int num_strings; +}; + +struct obj_shape { + std::vector v; + std::vector vn; + std::vector vt; +}; + +// See +// http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf +static std::istream &safeGetline(std::istream &is, std::string &t) { + t.clear(); + + // The characters in the stream are read one-by-one using a std::streambuf. + // That is faster than reading them one-by-one using the std::istream. + // Code that uses streambuf this way must be guarded by a sentry object. + // The sentry object performs various tasks, + // such as thread synchronization and updating the stream state. + + std::istream::sentry se(is, true); + std::streambuf *sb = is.rdbuf(); + + for (;;) { + int c = sb->sbumpc(); + switch (c) { + case '\n': + return is; + case '\r': + if (sb->sgetc() == '\n') sb->sbumpc(); + return is; + case EOF: + // Also handle the case when the last line has no line ending + if (t.empty()) is.setstate(std::ios::eofbit); + return is; + default: + t += static_cast(c); + } + } +} + +#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) +#define IS_DIGIT(x) \ + (static_cast((x) - '0') < static_cast(10)) +#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) + +// Make index zero-base, and also support relative index. +static inline int fixIndex(int idx, int n) { + if (idx > 0) return idx - 1; + if (idx == 0) return 0; + return n + idx; // negative value = relative +} + +static inline std::string parseString(const char **token) { + std::string s; + (*token) += strspn((*token), " \t"); + size_t e = strcspn((*token), " \t\r"); + s = std::string((*token), &(*token)[e]); + (*token) += e; + return s; +} + +static inline int parseInt(const char **token) { + (*token) += strspn((*token), " \t"); + int i = atoi((*token)); + (*token) += strcspn((*token), " \t\r"); + return i; +} + +// Tries to parse a floating point number located at s. +// +// s_end should be a location in the string where reading should absolutely +// stop. For example at the end of the string, to prevent buffer overflows. +// +// Parses the following EBNF grammar: +// sign = "+" | "-" ; +// END = ? anything not in digit ? +// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; +// integer = [sign] , digit , {digit} ; +// decimal = integer , ["." , integer] ; +// float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; +// +// Valid strings are for example: +// -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 +// +// If the parsing is a success, result is set to the parsed value and true +// is returned. +// +// The function is greedy and will parse until any of the following happens: +// - a non-conforming character is encountered. +// - s_end is reached. +// +// The following situations triggers a failure: +// - s >= s_end. +// - parse failure. +// +static bool tryParseDouble(const char *s, const char *s_end, double *result) { + if (s >= s_end) { + return false; + } + + double mantissa = 0.0; + // This exponent is base 2 rather than 10. + // However the exponent we parse is supposed to be one of ten, + // thus we must take care to convert the exponent/and or the + // mantissa to a * 2^E, where a is the mantissa and E is the + // exponent. + // To get the final double we will use ldexp, it requires the + // exponent to be in base 2. + int exponent = 0; + + // NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED + // TO JUMP OVER DEFINITIONS. + char sign = '+'; + char exp_sign = '+'; + char const *curr = s; + + // How many characters were read in a loop. + int read = 0; + // Tells whether a loop terminated due to reaching s_end. + bool end_not_reached = false; + + /* + BEGIN PARSING. + */ + + // Find out what sign we've got. + if (*curr == '+' || *curr == '-') { + sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + goto fail; + } + + // Read the integer part. + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + mantissa *= 10; + mantissa += static_cast(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + + // We must make sure we actually got something. + if (read == 0) goto fail; + // We allow numbers of form "#", "###" etc. + if (!end_not_reached) goto assemble; + + // Read the decimal part. + if (*curr == '.') { + curr++; + read = 1; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + static const double pow_lut[] = { + 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, + }; + const int lut_entries = sizeof pow_lut / sizeof pow_lut[0]; + + // NOTE: Don't use powf here, it will absolutely murder precision. + mantissa += static_cast(*curr - 0x30) * + (read < lut_entries ? pow_lut[read] : pow(10.0, -read)); + read++; + curr++; + end_not_reached = (curr != s_end); + } + } else if (*curr == 'e' || *curr == 'E') { + } else { + goto assemble; + } + + if (!end_not_reached) goto assemble; + + // Read the exponent part. + if (*curr == 'e' || *curr == 'E') { + curr++; + // Figure out if a sign is present and if it is. + end_not_reached = (curr != s_end); + if (end_not_reached && (*curr == '+' || *curr == '-')) { + exp_sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + // Empty E is not allowed. + goto fail; + } + + read = 0; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + exponent *= 10; + exponent += static_cast(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + exponent *= (exp_sign == '+' ? 1 : -1); + if (read == 0) goto fail; + } + +assemble: + *result = + (sign == '+' ? 1 : -1) * + (exponent ? ldexp(mantissa * pow(5.0, exponent), exponent) : mantissa); + return true; +fail: + return false; +} + +static inline float parseFloat(const char **token, double default_value = 0.0) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + double val = default_value; + tryParseDouble((*token), end, &val); + float f = static_cast(val); + (*token) = end; + return f; +} + +static inline void parseFloat2(float *x, float *y, const char **token, + const double default_x = 0.0, + const double default_y = 0.0) { + (*x) = parseFloat(token, default_x); + (*y) = parseFloat(token, default_y); +} + +static inline void parseFloat3(float *x, float *y, float *z, const char **token, + const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0) { + (*x) = parseFloat(token, default_x); + (*y) = parseFloat(token, default_y); + (*z) = parseFloat(token, default_z); +} + +static inline void parseV(float *x, float *y, float *z, float *w, + const char **token, const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0, + const double default_w = 1.0) { + (*x) = parseFloat(token, default_x); + (*y) = parseFloat(token, default_y); + (*z) = parseFloat(token, default_z); + (*w) = parseFloat(token, default_w); +} + +static inline bool parseOnOff(const char **token, bool default_value = true) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + + bool ret = default_value; + if ((0 == strncmp((*token), "on", 2))) { + ret = true; + } else if ((0 == strncmp((*token), "off", 3))) { + ret = false; + } + + (*token) = end; + return ret; +} + +static inline texture_type_t parseTextureType( + const char **token, texture_type_t default_value = TEXTURE_TYPE_NONE) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + texture_type_t ty = default_value; + + if ((0 == strncmp((*token), "cube_top", strlen("cube_top")))) { + ty = TEXTURE_TYPE_CUBE_TOP; + } else if ((0 == strncmp((*token), "cube_bottom", strlen("cube_bottom")))) { + ty = TEXTURE_TYPE_CUBE_BOTTOM; + } else if ((0 == strncmp((*token), "cube_left", strlen("cube_left")))) { + ty = TEXTURE_TYPE_CUBE_LEFT; + } else if ((0 == strncmp((*token), "cube_right", strlen("cube_right")))) { + ty = TEXTURE_TYPE_CUBE_RIGHT; + } else if ((0 == strncmp((*token), "cube_front", strlen("cube_front")))) { + ty = TEXTURE_TYPE_CUBE_FRONT; + } else if ((0 == strncmp((*token), "cube_back", strlen("cube_back")))) { + ty = TEXTURE_TYPE_CUBE_BACK; + } else if ((0 == strncmp((*token), "sphere", strlen("sphere")))) { + ty = TEXTURE_TYPE_SPHERE; + } + + (*token) = end; + return ty; +} + +static tag_sizes parseTagTriple(const char **token) { + tag_sizes ts; + + ts.num_ints = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return ts; + } + (*token)++; + + ts.num_floats = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return ts; + } + (*token)++; + + ts.num_strings = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r") + 1; + + return ts; +} + +// Parse triples with index offsets: i, i/j/k, i//k, i/j +static vertex_index parseTriple(const char **token, int vsize, int vnsize, + int vtsize) { + vertex_index vi(-1); + + vi.v_idx = fixIndex(atoi((*token)), vsize); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + (*token)++; + + // i//k + if ((*token)[0] == '/') { + (*token)++; + vi.vn_idx = fixIndex(atoi((*token)), vnsize); + (*token) += strcspn((*token), "/ \t\r"); + return vi; + } + + // i/j/k or i/j + vi.vt_idx = fixIndex(atoi((*token)), vtsize); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + + // i/j/k + (*token)++; // skip '/' + vi.vn_idx = fixIndex(atoi((*token)), vnsize); + (*token) += strcspn((*token), "/ \t\r"); + return vi; +} + +// Parse raw triples: i, i/j/k, i//k, i/j +static vertex_index parseRawTriple(const char **token) { + vertex_index vi(static_cast(0)); // 0 is an invalid index in OBJ + + vi.v_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + (*token)++; + + // i//k + if ((*token)[0] == '/') { + (*token)++; + vi.vn_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + return vi; + } + + // i/j/k or i/j + vi.vt_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + + // i/j/k + (*token)++; // skip '/' + vi.vn_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + return vi; +} + +static bool ParseTextureNameAndOption(std::string *texname, + texture_option_t *texopt, + const char *linebuf, const bool is_bump) { + // @todo { write more robust lexer and parser. } + bool found_texname = false; + std::string texture_name; + + // Fill with default value for texopt. + if (is_bump) { + texopt->imfchan = 'l'; + } else { + texopt->imfchan = 'm'; + } + texopt->bump_multiplier = 1.0f; + texopt->clamp = false; + texopt->blendu = true; + texopt->blendv = true; + texopt->sharpness = 1.0f; + texopt->brightness = 0.0f; + texopt->contrast = 1.0f; + texopt->origin_offset[0] = 0.0f; + texopt->origin_offset[1] = 0.0f; + texopt->origin_offset[2] = 0.0f; + texopt->scale[0] = 1.0f; + texopt->scale[1] = 1.0f; + texopt->scale[2] = 1.0f; + texopt->turbulence[0] = 0.0f; + texopt->turbulence[1] = 0.0f; + texopt->turbulence[2] = 0.0f; + texopt->type = TEXTURE_TYPE_NONE; + + const char *token = linebuf; // Assume line ends with NULL + + while (!IS_NEW_LINE((*token))) { + if ((0 == strncmp(token, "-blendu", 7)) && IS_SPACE((token[7]))) { + token += 8; + texopt->blendu = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-blendv", 7)) && IS_SPACE((token[7]))) { + token += 8; + texopt->blendv = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-clamp", 6)) && IS_SPACE((token[6]))) { + token += 7; + texopt->clamp = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-boost", 6)) && IS_SPACE((token[6]))) { + token += 7; + texopt->sharpness = parseFloat(&token, 1.0); + } else if ((0 == strncmp(token, "-bm", 3)) && IS_SPACE((token[3]))) { + token += 4; + texopt->bump_multiplier = parseFloat(&token, 1.0); + } else if ((0 == strncmp(token, "-o", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseFloat3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]), + &(texopt->origin_offset[2]), &token); + } else if ((0 == strncmp(token, "-s", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseFloat3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]), + &token, 1.0, 1.0, 1.0); + } else if ((0 == strncmp(token, "-t", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseFloat3(&(texopt->turbulence[0]), &(texopt->turbulence[1]), + &(texopt->turbulence[2]), &token); + } else if ((0 == strncmp(token, "-type", 5)) && IS_SPACE((token[5]))) { + token += 5; + texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE); + } else if ((0 == strncmp(token, "-imfchan", 8)) && IS_SPACE((token[8]))) { + token += 9; + token += strspn(token, " \t"); + const char *end = token + strcspn(token, " \t\r"); + if ((end - token) == 1) { // Assume one char for -imfchan + texopt->imfchan = (*token); + } + token = end; + } else if ((0 == strncmp(token, "-mm", 3)) && IS_SPACE((token[3]))) { + token += 4; + parseFloat2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0); + } else { + // Assume texture filename + token += strspn(token, " \t"); // skip space + size_t len = strcspn(token, " \t\r"); // untile next space + texture_name = std::string(token, token + len); + token += len; + + token += strspn(token, " \t"); // skip space + + found_texname = true; + } + } + + if (found_texname) { + (*texname) = texture_name; + return true; + } else { + return false; + } +} + +static void InitMaterial(material_t *material) { + material->name = ""; + material->ambient_texname = ""; + material->diffuse_texname = ""; + material->specular_texname = ""; + material->specular_highlight_texname = ""; + material->bump_texname = ""; + material->displacement_texname = ""; + material->alpha_texname = ""; + for (int i = 0; i < 3; i++) { + material->ambient[i] = 0.f; + material->diffuse[i] = 0.f; + material->specular[i] = 0.f; + material->transmittance[i] = 0.f; + material->emission[i] = 0.f; + } + material->illum = 0; + material->dissolve = 1.f; + material->shininess = 1.f; + material->ior = 1.f; + + material->roughness = 0.f; + material->metallic = 0.f; + material->sheen = 0.f; + material->clearcoat_thickness = 0.f; + material->clearcoat_roughness = 0.f; + material->anisotropy_rotation = 0.f; + material->anisotropy = 0.f; + material->roughness_texname = ""; + material->metallic_texname = ""; + material->sheen_texname = ""; + material->emissive_texname = ""; + material->normal_texname = ""; + + material->unknown_parameter.clear(); +} + +static bool exportFaceGroupToShape( + shape_t *shape, const std::vector > &faceGroup, + const std::vector &tags, const int material_id, + const std::string &name, bool triangulate) { + if (faceGroup.empty()) { + return false; + } + + // Flatten vertices and indices + for (size_t i = 0; i < faceGroup.size(); i++) { + const std::vector &face = faceGroup[i]; + + vertex_index i0 = face[0]; + vertex_index i1(-1); + vertex_index i2 = face[1]; + + size_t npolys = face.size(); + + if (triangulate) { + // Polygon -> triangle fan conversion + for (size_t k = 2; k < npolys; k++) { + i1 = i2; + i2 = face[k]; + + index_t idx0, idx1, idx2; + idx0.vertex_index = i0.v_idx; + idx0.normal_index = i0.vn_idx; + idx0.texcoord_index = i0.vt_idx; + idx1.vertex_index = i1.v_idx; + idx1.normal_index = i1.vn_idx; + idx1.texcoord_index = i1.vt_idx; + idx2.vertex_index = i2.v_idx; + idx2.normal_index = i2.vn_idx; + idx2.texcoord_index = i2.vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + } + } else { + for (size_t k = 0; k < npolys; k++) { + index_t idx; + idx.vertex_index = face[k].v_idx; + idx.normal_index = face[k].vn_idx; + idx.texcoord_index = face[k].vt_idx; + shape->mesh.indices.push_back(idx); + } + + shape->mesh.num_face_vertices.push_back( + static_cast(npolys)); + shape->mesh.material_ids.push_back(material_id); // per face + } + } + + shape->name = name; + shape->mesh.tags = tags; + + return true; +} + +void LoadMtl(std::map *material_map, + std::vector *materials, std::istream *inStream) { + // Create a default material anyway. + material_t material; + InitMaterial(&material); + + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + + // Trim trailing whitespace. + if (linebuf.size() > 0) { + linebuf = linebuf.substr(0, linebuf.find_last_not_of(" \t") + 1); + } + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // new mtl + if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) { + // flush previous material. + if (!material.name.empty()) { + material_map->insert(std::pair( + material.name, static_cast(materials->size()))); + materials->push_back(material); + } + + // initial temporary material + InitMaterial(&material); + + // set new mtl name + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + material.name = namebuf; + continue; + } + + // ambient + if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.ambient[0] = r; + material.ambient[1] = g; + material.ambient[2] = b; + continue; + } + + // diffuse + if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.diffuse[0] = r; + material.diffuse[1] = g; + material.diffuse[2] = b; + continue; + } + + // specular + if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.specular[0] = r; + material.specular[1] = g; + material.specular[2] = b; + continue; + } + + // transmittance + if ((token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) || + (token[0] == 'T' && token[1] == 'f' && IS_SPACE((token[2])))) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.transmittance[0] = r; + material.transmittance[1] = g; + material.transmittance[2] = b; + continue; + } + + // ior(index of refraction) + if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) { + token += 2; + material.ior = parseFloat(&token); + continue; + } + + // emission + if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.emission[0] = r; + material.emission[1] = g; + material.emission[2] = b; + continue; + } + + // shininess + if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.shininess = parseFloat(&token); + continue; + } + + // illum model + if (0 == strncmp(token, "illum", 5) && IS_SPACE(token[5])) { + token += 6; + material.illum = parseInt(&token); + continue; + } + + // dissolve + if ((token[0] == 'd' && IS_SPACE(token[1]))) { + token += 1; + material.dissolve = parseFloat(&token); + continue; + } + if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + // Invert value of Tr(assume Tr is in range [0, 1]) + material.dissolve = 1.0f - parseFloat(&token); + continue; + } + + // PBR: roughness + if (token[0] == 'P' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + material.roughness = parseFloat(&token); + continue; + } + + // PBR: metallic + if (token[0] == 'P' && token[1] == 'm' && IS_SPACE(token[2])) { + token += 2; + material.metallic = parseFloat(&token); + continue; + } + + // PBR: sheen + if (token[0] == 'P' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.sheen = parseFloat(&token); + continue; + } + + // PBR: clearcoat thickness + if (token[0] == 'P' && token[1] == 'c' && IS_SPACE(token[2])) { + token += 2; + material.clearcoat_thickness = parseFloat(&token); + continue; + } + + // PBR: clearcoat roughness + if ((0 == strncmp(token, "Pcr", 3)) && IS_SPACE(token[3])) { + token += 4; + material.clearcoat_roughness = parseFloat(&token); + continue; + } + + // PBR: anisotropy + if ((0 == strncmp(token, "aniso", 5)) && IS_SPACE(token[5])) { + token += 6; + material.anisotropy = parseFloat(&token); + continue; + } + + // PBR: anisotropy rotation + if ((0 == strncmp(token, "anisor", 6)) && IS_SPACE(token[6])) { + token += 7; + material.anisotropy_rotation = parseFloat(&token); + continue; + } + + // ambient texture + if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.ambient_texname), + &(material.ambient_texopt), token, + /* is_bump */ false); + continue; + } + + // diffuse texture + if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.diffuse_texname), + &(material.diffuse_texopt), token, + /* is_bump */ false); + continue; + } + + // specular texture + if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.specular_texname), + &(material.specular_texopt), token, + /* is_bump */ false); + continue; + } + + // specular highlight texture + if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.specular_highlight_texname), + &(material.specular_highlight_texopt), token, + /* is_bump */ false); + continue; + } + + // bump texture + if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) { + token += 9; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token, + /* is_bump */ true); + continue; + } + + // bump texture + if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token, + /* is_bump */ true); + continue; + } + + // alpha texture + if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) { + token += 6; + material.alpha_texname = token; + ParseTextureNameAndOption(&(material.alpha_texname), + &(material.alpha_texopt), token, + /* is_bump */ false); + continue; + } + + // displacement texture + if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.displacement_texname), + &(material.displacement_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: roughness texture + if ((0 == strncmp(token, "map_Pr", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.roughness_texname), + &(material.roughness_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: metallic texture + if ((0 == strncmp(token, "map_Pm", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.metallic_texname), + &(material.metallic_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: sheen texture + if ((0 == strncmp(token, "map_Ps", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.sheen_texname), + &(material.sheen_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: emissive texture + if ((0 == strncmp(token, "map_Ke", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.emissive_texname), + &(material.emissive_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: normal map texture + if ((0 == strncmp(token, "norm", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption( + &(material.normal_texname), &(material.normal_texopt), token, + /* is_bump */ false); // @fixme { is_bump will be true? } + continue; + } + + // unknown parameter + const char *_space = strchr(token, ' '); + if (!_space) { + _space = strchr(token, '\t'); + } + if (_space) { + std::ptrdiff_t len = _space - token; + std::string key(token, static_cast(len)); + std::string value = _space + 1; + material.unknown_parameter.insert( + std::pair(key, value)); + } + } + // flush last material. + material_map->insert(std::pair( + material.name, static_cast(materials->size()))); + materials->push_back(material); +} + +bool MaterialFileReader::operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, + std::string *err) { + std::string filepath; + + if (!m_mtlBaseDir.empty()) { + filepath = std::string(m_mtlBaseDir) + matId; + } else { + filepath = matId; + } + + std::ifstream matIStream(filepath.c_str()); + LoadMtl(matMap, materials, &matIStream); + if (!matIStream) { + std::stringstream ss; + ss << "WARN: Material file [ " << filepath + << " ] not found. Created a default material."; + if (err) { + (*err) += ss.str(); + } + } + return true; +} + +bool MaterialStreamReader::operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, + std::string *err) { + (void)matId; + LoadMtl(matMap, materials, &m_inStream); + if (!m_inStream) { + std::stringstream ss; + ss << "WARN: Material stream in error state." + << " Created a default material."; + if (err) { + (*err) += ss.str(); + } + } + return true; +} + +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *err, + const char *filename, const char *mtl_basedir, + bool trianglulate) { + attrib->vertices.clear(); + attrib->normals.clear(); + attrib->texcoords.clear(); + shapes->clear(); + + std::stringstream errss; + + std::ifstream ifs(filename); + if (!ifs) { + errss << "Cannot open file [" << filename << "]" << std::endl; + if (err) { + (*err) = errss.str(); + } + return false; + } + + std::string baseDir; + if (mtl_basedir) { + baseDir = mtl_basedir; + } + MaterialFileReader matFileReader(baseDir); + + return LoadObj(attrib, shapes, materials, err, &ifs, &matFileReader, + trianglulate); +} + +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *err, + std::istream *inStream, MaterialReader *readMatFn /*= NULL*/, + bool triangulate) { + std::stringstream errss; + + std::vector v; + std::vector vn; + std::vector vt; + std::vector tags; + std::vector > faceGroup; + std::string name; + + // material + std::map material_map; + int material = -1; + + shape_t shape; + + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // vertex + if (token[0] == 'v' && IS_SPACE((token[1]))) { + token += 2; + float x, y, z; + parseFloat3(&x, &y, &z, &token); + v.push_back(x); + v.push_back(y); + v.push_back(z); + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + token += 3; + float x, y, z; + parseFloat3(&x, &y, &z, &token); + vn.push_back(x); + vn.push_back(y); + vn.push_back(z); + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + token += 3; + float x, y; + parseFloat2(&x, &y, &token); + vt.push_back(x); + vt.push_back(y); + continue; + } + + // face + if (token[0] == 'f' && IS_SPACE((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + std::vector face; + face.reserve(3); + + while (!IS_NEW_LINE(token[0])) { + vertex_index vi = parseTriple(&token, static_cast(v.size() / 3), + static_cast(vn.size() / 3), + static_cast(vt.size() / 2)); + face.push_back(vi); + size_t n = strspn(token, " \t\r"); + token += n; + } + + // replace with emplace_back + std::move on C++11 + faceGroup.push_back(std::vector()); + faceGroup[faceGroup.size() - 1].swap(face); + + continue; + } + + // use mtl + if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + + int newMaterialId = -1; + if (material_map.find(namebuf) != material_map.end()) { + newMaterialId = material_map[namebuf]; + } else { + // { error!! material not found } + } + + if (newMaterialId != material) { + // Create per-face material. Thus we don't add `shape` to `shapes` at + // this time. + // just clear `faceGroup` after `exportFaceGroupToShape()` call. + exportFaceGroupToShape(&shape, faceGroup, tags, material, name, + triangulate); + faceGroup.clear(); + material = newMaterialId; + } + + continue; + } + + // load mtl + if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + + std::string err_mtl; + bool ok = (*readMatFn)(namebuf, materials, &material_map, &err_mtl); + if (err) { + (*err) += err_mtl; + } + + if (!ok) { + faceGroup.clear(); // for safety + return false; + } + } + + continue; + } + + // group name + if (token[0] == 'g' && IS_SPACE((token[1]))) { + // flush previous face group. + bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, + triangulate); + if (ret) { + shapes->push_back(shape); + } + + shape = shape_t(); + + // material = -1; + faceGroup.clear(); + + std::vector names; + names.reserve(2); + + while (!IS_NEW_LINE(token[0])) { + std::string str = parseString(&token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + assert(names.size() > 0); + + // names[0] must be 'g', so skip the 0th element. + if (names.size() > 1) { + name = names[1]; + } else { + name = ""; + } + + continue; + } + + // object name + if (token[0] == 'o' && IS_SPACE((token[1]))) { + // flush previous face group. + bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, + triangulate); + if (ret) { + shapes->push_back(shape); + } + + // material = -1; + faceGroup.clear(); + shape = shape_t(); + + // @todo { multiple object name? } + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 2; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + name = std::string(namebuf); + + continue; + } + + if (token[0] == 't' && IS_SPACE(token[1])) { + tag_t tag; + + char namebuf[4096]; + token += 2; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + tag.name = std::string(namebuf); + + token += tag.name.size() + 1; + + tag_sizes ts = parseTagTriple(&token); + + tag.intValues.resize(static_cast(ts.num_ints)); + + for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { + tag.intValues[i] = atoi(token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.floatValues.resize(static_cast(ts.num_floats)); + for (size_t i = 0; i < static_cast(ts.num_floats); ++i) { + tag.floatValues[i] = parseFloat(&token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.stringValues.resize(static_cast(ts.num_strings)); + for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { + char stringValueBuffer[4096]; + +#ifdef _MSC_VER + sscanf_s(token, "%s", stringValueBuffer, + (unsigned)_countof(stringValueBuffer)); +#else + sscanf(token, "%s", stringValueBuffer); +#endif + tag.stringValues[i] = stringValueBuffer; + token += tag.stringValues[i].size() + 1; + } + + tags.push_back(tag); + } + + // Ignore unknown command. + } + + bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, + triangulate); + // exportFaceGroupToShape return false when `usemtl` is called in the last + // line. + // we also add `shape` to `shapes` when `shape.mesh` has already some + // faces(indices) + if (ret || shape.mesh.indices.size()) { + shapes->push_back(shape); + } + faceGroup.clear(); // for safety + + if (err) { + (*err) += errss.str(); + } + + attrib->vertices.swap(v); + attrib->normals.swap(vn); + attrib->texcoords.swap(vt); + + return true; +} + +bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback, + void *user_data /*= NULL*/, + MaterialReader *readMatFn /*= NULL*/, + std::string *err /*= NULL*/) { + std::stringstream errss; + + // material + std::map material_map; + int material_id = -1; // -1 = invalid + + std::vector indices; + std::vector materials; + std::vector names; + names.reserve(2); + std::string name; + std::vector names_out; + + std::string linebuf; + while (inStream.peek() != -1) { + safeGetline(inStream, linebuf); + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // vertex + if (token[0] == 'v' && IS_SPACE((token[1]))) { + token += 2; + float x, y, z, w; // w is optional. default = 1.0 + parseV(&x, &y, &z, &w, &token); + if (callback.vertex_cb) { + callback.vertex_cb(user_data, x, y, z, w); + } + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + token += 3; + float x, y, z; + parseFloat3(&x, &y, &z, &token); + if (callback.normal_cb) { + callback.normal_cb(user_data, x, y, z); + } + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + token += 3; + float x, y, z; // y and z are optional. default = 0.0 + parseFloat3(&x, &y, &z, &token); + if (callback.texcoord_cb) { + callback.texcoord_cb(user_data, x, y, z); + } + continue; + } + + // face + if (token[0] == 'f' && IS_SPACE((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + indices.clear(); + while (!IS_NEW_LINE(token[0])) { + vertex_index vi = parseRawTriple(&token); + + index_t idx; + idx.vertex_index = vi.v_idx; + idx.normal_index = vi.vn_idx; + idx.texcoord_index = vi.vt_idx; + + indices.push_back(idx); + size_t n = strspn(token, " \t\r"); + token += n; + } + + if (callback.index_cb && indices.size() > 0) { + callback.index_cb(user_data, &indices.at(0), + static_cast(indices.size())); + } + + continue; + } + + // use mtl + if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, + static_cast(_countof(namebuf))); +#else + sscanf(token, "%s", namebuf); +#endif + + int newMaterialId = -1; + if (material_map.find(namebuf) != material_map.end()) { + newMaterialId = material_map[namebuf]; + } else { + // { error!! material not found } + } + + if (newMaterialId != material_id) { + material_id = newMaterialId; + } + + if (callback.usemtl_cb) { + callback.usemtl_cb(user_data, namebuf, material_id); + } + + continue; + } + + // load mtl + if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + + std::string err_mtl; + materials.clear(); + bool ok = (*readMatFn)(namebuf, &materials, &material_map, &err_mtl); + if (err) { + (*err) += err_mtl; + } + + if (!ok) { + return false; + } + + if (callback.mtllib_cb) { + callback.mtllib_cb(user_data, &materials.at(0), + static_cast(materials.size())); + } + } + + continue; + } + + // group name + if (token[0] == 'g' && IS_SPACE((token[1]))) { + names.clear(); + + while (!IS_NEW_LINE(token[0])) { + std::string str = parseString(&token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + assert(names.size() > 0); + + // names[0] must be 'g', so skip the 0th element. + if (names.size() > 1) { + name = names[1]; + } else { + name.clear(); + } + + if (callback.group_cb) { + if (names.size() > 1) { + // create const char* array. + names_out.resize(names.size() - 1); + for (size_t j = 0; j < names_out.size(); j++) { + names_out[j] = names[j + 1].c_str(); + } + callback.group_cb(user_data, &names_out.at(0), + static_cast(names_out.size())); + + } else { + callback.group_cb(user_data, NULL, 0); + } + } + + continue; + } + + // object name + if (token[0] == 'o' && IS_SPACE((token[1]))) { + // @todo { multiple object name? } + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 2; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + std::string object_name = std::string(namebuf); + + if (callback.object_cb) { + callback.object_cb(user_data, object_name.c_str()); + } + + continue; + } + +#if 0 // @todo + if (token[0] == 't' && IS_SPACE(token[1])) { + tag_t tag; + + char namebuf[4096]; + token += 2; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + tag.name = std::string(namebuf); + + token += tag.name.size() + 1; + + tag_sizes ts = parseTagTriple(&token); + + tag.intValues.resize(static_cast(ts.num_ints)); + + for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { + tag.intValues[i] = atoi(token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.floatValues.resize(static_cast(ts.num_floats)); + for (size_t i = 0; i < static_cast(ts.num_floats); ++i) { + tag.floatValues[i] = parseFloat(&token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.stringValues.resize(static_cast(ts.num_strings)); + for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { + char stringValueBuffer[4096]; + +#ifdef _MSC_VER + sscanf_s(token, "%s", stringValueBuffer, + (unsigned)_countof(stringValueBuffer)); +#else + sscanf(token, "%s", stringValueBuffer); +#endif + tag.stringValues[i] = stringValueBuffer; + token += tag.stringValues[i].size() + 1; + } + + tags.push_back(tag); + } +#endif + + // Ignore unknown command. + } + + if (err) { + (*err) += errss.str(); + } + + return true; +} +} // namespace tinyobj + +#endif + +#endif // TINY_OBJ_LOADER_H_ diff --git a/L13.zip b/L13.zip new file mode 100644 index 0000000000000000000000000000000000000000..2d94e9ac7abf94fd4b3cd0f921b80abbfb3f2011 GIT binary patch literal 10824 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 literal 0 HcmV?d00001 diff --git a/L13/CMakeLists.txt b/L13/CMakeLists.txt new file mode 100644 index 0000000..d6c2235 --- /dev/null +++ b/L13/CMakeLists.txt @@ -0,0 +1,126 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +# Name of the project +PROJECT(L13) + +# FOR LAB MACHINES ONLY! +# DO NOT EDIT +SET(DEF_DIR_GLM "C:\\c++\\glm") +SET(DEF_DIR_GLFW "C:\\c++\\glfw-3.2.1") +SET(DEF_DIR_GLEW "C:\\c++\\glew-2.0.0") + +# Is this the solution? +# Override with `cmake -DSOL=ON ..` +OPTION(SOL "Solution" OFF) + +# Use glob to get the list of all source files. +# We don't really need to include header and resource files to build, but it's +# nice to have them also show up in IDEs. +IF(${SOL}) + FILE(GLOB_RECURSE SOURCES "src0/*.cpp") + FILE(GLOB_RECURSE HEADERS "src0/*.h") +ELSE() + FILE(GLOB_RECURSE SOURCES "src/*.cpp") + FILE(GLOB_RECURSE HEADERS "src/*.h") +ENDIF() +FILE(GLOB_RECURSE GLSL "resources/*.glsl") + +# Set the executable. +ADD_EXECUTABLE(${CMAKE_PROJECT_NAME} ${SOURCES} ${HEADERS} ${GLSL}) + +# Get the GLM environment variable. Since GLM is a header-only library, we +# just need to add it to the include directory. +SET(GLM_INCLUDE_DIR "$ENV{GLM_INCLUDE_DIR}") +IF(NOT GLM_INCLUDE_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLM_INCLUDE_DIR to the root directory of your GLM installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLM in ${DEF_DIR_GLM}") + IF(IS_DIRECTORY ${DEF_DIR_GLM}) + MESSAGE(STATUS "Found!") + SET(GLM_INCLUDE_DIR ${DEF_DIR_GLM}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +INCLUDE_DIRECTORIES(${GLM_INCLUDE_DIR}) + +# Get the GLFW environment variable. There should be a CMakeLists.txt in the +# specified directory. +SET(GLFW_DIR "$ENV{GLFW_DIR}") +IF(NOT GLFW_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLFW_DIR to the root directory of your GLFW installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLFW in ${DEF_DIR_GLFW}") + IF(IS_DIRECTORY ${DEF_DIR_GLFW}) + MESSAGE(STATUS "Found!") + SET(GLFW_DIR ${DEF_DIR_GLFW}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +OPTION(GLFW_BUILD_EXAMPLES "GLFW_BUILD_EXAMPLES" OFF) +OPTION(GLFW_BUILD_TESTS "GLFW_BUILD_TESTS" OFF) +OPTION(GLFW_BUILD_DOCS "GLFW_BUILD_DOCS" OFF) +IF(CMAKE_BUILD_TYPE MATCHES Release) + ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/release) +ELSE() + ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/debug) +ENDIF() +INCLUDE_DIRECTORIES(${GLFW_DIR}/include) +TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} glfw ${GLFW_LIBRARIES}) + +# Get the GLEW environment variable. +SET(GLEW_DIR "$ENV{GLEW_DIR}") +IF(NOT GLEW_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLEW_DIR to the root directory of your GLEW installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLEW in ${DEF_DIR_GLEW}") + IF(IS_DIRECTORY ${DEF_DIR_GLEW}) + MESSAGE(STATUS "Found!") + SET(GLEW_DIR ${DEF_DIR_GLEW}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +INCLUDE_DIRECTORIES(${GLEW_DIR}/include) +IF(WIN32) + # With prebuilt binaries + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/Release/Win32/glew32s.lib) +ELSE() + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/libGLEW.a) +ENDIF() + +# OS specific options and libraries +IF(WIN32) + # c++11 is enabled by default. + # -Wall produces way too many warnings. + # -pedantic is not supported. + # Disable warning 4996. + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996") + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} opengl32.lib) +ELSE() + # Enable all pedantic warnings. + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -pedantic") + IF(APPLE) + # Add required frameworks for GLFW. + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "-framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo") + ELSE() + #Link the Linux OpenGL library + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "GL") + ENDIF() +ENDIF() diff --git a/L13/resources/simple_frag.glsl b/L13/resources/simple_frag.glsl new file mode 100644 index 0000000..013f708 --- /dev/null +++ b/L13/resources/simple_frag.glsl @@ -0,0 +1,8 @@ +#version 120 + +varying vec3 fragColor; + +void main() +{ + gl_FragColor = vec4(fragColor, 1.0); +} diff --git a/L13/resources/simple_vert.glsl b/L13/resources/simple_vert.glsl new file mode 100644 index 0000000..d6cc5b4 --- /dev/null +++ b/L13/resources/simple_vert.glsl @@ -0,0 +1,11 @@ +#version 120 + +uniform mat4 P; +uniform mat4 MV; +varying vec3 fragColor; + +void main() +{ + gl_Position = P * MV * gl_Vertex; + fragColor = gl_Color.rgb; +} diff --git a/L13/src/GLSL.cpp b/L13/src/GLSL.cpp new file mode 100644 index 0000000..2969872 --- /dev/null +++ b/L13/src/GLSL.cpp @@ -0,0 +1,152 @@ +// +// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book +// Created by zwood on 2/21/10. +// Modified by sueda 10/15/15. +// + +#include "GLSL.h" +#include +#include +#include +#include + +using namespace std; + +namespace GLSL { + +const char * errorString(GLenum err) +{ + switch(err) { + case GL_NO_ERROR: + return "No error"; + case GL_INVALID_ENUM: + return "Invalid enum"; + case GL_INVALID_VALUE: + return "Invalid value"; + case GL_INVALID_OPERATION: + return "Invalid operation"; + case GL_STACK_OVERFLOW: + return "Stack overflow"; + case GL_STACK_UNDERFLOW: + return "Stack underflow"; + case GL_OUT_OF_MEMORY: + return "Out of memory"; + default: + return "No error"; + } +} + +void checkVersion() +{ + int major, minor; + major = minor = 0; + const char *verstr = (const char *)glGetString(GL_VERSION); + + if((verstr == NULL) || (sscanf(verstr, "%d.%d", &major, &minor) != 2)) { + printf("Invalid GL_VERSION format %d.%d\n", major, minor); + } + if(major < 2) { + printf("This shader example will not work due to the installed Opengl version, which is %d.%d.\n", major, minor); + exit(0); + } +} + +void checkError(const char *str) +{ + GLenum glErr = glGetError(); + if(glErr != GL_NO_ERROR) { + if(str) { + printf("%s: ", str); + } + printf("GL_ERROR = %s.\n", errorString(glErr)); + assert(false); + } +} + +void printShaderInfoLog(GLuint shader) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + GLchar *infoLog = 0; + + checkError(GET_FILE_LINE); + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength); + checkError(GET_FILE_LINE); + + if(infologLength > 0) { + infoLog = (GLchar *)malloc(infologLength); + if(infoLog == NULL) { + puts("ERROR: Could not allocate InfoLog buffer"); + exit(1); + } + glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog); + checkError(GET_FILE_LINE); + printf("Shader InfoLog:\n%s\n\n", infoLog); + free(infoLog); + } +} + +void printProgramInfoLog(GLuint program) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + GLchar *infoLog = 0; + + checkError(GET_FILE_LINE); + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infologLength); + checkError(GET_FILE_LINE); + + if(infologLength > 0) { + infoLog = (GLchar *)malloc(infologLength); + if(infoLog == NULL) { + puts("ERROR: Could not allocate InfoLog buffer"); + exit(1); + } + glGetProgramInfoLog(program, infologLength, &charsWritten, infoLog); + checkError(GET_FILE_LINE); + printf("Program InfoLog:\n%s\n\n", infoLog); + free(infoLog); + } +} + +char *textFileRead(const char *fn) +{ + FILE *fp; + char *content = NULL; + int count = 0; + if(fn != NULL) { + fp = fopen(fn,"rt"); + if(fp != NULL) { + fseek(fp, 0, SEEK_END); + count = (int)ftell(fp); + rewind(fp); + if(count > 0) { + content = (char *)malloc(sizeof(char) * (count+1)); + count = (int)fread(content,sizeof(char),count,fp); + content[count] = '\0'; + } + fclose(fp); + } else { + printf("error loading %s\n", fn); + } + } + return content; +} + +int textFileWrite(const char *fn, const char *s) +{ + FILE *fp; + int status = 0; + if(fn != NULL) { + fp = fopen(fn,"w"); + if(fp != NULL) { + if(fwrite(s,sizeof(char),strlen(s),fp) == strlen(s)) { + status = 1; + } + fclose(fp); + } + } + return(status); +} + +} diff --git a/L13/src/GLSL.h b/L13/src/GLSL.h new file mode 100644 index 0000000..f945fdd --- /dev/null +++ b/L13/src/GLSL.h @@ -0,0 +1,40 @@ +// +// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book +// Created by zwood on 2/21/10. +// Modified by sueda 10/15/15. +// + +#pragma once +#ifndef __GLSL__ +#define __GLSL__ + +#define GLEW_STATIC +#include + +/////////////////////////////////////////////////////////////////////////////// +// For printing out the current file and line number // +/////////////////////////////////////////////////////////////////////////////// +#include + +template +std::string NumberToString(T x) +{ + std::ostringstream ss; + ss << x; + return ss.str(); +} + +#define GET_FILE_LINE (std::string(__FILE__) + ":" + NumberToString(__LINE__)).c_str() +/////////////////////////////////////////////////////////////////////////////// + +namespace GLSL { + + void checkVersion(); + void checkError(const char *str = 0); + void printProgramInfoLog(GLuint program); + void printShaderInfoLog(GLuint shader); + int textFileWrite(const char *filename, const char *s); + char *textFileRead(const char *filename); +} + +#endif diff --git a/L13/src/MatrixStack.cpp b/L13/src/MatrixStack.cpp new file mode 100644 index 0000000..eaa6e6c --- /dev/null +++ b/L13/src/MatrixStack.cpp @@ -0,0 +1,114 @@ +#include "MatrixStack.h" + +#include +#include +#include + +#define GLM_FORCE_RADIANS +#include +#include + +using namespace std; + +MatrixStack::MatrixStack() +{ + mstack = make_shared< stack >(); + mstack->push(glm::mat4(1.0)); +} + +MatrixStack::~MatrixStack() +{ +} + +void MatrixStack::pushMatrix() +{ + const glm::mat4 &top = mstack->top(); + mstack->push(top); + assert(mstack->size() < 100); +} + +void MatrixStack::popMatrix() +{ + assert(!mstack->empty()); + mstack->pop(); + // There should always be one matrix left. + assert(!mstack->empty()); +} + +void MatrixStack::loadIdentity() +{ + glm::mat4 &top = mstack->top(); + top = glm::mat4(1.0); +} + +void MatrixStack::translate(const glm::vec3 &t) +{ + glm::mat4 &top = mstack->top(); + top *= glm::translate(t); +} + +void MatrixStack::translate(float x, float y, float z) +{ + translate(glm::vec3(x, y, z)); +} + +void MatrixStack::scale(const glm::vec3 &s) +{ + glm::mat4 &top = mstack->top(); + top *= glm::scale(s); +} + +void MatrixStack::scale(float x, float y, float z) +{ + scale(glm::vec3(x, y, z)); +} + +void MatrixStack::scale(float s) +{ + scale(glm::vec3(s, s, s)); +} + +void MatrixStack::rotate(float angle, const glm::vec3 &axis) +{ + glm::mat4 &top = mstack->top(); + top *= glm::rotate(angle, axis); +} + +void MatrixStack::rotate(float angle, float x, float y, float z) +{ + rotate(angle, glm::vec3(x, y, z)); +} + +void MatrixStack::multMatrix(const glm::mat4 &matrix) +{ + glm::mat4 &top = mstack->top(); + top *= matrix; +} + +const glm::mat4 &MatrixStack::topMatrix() const +{ + return mstack->top(); +} + +void MatrixStack::print(const glm::mat4 &mat, const char *name) +{ + if(name) { + printf("%s = [\n", name); + } + for(int i = 0; i < 4; ++i) { + for(int j = 0; j < 4; ++j) { + // mat[j] returns the jth column + printf("%- 5.2f ", mat[j][i]); + } + printf("\n"); + } + if(name) { + printf("];"); + } + printf("\n"); +} + +void MatrixStack::print(const char *name) const +{ + print(mstack->top(), name); +} diff --git a/L13/src/MatrixStack.h b/L13/src/MatrixStack.h new file mode 100644 index 0000000..66278ce --- /dev/null +++ b/L13/src/MatrixStack.h @@ -0,0 +1,50 @@ +#pragma once +#ifndef _MatrixStack_H_ +#define _MatrixStack_H_ + +#include +#include +#include + +class MatrixStack +{ +public: + MatrixStack(); + virtual ~MatrixStack(); + + // glPushMatrix(): Copies the current matrix and adds it to the top of the stack + void pushMatrix(); + // glPopMatrix(): Removes the top of the stack and sets the current matrix to be the matrix that is now on top + void popMatrix(); + + // glLoadIdentity(): Sets the top matrix to be the identity + void loadIdentity(); + // glMultMatrix(): Right multiplies the top matrix + void multMatrix(const glm::mat4 &matrix); + + // glTranslate(): Right multiplies the top matrix by a translation matrix + void translate(const glm::vec3 &trans); + void translate(float x, float y, float z); + // glScale(): Right multiplies the top matrix by a scaling matrix + void scale(const glm::vec3 &scale); + void scale(float x, float y, float z); + // glScale(): Right multiplies the top matrix by a scaling matrix + void scale(float size); + // glRotate(): Right multiplies the top matrix by a rotation matrix (angle in radians) + void rotate(float angle, const glm::vec3 &axis); + void rotate(float angle, float x, float y, float z); + + // glGet(GL_MODELVIEW_MATRIX): Gets the top matrix + const glm::mat4 &topMatrix() const; + + // Prints out the specified matrix + static void print(const glm::mat4 &mat, const char *name = 0); + // Prints out the top matrix + void print(const char *name = 0) const; + +private: + std::shared_ptr< std::stack > mstack; + +}; + +#endif diff --git a/L13/src/Program.cpp b/L13/src/Program.cpp new file mode 100644 index 0000000..1e85538 --- /dev/null +++ b/L13/src/Program.cpp @@ -0,0 +1,126 @@ +#include "Program.h" + +#include +#include + +#include "GLSL.h" + +using namespace std; + +Program::Program() : + vShaderName(""), + fShaderName(""), + pid(0), + verbose(true) +{ + +} + +Program::~Program() +{ + +} + +void Program::setShaderNames(const string &v, const string &f) +{ + vShaderName = v; + fShaderName = f; +} + +bool Program::init() +{ + GLint rc; + + // Create shader handles + GLuint VS = glCreateShader(GL_VERTEX_SHADER); + GLuint FS = glCreateShader(GL_FRAGMENT_SHADER); + + // Read shader sources + const char *vshader = GLSL::textFileRead(vShaderName.c_str()); + const char *fshader = GLSL::textFileRead(fShaderName.c_str()); + glShaderSource(VS, 1, &vshader, NULL); + glShaderSource(FS, 1, &fshader, NULL); + + // Compile vertex shader + glCompileShader(VS); + glGetShaderiv(VS, GL_COMPILE_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printShaderInfoLog(VS); + cout << "Error compiling vertex shader " << vShaderName << endl; + } + return false; + } + + // Compile fragment shader + glCompileShader(FS); + glGetShaderiv(FS, GL_COMPILE_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printShaderInfoLog(FS); + cout << "Error compiling fragment shader " << fShaderName << endl; + } + return false; + } + + // Create the program and link + pid = glCreateProgram(); + glAttachShader(pid, VS); + glAttachShader(pid, FS); + glLinkProgram(pid); + glGetProgramiv(pid, GL_LINK_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printProgramInfoLog(pid); + cout << "Error linking shaders " << vShaderName << " and " << fShaderName << endl; + } + return false; + } + + GLSL::checkError(GET_FILE_LINE); + return true; +} + +void Program::bind() +{ + glUseProgram(pid); +} + +void Program::unbind() +{ + glUseProgram(0); +} + +void Program::addAttribute(const string &name) +{ + attributes[name] = glGetAttribLocation(pid, name.c_str()); +} + +void Program::addUniform(const string &name) +{ + uniforms[name] = glGetUniformLocation(pid, name.c_str()); +} + +GLint Program::getAttribute(const string &name) const +{ + map::const_iterator attribute = attributes.find(name.c_str()); + if(attribute == attributes.end()) { + if(isVerbose()) { + cout << name << " is not an attribute variable" << endl; + } + return -1; + } + return attribute->second; +} + +GLint Program::getUniform(const string &name) const +{ + map::const_iterator uniform = uniforms.find(name.c_str()); + if(uniform == uniforms.end()) { + if(isVerbose()) { + cout << name << " is not a uniform variable" << endl; + } + return -1; + } + return uniform->second; +} diff --git a/L13/src/Program.h b/L13/src/Program.h new file mode 100644 index 0000000..51e58bb --- /dev/null +++ b/L13/src/Program.h @@ -0,0 +1,44 @@ +#pragma once +#ifndef __Program__ +#define __Program__ + +#include +#include + +#define GLEW_STATIC +#include + +/** + * An OpenGL Program (vertex and fragment shaders) + */ +class Program +{ +public: + Program(); + virtual ~Program(); + + void setVerbose(bool v) { verbose = v; } + bool isVerbose() const { return verbose; } + + void setShaderNames(const std::string &v, const std::string &f); + virtual bool init(); + virtual void bind(); + virtual void unbind(); + + void addAttribute(const std::string &name); + void addUniform(const std::string &name); + GLint getAttribute(const std::string &name) const; + GLint getUniform(const std::string &name) const; + +protected: + std::string vShaderName; + std::string fShaderName; + +private: + GLuint pid; + std::map attributes; + std::map uniforms; + bool verbose; +}; + +#endif diff --git a/L13/src/main.cpp b/L13/src/main.cpp new file mode 100644 index 0000000..b8339a6 --- /dev/null +++ b/L13/src/main.cpp @@ -0,0 +1,360 @@ +#include +#include + +#define GLEW_STATIC +#include +#include + +#define GLM_FORCE_RADIANS +#include +#include +#include + +#include "GLSL.h" +#include "Program.h" +#include "MatrixStack.h" + +using namespace std; + +GLFWwindow *window; // Main application window +string RESOURCE_DIR = ""; // Where the resources are loaded from +shared_ptr prog; + +bool keyToggles[256] = {false}; // only for English keyboards! +glm::vec2 cameraRotations(0, 0); +glm::vec2 mousePrev(-1, -1); + +// Control points +vector cps; + +enum SplineType +{ + CATMULL_ROM = 0, + BASIS, + SPLINE_TYPE_COUNT +}; + +SplineType type = CATMULL_ROM; + +glm::mat4 Bcr, Bb; + +vector > usTable; + +void buildTable(); + +static void error_callback(int error, const char *description) +{ + cerr << description << endl; +} + +static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) +{ + if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, GL_TRUE); + } + + if(action == GLFW_PRESS) { + switch(key) { + case GLFW_KEY_S: + type = (SplineType)((type + 1) % SPLINE_TYPE_COUNT); + buildTable(); + break; + case GLFW_KEY_C: + cps.clear(); + buildTable(); + break; + case GLFW_KEY_R: + cps.clear(); + int n = 8; + for(int i = 0; i < n; ++i) { + float alpha = i / (n - 1.0f); + float angle = 2.0f * M_PI * alpha; + float radius = cos(2.0f * angle); + glm::vec3 cp; + cp.x = radius * cos(angle); + cp.y = radius * sin(angle); + cp.z = (1.0f - alpha)*(-0.5) + alpha*0.5; + cps.push_back(cp); + } + buildTable(); + break; + } + } +} + +static void char_callback(GLFWwindow *window, unsigned int key) +{ + keyToggles[key] = !keyToggles[key]; +} + +static void cursor_position_callback(GLFWwindow* window, double xmouse, double ymouse) +{ + if(mousePrev.x >= 0) { + glm::vec2 mouseCurr(xmouse, ymouse); + cameraRotations += 0.01f * (mouseCurr - mousePrev); + mousePrev = mouseCurr; + } +} + +void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) +{ + // Get the current mouse position. + double xmouse, ymouse; + glfwGetCursorPos(window, &xmouse, &ymouse); + // Get current window size. + int width, height; + glfwGetWindowSize(window, &width, &height); + if(action == GLFW_PRESS) { + if(mods & GLFW_MOD_SHIFT) { + // Insert a new control point + // Convert from window coord to world coord assuming that we're + // using an orthgraphic projection from -1 to 1. + float aspect = (float)width/height; + glm::vec4 x; + x[0] = 2.0f * ((xmouse / width) - 0.5f)* aspect; + x[1] = 2.0f * (((height - ymouse) / height) - 0.5f); + x[2] = 0.0f; + x[3] = 1.0f; + // Build the current modelview matrix. + auto MV = make_shared(); + MV->rotate(cameraRotations[1], glm::vec3(1, 0, 0)); + MV->rotate(cameraRotations[0], glm::vec3(0, 1, 0)); + // Since the modelview matrix transforms from world to eye coords, + // we want to invert to go from eye to world. + x = glm::inverse(MV->topMatrix()) * x; + cps.push_back(glm::vec3(x)); + buildTable(); + } else { + mousePrev.x = xmouse; + mousePrev.y = ymouse; + } + } else { + mousePrev[0] = -1; + mousePrev[1] = -1; + } +} + +static void init() +{ + GLSL::checkVersion(); + + // Set background color + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + // Enable z-buffer test + glEnable(GL_DEPTH_TEST); + + // Initialize the GLSL program. + prog = make_shared(); + prog->setVerbose(true); + prog->setShaderNames(RESOURCE_DIR + "simple_vert.glsl", RESOURCE_DIR + "simple_frag.glsl"); + prog->init(); + prog->addUniform("P"); + prog->addUniform("MV"); + prog->setVerbose(false); + + // Initialize time. + glfwSetTime(0.0); + + keyToggles[(unsigned)'l'] = true; + + Bcr[0] = glm::vec4( 0.0f, 2.0f, 0.0f, 0.0f); + Bcr[1] = glm::vec4(-1.0f, 0.0f, 1.0f, 0.0f); + Bcr[2] = glm::vec4( 2.0f, -5.0f, 4.0f, -1.0f); + Bcr[3] = glm::vec4(-1.0f, 3.0f, -3.0f, 1.0f); + Bcr *= 0.5; + + Bb[0] = glm::vec4( 1.0f, 4.0f, 1.0f, 0.0f); + Bb[1] = glm::vec4(-3.0f, 0.0f, 3.0f, 0.0f); + Bb[2] = glm::vec4( 3.0f, -6.0f, 3.0f, 0.0f); + Bb[3] = glm::vec4(-1.0f, 3.0f, -3.0f, 1.0f); + Bb /= 6.0f; + + // If there were any OpenGL errors, this will print something. + // You can intersperse this line in your code to find the exact location + // of your OpenGL error. + GLSL::checkError(GET_FILE_LINE); +} + +void buildTable() +{ + // INSERT CODE HERE + usTable.clear(); +} + +float s2u(float s) +{ + // INSERT CODE HERE + return 0.0f; +} + +void render() +{ + // Update time. + //double t = glfwGetTime(); + + // Get current frame buffer size. + int width, height; + glfwGetFramebufferSize(window, &width, &height); + glViewport(0, 0, width, height); + + // Clear buffers + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + auto P = make_shared(); + auto MV = make_shared(); + P->pushMatrix(); + MV->pushMatrix(); + + double aspect = (double)width/height; + P->multMatrix(glm::ortho(-aspect, aspect, -1.0, 1.0, -2.0, 2.0)); + MV->rotate(cameraRotations.y, glm::vec3(1, 0, 0)); + MV->rotate(cameraRotations.x, glm::vec3(0, 1, 0)); + + // Bind the program + prog->bind(); + glUniformMatrix4fv(prog->getUniform("P"), 1, GL_FALSE, glm::value_ptr(P->topMatrix())); + glUniformMatrix4fv(prog->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix())); + + // Draw control points + int ncps = (int)cps.size(); + glPointSize(5.0f); + glColor3f(1.0f, 0.0f, 0.0f); + glBegin(GL_POINTS); + for(int i = 0; i < ncps; ++i) { + glVertex3f(cps[i].x, cps[i].y, cps[i].z); + } + glEnd(); + glLineWidth(1.0f); + if(keyToggles[(unsigned)'l']) { + glColor3f(1.0f, 0.5f, 0.5f); + glBegin(GL_LINE_STRIP); + for(int i = 0; i < ncps; ++i) { + glVertex3f(cps[i].x, cps[i].y, cps[i].z); + } + glEnd(); + } + + if(ncps >= 4) { + // Draw spline + glm::mat4 B = (type == CATMULL_ROM ? Bcr : Bb); + glLineWidth(3.0f); + for(int k = 0; k < ncps - 3; ++k) { + glm::mat4 Gk; + for(int i = 0; i < 4; ++i) { + Gk[i] = glm::vec4(cps[k+i], 0.0f); + } + int n = 32; // curve discretization + glBegin(GL_LINE_STRIP); + if(k % 2 == 0) { + // Even segment color + glColor3f(0.0f, 1.0f, 0.0f); + } else { + // Odd segment color + glColor3f(0.0f, 0.0f, 1.0f); + } + for(int i = 0; i < n; ++i) { + // u goes from 0 to 1 within this segment + float u = i / (n - 1.0f); + // Compute spline point at u + glm::vec4 uVec(1.0f, u, u*u, u*u*u); + glm::vec3 P(Gk * (B * uVec)); + glVertex3fv(&P[0]); + } + glEnd(); + } + + // Draw equally spaced points on the spline curve + if(keyToggles[(unsigned)'a'] && !usTable.empty()) { + float ds = 0.2; + glColor3f(1.0f, 0.0f, 0.0f); + glPointSize(10.0f); + glBegin(GL_POINTS); + float smax = usTable.back().second; // spline length + for(float s = 0.0f; s < smax; s += ds) { + // Convert from s to (concatenated) u + float uu = s2u(s); + // Convert from concatenated u to the usual u between 0 and 1. + float kfloat; + float u = std::modf(uu, &kfloat); + // k is the index of the starting control point + int k = (int)std::floor(kfloat); + // Compute spline point at u + glm::mat4 Gk; + for(int i = 0; i < 4; ++i) { + Gk[i] = glm::vec4(cps[k+i], 0.0f); + } + glm::vec4 uVec(1.0f, u, u*u, u*u*u); + glm::vec3 P(Gk * (B * uVec)); + glVertex3fv(&P[0]); + } + glEnd(); + } + } + + // Unbind the program + prog->unbind(); + + // Pop matrix stacks. + MV->popMatrix(); + P->popMatrix(); + + GLSL::checkError(GET_FILE_LINE); +} + +int main(int argc, char **argv) +{ + if(argc < 2) { + cout << "Please specify the resource directory." << endl; + return 0; + } + RESOURCE_DIR = argv[1] + string("/"); + + // Set error callback. + glfwSetErrorCallback(error_callback); + // Initialize the library. + if(!glfwInit()) { + return -1; + } + // Create a windowed mode window and its OpenGL context. + window = glfwCreateWindow(640, 480, "YOUR NAME", NULL, NULL); + if(!window) { + glfwTerminate(); + return -1; + } + // Make the window's context current. + glfwMakeContextCurrent(window); + // Initialize GLEW. + glewExperimental = true; + if(glewInit() != GLEW_OK) { + cerr << "Failed to initialize GLEW" << endl; + return -1; + } + glGetError(); // A bug in glewInit() causes an error that we can safely ignore. + cout << "OpenGL version: " << glGetString(GL_VERSION) << endl; + cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl; + // Set vsync. + glfwSwapInterval(1); + // Set keyboard callback. + glfwSetKeyCallback(window, key_callback); + // Set char callback. + glfwSetCharCallback(window, char_callback); + // Set cursor position callback. + glfwSetCursorPosCallback(window, cursor_position_callback); + // Set mouse button callback. + glfwSetMouseButtonCallback(window, mouse_button_callback); + // Initialize scene. + init(); + // Loop until the user closes the window. + while(!glfwWindowShouldClose(window)) { + // Render scene. + render(); + // Swap front and back buffers. + glfwSwapBuffers(window); + // Poll for and process events. + glfwPollEvents(); + } + // Quit program. + glfwDestroyWindow(window); + glfwTerminate(); + return 0; +} diff --git a/L14.zip b/L14.zip new file mode 100644 index 0000000000000000000000000000000000000000..5d707f28e410f7f515158f62465bd24871332c34 GIT binary patch literal 9821 zcma)?Wl&t%)`mNHaQEQu(zv@5+=IKj1rHY7-3gZ9-ncuBJHa(*AV`3ak4$cTliay8 z_x|XvbGqt0_3l1001(85Fn;tWMd|8 z<>KnXrY1cm{R#3;_7!`Ee~9hh=HZZ{VtCH?m~gNQ^w) z26}aRSd>}aH+7A)6_{`F`BAwBwy(&6?=RMGz@B6Hj+uEMi|R^ip|W3e>#l#TSwCb(^*%>>kopHbfYzr0IKpFTbz7-P8C;BG6>j zXaFa_UfVqjHY&YZ!zbSg;9wIH?0)_+D1H}W3aM!mwW%!eQH|^Pu!}Hg`u^m?`SEyZ zcb83%mYVPK+c36ajlJ7k%<@`qydB}ICf-l!-i>d_2Lht#gz*`yX6XcRIy;U%PZmD9 z-zQgv@8Z%{a!U6nsABJFcNMHVt+wRLpxu>icSRVLLz znGs{VOj3m^B_9Sn^LQ}qELw?=vC0KrcSFu}n%vbw{T{ zk)d)g4j2=a?G2kZY6V9lztP^JY??4qn3~%sq*b|IyYxM#_TO5Qqq-FdYB3$IptFos zEEy=Zh;i#VL>XblYyaND?j6R_mEq)jI(Gh^IB*m}HIb*h9g{3YM3x=u!n3cjM9cy( zA|Wk6;WZW{t%YCI7EFJTpme%_p;)(t=AV;t4;;&H65fh-Lw zeq#R6WoR;k@5^D&XfL8DCr%0kFGWltlJtxdhes448(u4N0VRVL9{j!5Qpsr&859hV zP%xaK`Z$&^52Eg@ed1!szaVMGZM@8-URh?&!oY>YC8D9RIlkP>isWmjnRlm=mBwS$ z4rPiJYKd2yRMv~2ZH-qGj;2bYUmp{~1jlF++PL}{XZjeK)$5q?syI9X*QV3JZzKW; z*9)EfYx_61jR zx1`%q6I|_RWQk*;BbQbx%eHh^hN`*Xi`{S2Oq&-pJXXya0wkxiK*_W7?bUgT`cuLk zoI17xnATRIIEP~tm333ybyI`&o%k;bM8ysl;dfN8@2F6wxpp$8jUlpnA;7m=7ZBYr#oH4>j;4pcg3%-C7Tl8bE_)vb$*WZ_YuB& z)b^7Q>pvR3sf>r-66%zOZ~BdW5!@$?#J?k4L=*JhEe95?d7q8I%i$dw%cXS4rvBbO^W%H?3i* z)Fi!a!EK)cjM{sBZ4u%pZvtPY*Y?hnvxirP1b-&|uELv|xwGkoEMF9}buMSaq+J&s3$vjaW-N8!^H1DOlxVk{l&z8JpD5m?3=O6KC|PUDTM+6Di8qx z#D6_4C9f*aWa8-f2c_nDpcc|!DZ3i499B3neH;Dyv%~7A_xjxf+9?zQNYwQTW7HQF zBaHA6B@1jBfmU%z+4Wcc>y)&^DuNM4xYxB^)rF(?PN$%-cP+1~R-hkR$sW+0C1$d^ z6KXk<LH%NR3!BVuTrGM2mt947+JIfq`lfShnF~;+4X0^#;^L224_@@eBgu zf|+SnpF0^~w!|e_BDTE_X4WM|M7iweCX-?gmf8i9PM*2lcWw=OdalJX z357I1b8EIeV?0YzWOHifx5?0QU#RaFr=@f2eOE6&WRa6f51E~arEY_++66_O)8yZ% z=5y7C3z|Y@ejA({AWOS5TYL^nK607N3caRTRn(XsliK0cSB*W-$+Nd@Nu)?MwX`Mh4D;S`b@%)1MD#H@aa8#Wh=_BJq64-jpUuqpo`28#;jtkvi+ZB4;An}z zCCea0b84r_TRzDKmA3pqc1Q{%ellrCzEkoDyyCScX(;tMVc>?V)WUY8DRHDZ6zi+% z5OO&i6Gh946t~;N?FxIE^_xK$W$xyUg^KPVq|(YA7O9}(A)A11Ey}BJY{!@b3x&#n z^^U+QHF-}R2Dd!lI6@+d6XZ5plJ**0h}%uf7zp~Jd3=O}*{aZbW;4!{2+L|2d!FJl zE^I9_MD&GqzOhAVZe8>Di>JcGL)POow(J7|2uQl5XQaclme0IpoI2?haC=`6RL~l* zEOM*xRlhR-jLwoA;&e+EgY7$1zmAYIK?P*DIgjXD6v5)N?Vf}NHQDkxB*LsX(+{cH z6@rkRrc7(TYn~95nh0B(catp7rFB7Z;*S#2EQt74t%wFjJ6lBLq8D4%5oFp}FA-j- zMFpct*w60KFnP0uA}*wB8Tuo%Gkn?8K!p5MH&$Ov_#SIeZm$+wL+v1^Lxeli09k6& z2S^wOlag3mk!j}xo3|YkIBF>v0duL$O*AH$w}Edce|&SHvzB>2k*67_zj-M))D2Hb zZv0(4nl1W@`6et=qcVBjJ&Z~(Jd08zh7(1fPRS9$!z)8&sc|@~K<=uX*crh z;o-isZ}Q_wN%V9wWEYGHO(~ALFj(E?F|$ijCs9O`19vqzi&+HAPi&)J_@b7>NUgqY zMKp=mRh`IwPs=6sDQD3&+J?3R&r$DFeUW{tOILEJ1-*LGS|JFs9a+BjoV;VA%|kp@ zq8jVPy9~BaKYN*JyMe?{Xc&C^vcyy^eJ5O3`L)by@8)qg5HcbkKxg1jCF*7(i86C# zQtssjCE`jc_a8I9cilEMwKut2S*%2*E7e1_K}L9pT)wYKg=G;rMyO4vSHucaIY1QZ z*OgN~>?4FT$KDl>EGwZWHrPuVQrljFhv>UNg@qqVFjg-Yc$R8o^z5A>v0H^lBXN(de=^_@1a5=^I_?h6t{C zuF9}wuFwPUuSjj9K>mIQ%LV7A%}c$xQYI9*NH~Z66xmTy%sNqOMW1+>@-SKON)jEu zNWhr9nU8pnW~xm>P^u!w5O`S{=fatnIDHG#MmB2eH@NUM*2hi3JXNAcqxBTYj^>ybPc}NWq|?md*mw&c70+?#@!M=S%o!JNhmBRrO=NTS#VK$B ziUtO6!M&;H@FNkXMb2eEUFM~&8++K!MtkrLjt^Y!rjNJccMo_^3-RF1(v9q+M2m=i z@n#Lo#g{!8CKf1?GBk}^tLxKBlkfWCkS9S6160roan!q!@>o`RXJ9po0tZ|dclts9yIQN+iz9SnuIw`DA*&om~z-}Gwt z;Z&R(BY9o{HVi*M+r)xj0MCuvEx6nBrG5iD>VeoI_Z&^u;1hR@G0NM;+U1)Q555## zfyh$00HP{N>wnh*I zTT!ha7^T7^_wg(5d4?&j&BA>QY=it;&jDi(u=a7;RXDwxG~~gPz|-O{hA(%Oy+l&LwaK-2!zR{{RzY}9)lBy z7=crFNzT_dOr6R^F1cC6($6V?t`uaG3Z9;#0iuXZfKB zn@8sXA$nt?NZ4XW*Rn?u#PoF?qsr@et1zUQ;euu|nQ7O`;{EA}i-j8qV|}%Kv)2jp z7+PSOVPR4DJ(zgAZQ4GFIz+d5hI#|i6gGTb>WadE6Ly64jN{TPR?8$c4U5r+I$}q6 zD2p$(0jVaJwM@L?G_e__!Y*c2@5$_8u!*~`K=;{v#l~5hBTFG6$8bk?j~13xMX!

|yv>nS2W!Fd*kd1c>YUlI9_6s-T2-6hK98K`B ze$^R<6kUbXTH%fuhEljaivtkFI#fIpFt}-@6(n#y(kw(^W|RK91Q<#?$tOHcLtH6VD=BH`2KSd3Xd^+(RBE|w$Vzc4%7PY!=7-DsyyBED1B=ksIx*xrAo5PGVgad11 zx+-ChC`N&Kgrm?(X46JsR|gobCU9!&2YLd(JB({CdUh*lj^M|Vempw;gtBTHN3Ule z0pElc9NCUj$?`4=R7_VfH&UFGa=au{W;UkSaM>$AfZ&T__C9<78`=`@Tz!mYTjto2N7V&WaX^dEHpDrc*pt!rN^pdXm4@PRJK*sOi##r%Eru?D|~)&$<_YShJpLF#5H zMH6X%B<$b{tP}w(Xw_^YZ}Ggg?3~UnNbz**5CJc~UqTUeOPXq|e55*BR9UH_4Nz{( z%8ahwRh4XlZ)_MzN!@xl#y6B&@9XKsz)8Umn8?L-c+EDmSn-LxG-^_;8W?T}YMf>> zcvsKGq_tv@4Hnh+BDC^vn z$+#R8eXXcmm7g3Jv$xl&M*4Ef#HE!~e<90tTx3n4i80h5{s7xx@g)m)IFDf~+Cj*6 z78)i>G}2P$#9r&n_yWJ-1$3w1ZUme>tisE3jCCyX5ZSuY)Ypq_+orHBmx%kx@NyF& zQ@VlV7r0ZTnD3xVyre+SVp9;Yt<$%-l?NP7E2Y@|a#<6C7NZp&M4p4190tE-8WoZm zdgV&)Xgb9DpXptP30O?xU7zv_yv70XHxkdWT}Q;}H_H&004)XQolHX1e1?|dAq~FP zjs+OQzxQJ-Q_4qNFP?-x$9~)3fTfQA#VioZ0NXvDJStvo1!!fc?TZ1=POPgG-21=`k}m#?sjTykiQv7KneY%P+gdukE+O0*)Ay zmQIyOanKY+Mhl{<#rH0bi9#pfYMC|3>PfA-nOQkQAr^W`Y%lonqtEN|01J`D-ocCQ z#WmzniI-Ht2+Xq10rBty7F{yZ67q!brIwbsSp9EAcKeTU{i8H!X7L4urE?C{ZYlCl z;cD~Vv*QMf>#rDQW*a^0sNYt*HBaZLD))n(IjYd{Z;B+{;4x;JRf>>x@Tc=x3xC&Ot zCnImvFA0VzZi7o3{#JstM-_=(1+J93LaaWzASk@qgK0N`Hfh>z7WqX5@i5W#@jR5c zN}Vx>{;0>$w+rKauLh({e*MW_Fa<+P9?qz7&B!Nv$07=hnsA+y23c+jOH1*rwQzIv zFoYNO!X}DXRe0j$Zw`X)PRyjqK%bM(wS`-&O<=UEzn_zrfMwWYFvJNt--Ew7_x1qe zzV5fMQ+>hlP|5X{)36Dv^n1glD!P)%A!3$sZg;vzo5;dMK#4QByRi}C!qHNPoMvHe z)8$6La*}?s0HKTbedolUb6cIro<+T`e`(ogOe2x`|vKbutS}2 zIV%umHYN{fVfXM$V*jJyHSFz2PVqEjzddz8(Eh`W{l}ePyP87e3JWIxVCR;I;c!Y3 zZ9O$LQj)t2SToe+b0uqv7 zO`<5bS;YyAIfy(`CW)u^X>j>aDTy~Kg;kVUkX=-bBZ=ZZ%O9!|%ZPJE=Pn)rCvZfB zp;=+PgSsb3n6DwMaHG7>cigd~kW1}EpdLC_;Us5hDYo)itQt5#NSlQt@dVYhusW9G zMImDj5b=m`CNPsh>N!U0$aL3o>u=aqhe*z7!T31I9#pyu>-p}W*>l0rl@EAXXF2!L zFw$?Kfh2Q@e4#4k!;@d#Dk`yz==Z)%=8O=w4iqD@R(EA+(?`^86;~;c+E%g3tKiHV zr6KI3ZZ)XP&nZzxyRm8G@{aH|mxZ^F#b!v8hwm~^hJAYux7Y&lQ5fuFM?Y65;CP2^ z|B%wjxZk(vX1D1HJGV8e)BwEvjua{`~eiffG} ze;&A3)2*rj&*R@Z-pB?~A&v$vgtkmq5DFY3!)%jC9V;H_^cz^HdQ|VY*Xl`SGUuKy z7--(C7mSAuo_uOOvgGkW=(cneu)8UL9~}MVjpQMen$d@nESCsY=Xu$5XKc*(gW3sI zYu}0;GSHE#D2BP)!nm%U>3JfqsT*92<{=zO!*aD$%lGw6auZo7+g}mV=qCQ%Aa^0cT<9SIfQ9D(0Ls6no07AGg|m^}e>2AhbzPgM$>ta1 zAF|iuDCzxLVOsbgt9)!+HY>OrSER;FYBoNIBD4Fz?>>fM$<3beWKm3*XP>X>%qL-j zCbE{FYRDIrAIsCF#{I>9dF?fAsw`?79?%voB>|4Za%0sA6~@exiB=A+mw>E^n@swB z^FBAHSCb8jK7m`d23n<)d>>R-&QT+uB0W#Ft<~|XLot!Q2)QlV_{7G`6)T>X(QW>p z`jS6v03{m?(66#|ywNOFL>xr9?rRS6UWuugTh)izD^0Cfp)kn2T+nvP5m?BNqMPaE z&XXra6G@wCX%lY}E`$&qL9~q4&O$3Q0u3;VN~f8_n7;SiHUyoQuz$a2dtiGwe!0?) zFUX5btPr;S+Mmq^Dyg9aYEa#5*ahuy#C*px8v0I6YaeMk^4J~gYmp?7oOjaZ+!2j2 zki4pboohQWbt`fEvz7U=(NbI!9N$3;K^Zw*EM?QKh-JBru= z{cI`8gJJX8OS=l}^JMzjGx7zTAOxi>d+AZT63rcJc~$T8)Br8l80y>S1_y>1CH}#@xpQxQRYbrQ$yv!Qp zbT(HjQia8y8`Ywt!{KGjdpR|&&gHqnRjHV60zjDQpi~z(gvKw^4oJzt14#pyUPoJM zb8hf?7I<6+dD5HJ>bR?s4Pcd4O^F6V_kW0LrvBpLXV+)(eLip>QpT|I7D}7Be2-CW z2@67bj_u{Nni#?2jjEcaAGr```7qev_ce!p7tiVZROQotT6akQw&woP-a`@$YFx3smm@l=CPzF&8YE6>^ce#?cF}5DjD=JR zjuBlU4?)B9qCvGXZ3CkxypZqIuq-@_rI1qC$Og9>UC4A8c~Ue4iW1XCpXAkB;EMyX zcSBmR*7YI9F;z=)rlM_g5I932K1ffIaS#wXz~8Xn>v@6Z z`_CzevYG+f&XJea-pbJvMF)hZ<4mvTtv)(Hx2+7V0wT?$;cfI4?g5L#AKStxOvn75 z{djRdTUocVw9>z}vVN3joy}Yv+?-9!Tz)pRps3^@5jdEG->1% zI5ni{W#v7<6T{54FtR%q#WXuq=6hC_&gw2s#ru7&-KJQ!A|ndGjS)9Y#4AK#1;`o% z_;Y%Syv~(~95RCUdQzA2cM9FjoL&D^cxd&%C>$S^A7vg<*4aN`QQ$I-JrZ#3vYZ;mzvV zf`nOk8z#kO`#gv|?zA$^q#V<6^-<`j!90T?g8aMVB)Ct50sx*CA0RLA$JM_dE`k1e zxa8jsmi%P?T~G5T697O3oQO<3rENbuoKK`59nSwq`n&$-pX%NPBEkG5{n_n&BL3K? z{1@WyJ%nG0_fG@(q3sXilhOQl-d`)tzw#)Ne)9gTJ3kSB)Sdr}!rwP#zY^u2s@Xpj z{$-2y-=+RFcm5Up_;mB{;Q#3#_<{XBNBR|ONAMH-TgLRiY5hG2{0iM9`W^aTbpD+^ z{Y3tpl^G;}-^}Vs;t#X>hxhbXtNK;q+HbtS8rKv5hjIM_|F1^#D?fnrSH1t@|6)5& b{2#XS7e4gUn)%TWK?K}A#a0EfA9w!;mU0cI literal 0 HcmV?d00001 diff --git a/L14/CMakeLists.txt b/L14/CMakeLists.txt new file mode 100644 index 0000000..244fd97 --- /dev/null +++ b/L14/CMakeLists.txt @@ -0,0 +1,148 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +# Name of the project +PROJECT(L14) + +# FOR LAB MACHINES ONLY! +# DO NOT EDIT +SET(DEF_DIR_GLM "C:\\c++\\glm") +SET(DEF_DIR_GLFW "C:\\c++\\glfw-3.2.1") +SET(DEF_DIR_GLEW "C:\\c++\\glew-2.0.0") +SET(DEF_DIR_EIGEN "C:\\c++\\eigen-eigen-f562a193118d") + +# Is this the solution? +# Override with `cmake -DSOL=ON ..` +OPTION(SOL "Solution" OFF) + +# Use glob to get the list of all source files. +# We don't really need to include header and resource files to build, but it's +# nice to have them also show up in IDEs. +IF(${SOL}) + FILE(GLOB_RECURSE SOURCES "src0/*.cpp") + FILE(GLOB_RECURSE HEADERS "src0/*.h") +ELSE() + FILE(GLOB_RECURSE SOURCES "src/*.cpp") + FILE(GLOB_RECURSE HEADERS "src/*.h") +ENDIF() +FILE(GLOB_RECURSE GLSL "resources/*.glsl") + +# Set the executable. +ADD_EXECUTABLE(${CMAKE_PROJECT_NAME} ${SOURCES} ${HEADERS} ${GLSL}) + +# Get the GLM environment variable. Since GLM is a header-only library, we +# just need to add it to the include directory. +SET(GLM_INCLUDE_DIR "$ENV{GLM_INCLUDE_DIR}") +IF(NOT GLM_INCLUDE_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLM_INCLUDE_DIR to the root directory of your GLM installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLM in ${DEF_DIR_GLM}") + IF(IS_DIRECTORY ${DEF_DIR_GLM}) + MESSAGE(STATUS "Found!") + SET(GLM_INCLUDE_DIR ${DEF_DIR_GLM}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +INCLUDE_DIRECTORIES(${GLM_INCLUDE_DIR}) + +# Get the GLFW environment variable. There should be a CMakeLists.txt in the +# specified directory. +SET(GLFW_DIR "$ENV{GLFW_DIR}") +IF(NOT GLFW_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLFW_DIR to the root directory of your GLFW installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLFW in ${DEF_DIR_GLFW}") + IF(IS_DIRECTORY ${DEF_DIR_GLFW}) + MESSAGE(STATUS "Found!") + SET(GLFW_DIR ${DEF_DIR_GLFW}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +OPTION(GLFW_BUILD_EXAMPLES "GLFW_BUILD_EXAMPLES" OFF) +OPTION(GLFW_BUILD_TESTS "GLFW_BUILD_TESTS" OFF) +OPTION(GLFW_BUILD_DOCS "GLFW_BUILD_DOCS" OFF) +IF(CMAKE_BUILD_TYPE MATCHES Release) + ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/release) +ELSE() + ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/debug) +ENDIF() +INCLUDE_DIRECTORIES(${GLFW_DIR}/include) +TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} glfw ${GLFW_LIBRARIES}) + +# Get the GLEW environment variable. +SET(GLEW_DIR "$ENV{GLEW_DIR}") +IF(NOT GLEW_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLEW_DIR to the root directory of your GLEW installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLEW in ${DEF_DIR_GLEW}") + IF(IS_DIRECTORY ${DEF_DIR_GLEW}) + MESSAGE(STATUS "Found!") + SET(GLEW_DIR ${DEF_DIR_GLEW}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +INCLUDE_DIRECTORIES(${GLEW_DIR}/include) +IF(WIN32) + # With prebuilt binaries + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/Release/Win32/glew32s.lib) +ELSE() + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/libGLEW.a) +ENDIF() + +# Get the EIGEN environment variable. Since EIGEN is a header-only library, we +# just need to add it to the include directory. +SET(EIGEN3_INCLUDE_DIR "$ENV{EIGEN3_INCLUDE_DIR}") +IF(NOT EIGEN3_INCLUDE_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable EIGEN3_INCLUDE_DIR to the root directory of your EIGEN installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for EIGEN in ${DEF_DIR_EIGEN}") + IF(IS_DIRECTORY ${DEF_DIR_EIGEN}) + MESSAGE(STATUS "Found!") + SET(EIGEN3_INCLUDE_DIR ${DEF_DIR_EIGEN}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +INCLUDE_DIRECTORIES(${EIGEN3_INCLUDE_DIR}) + +# OS specific options and libraries +IF(WIN32) + # c++11 is enabled by default. + # -Wall produces way too many warnings. + # -pedantic is not supported. + # Disable warning 4996. + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996") + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} opengl32.lib) +ELSE() + # Enable all pedantic warnings. + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -pedantic") + IF(APPLE) + # Add required frameworks for GLFW. + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "-framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo") + ELSE() + #Link the Linux OpenGL library + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "GL") + ENDIF() +ENDIF() diff --git a/L14/resources/simple_frag.glsl b/L14/resources/simple_frag.glsl new file mode 100644 index 0000000..013f708 --- /dev/null +++ b/L14/resources/simple_frag.glsl @@ -0,0 +1,8 @@ +#version 120 + +varying vec3 fragColor; + +void main() +{ + gl_FragColor = vec4(fragColor, 1.0); +} diff --git a/L14/resources/simple_vert.glsl b/L14/resources/simple_vert.glsl new file mode 100644 index 0000000..d6cc5b4 --- /dev/null +++ b/L14/resources/simple_vert.glsl @@ -0,0 +1,11 @@ +#version 120 + +uniform mat4 P; +uniform mat4 MV; +varying vec3 fragColor; + +void main() +{ + gl_Position = P * MV * gl_Vertex; + fragColor = gl_Color.rgb; +} diff --git a/L14/src/GLSL.cpp b/L14/src/GLSL.cpp new file mode 100644 index 0000000..2969872 --- /dev/null +++ b/L14/src/GLSL.cpp @@ -0,0 +1,152 @@ +// +// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book +// Created by zwood on 2/21/10. +// Modified by sueda 10/15/15. +// + +#include "GLSL.h" +#include +#include +#include +#include + +using namespace std; + +namespace GLSL { + +const char * errorString(GLenum err) +{ + switch(err) { + case GL_NO_ERROR: + return "No error"; + case GL_INVALID_ENUM: + return "Invalid enum"; + case GL_INVALID_VALUE: + return "Invalid value"; + case GL_INVALID_OPERATION: + return "Invalid operation"; + case GL_STACK_OVERFLOW: + return "Stack overflow"; + case GL_STACK_UNDERFLOW: + return "Stack underflow"; + case GL_OUT_OF_MEMORY: + return "Out of memory"; + default: + return "No error"; + } +} + +void checkVersion() +{ + int major, minor; + major = minor = 0; + const char *verstr = (const char *)glGetString(GL_VERSION); + + if((verstr == NULL) || (sscanf(verstr, "%d.%d", &major, &minor) != 2)) { + printf("Invalid GL_VERSION format %d.%d\n", major, minor); + } + if(major < 2) { + printf("This shader example will not work due to the installed Opengl version, which is %d.%d.\n", major, minor); + exit(0); + } +} + +void checkError(const char *str) +{ + GLenum glErr = glGetError(); + if(glErr != GL_NO_ERROR) { + if(str) { + printf("%s: ", str); + } + printf("GL_ERROR = %s.\n", errorString(glErr)); + assert(false); + } +} + +void printShaderInfoLog(GLuint shader) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + GLchar *infoLog = 0; + + checkError(GET_FILE_LINE); + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength); + checkError(GET_FILE_LINE); + + if(infologLength > 0) { + infoLog = (GLchar *)malloc(infologLength); + if(infoLog == NULL) { + puts("ERROR: Could not allocate InfoLog buffer"); + exit(1); + } + glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog); + checkError(GET_FILE_LINE); + printf("Shader InfoLog:\n%s\n\n", infoLog); + free(infoLog); + } +} + +void printProgramInfoLog(GLuint program) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + GLchar *infoLog = 0; + + checkError(GET_FILE_LINE); + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infologLength); + checkError(GET_FILE_LINE); + + if(infologLength > 0) { + infoLog = (GLchar *)malloc(infologLength); + if(infoLog == NULL) { + puts("ERROR: Could not allocate InfoLog buffer"); + exit(1); + } + glGetProgramInfoLog(program, infologLength, &charsWritten, infoLog); + checkError(GET_FILE_LINE); + printf("Program InfoLog:\n%s\n\n", infoLog); + free(infoLog); + } +} + +char *textFileRead(const char *fn) +{ + FILE *fp; + char *content = NULL; + int count = 0; + if(fn != NULL) { + fp = fopen(fn,"rt"); + if(fp != NULL) { + fseek(fp, 0, SEEK_END); + count = (int)ftell(fp); + rewind(fp); + if(count > 0) { + content = (char *)malloc(sizeof(char) * (count+1)); + count = (int)fread(content,sizeof(char),count,fp); + content[count] = '\0'; + } + fclose(fp); + } else { + printf("error loading %s\n", fn); + } + } + return content; +} + +int textFileWrite(const char *fn, const char *s) +{ + FILE *fp; + int status = 0; + if(fn != NULL) { + fp = fopen(fn,"w"); + if(fp != NULL) { + if(fwrite(s,sizeof(char),strlen(s),fp) == strlen(s)) { + status = 1; + } + fclose(fp); + } + } + return(status); +} + +} diff --git a/L14/src/GLSL.h b/L14/src/GLSL.h new file mode 100644 index 0000000..f945fdd --- /dev/null +++ b/L14/src/GLSL.h @@ -0,0 +1,40 @@ +// +// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book +// Created by zwood on 2/21/10. +// Modified by sueda 10/15/15. +// + +#pragma once +#ifndef __GLSL__ +#define __GLSL__ + +#define GLEW_STATIC +#include + +/////////////////////////////////////////////////////////////////////////////// +// For printing out the current file and line number // +/////////////////////////////////////////////////////////////////////////////// +#include + +template +std::string NumberToString(T x) +{ + std::ostringstream ss; + ss << x; + return ss.str(); +} + +#define GET_FILE_LINE (std::string(__FILE__) + ":" + NumberToString(__LINE__)).c_str() +/////////////////////////////////////////////////////////////////////////////// + +namespace GLSL { + + void checkVersion(); + void checkError(const char *str = 0); + void printProgramInfoLog(GLuint program); + void printShaderInfoLog(GLuint shader); + int textFileWrite(const char *filename, const char *s); + char *textFileRead(const char *filename); +} + +#endif diff --git a/L14/src/MatrixStack.cpp b/L14/src/MatrixStack.cpp new file mode 100644 index 0000000..eaa6e6c --- /dev/null +++ b/L14/src/MatrixStack.cpp @@ -0,0 +1,114 @@ +#include "MatrixStack.h" + +#include +#include +#include + +#define GLM_FORCE_RADIANS +#include +#include + +using namespace std; + +MatrixStack::MatrixStack() +{ + mstack = make_shared< stack >(); + mstack->push(glm::mat4(1.0)); +} + +MatrixStack::~MatrixStack() +{ +} + +void MatrixStack::pushMatrix() +{ + const glm::mat4 &top = mstack->top(); + mstack->push(top); + assert(mstack->size() < 100); +} + +void MatrixStack::popMatrix() +{ + assert(!mstack->empty()); + mstack->pop(); + // There should always be one matrix left. + assert(!mstack->empty()); +} + +void MatrixStack::loadIdentity() +{ + glm::mat4 &top = mstack->top(); + top = glm::mat4(1.0); +} + +void MatrixStack::translate(const glm::vec3 &t) +{ + glm::mat4 &top = mstack->top(); + top *= glm::translate(t); +} + +void MatrixStack::translate(float x, float y, float z) +{ + translate(glm::vec3(x, y, z)); +} + +void MatrixStack::scale(const glm::vec3 &s) +{ + glm::mat4 &top = mstack->top(); + top *= glm::scale(s); +} + +void MatrixStack::scale(float x, float y, float z) +{ + scale(glm::vec3(x, y, z)); +} + +void MatrixStack::scale(float s) +{ + scale(glm::vec3(s, s, s)); +} + +void MatrixStack::rotate(float angle, const glm::vec3 &axis) +{ + glm::mat4 &top = mstack->top(); + top *= glm::rotate(angle, axis); +} + +void MatrixStack::rotate(float angle, float x, float y, float z) +{ + rotate(angle, glm::vec3(x, y, z)); +} + +void MatrixStack::multMatrix(const glm::mat4 &matrix) +{ + glm::mat4 &top = mstack->top(); + top *= matrix; +} + +const glm::mat4 &MatrixStack::topMatrix() const +{ + return mstack->top(); +} + +void MatrixStack::print(const glm::mat4 &mat, const char *name) +{ + if(name) { + printf("%s = [\n", name); + } + for(int i = 0; i < 4; ++i) { + for(int j = 0; j < 4; ++j) { + // mat[j] returns the jth column + printf("%- 5.2f ", mat[j][i]); + } + printf("\n"); + } + if(name) { + printf("];"); + } + printf("\n"); +} + +void MatrixStack::print(const char *name) const +{ + print(mstack->top(), name); +} diff --git a/L14/src/MatrixStack.h b/L14/src/MatrixStack.h new file mode 100644 index 0000000..66278ce --- /dev/null +++ b/L14/src/MatrixStack.h @@ -0,0 +1,50 @@ +#pragma once +#ifndef _MatrixStack_H_ +#define _MatrixStack_H_ + +#include +#include +#include + +class MatrixStack +{ +public: + MatrixStack(); + virtual ~MatrixStack(); + + // glPushMatrix(): Copies the current matrix and adds it to the top of the stack + void pushMatrix(); + // glPopMatrix(): Removes the top of the stack and sets the current matrix to be the matrix that is now on top + void popMatrix(); + + // glLoadIdentity(): Sets the top matrix to be the identity + void loadIdentity(); + // glMultMatrix(): Right multiplies the top matrix + void multMatrix(const glm::mat4 &matrix); + + // glTranslate(): Right multiplies the top matrix by a translation matrix + void translate(const glm::vec3 &trans); + void translate(float x, float y, float z); + // glScale(): Right multiplies the top matrix by a scaling matrix + void scale(const glm::vec3 &scale); + void scale(float x, float y, float z); + // glScale(): Right multiplies the top matrix by a scaling matrix + void scale(float size); + // glRotate(): Right multiplies the top matrix by a rotation matrix (angle in radians) + void rotate(float angle, const glm::vec3 &axis); + void rotate(float angle, float x, float y, float z); + + // glGet(GL_MODELVIEW_MATRIX): Gets the top matrix + const glm::mat4 &topMatrix() const; + + // Prints out the specified matrix + static void print(const glm::mat4 &mat, const char *name = 0); + // Prints out the top matrix + void print(const char *name = 0) const; + +private: + std::shared_ptr< std::stack > mstack; + +}; + +#endif diff --git a/L14/src/Program.cpp b/L14/src/Program.cpp new file mode 100644 index 0000000..1e85538 --- /dev/null +++ b/L14/src/Program.cpp @@ -0,0 +1,126 @@ +#include "Program.h" + +#include +#include + +#include "GLSL.h" + +using namespace std; + +Program::Program() : + vShaderName(""), + fShaderName(""), + pid(0), + verbose(true) +{ + +} + +Program::~Program() +{ + +} + +void Program::setShaderNames(const string &v, const string &f) +{ + vShaderName = v; + fShaderName = f; +} + +bool Program::init() +{ + GLint rc; + + // Create shader handles + GLuint VS = glCreateShader(GL_VERTEX_SHADER); + GLuint FS = glCreateShader(GL_FRAGMENT_SHADER); + + // Read shader sources + const char *vshader = GLSL::textFileRead(vShaderName.c_str()); + const char *fshader = GLSL::textFileRead(fShaderName.c_str()); + glShaderSource(VS, 1, &vshader, NULL); + glShaderSource(FS, 1, &fshader, NULL); + + // Compile vertex shader + glCompileShader(VS); + glGetShaderiv(VS, GL_COMPILE_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printShaderInfoLog(VS); + cout << "Error compiling vertex shader " << vShaderName << endl; + } + return false; + } + + // Compile fragment shader + glCompileShader(FS); + glGetShaderiv(FS, GL_COMPILE_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printShaderInfoLog(FS); + cout << "Error compiling fragment shader " << fShaderName << endl; + } + return false; + } + + // Create the program and link + pid = glCreateProgram(); + glAttachShader(pid, VS); + glAttachShader(pid, FS); + glLinkProgram(pid); + glGetProgramiv(pid, GL_LINK_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printProgramInfoLog(pid); + cout << "Error linking shaders " << vShaderName << " and " << fShaderName << endl; + } + return false; + } + + GLSL::checkError(GET_FILE_LINE); + return true; +} + +void Program::bind() +{ + glUseProgram(pid); +} + +void Program::unbind() +{ + glUseProgram(0); +} + +void Program::addAttribute(const string &name) +{ + attributes[name] = glGetAttribLocation(pid, name.c_str()); +} + +void Program::addUniform(const string &name) +{ + uniforms[name] = glGetUniformLocation(pid, name.c_str()); +} + +GLint Program::getAttribute(const string &name) const +{ + map::const_iterator attribute = attributes.find(name.c_str()); + if(attribute == attributes.end()) { + if(isVerbose()) { + cout << name << " is not an attribute variable" << endl; + } + return -1; + } + return attribute->second; +} + +GLint Program::getUniform(const string &name) const +{ + map::const_iterator uniform = uniforms.find(name.c_str()); + if(uniform == uniforms.end()) { + if(isVerbose()) { + cout << name << " is not a uniform variable" << endl; + } + return -1; + } + return uniform->second; +} diff --git a/L14/src/Program.h b/L14/src/Program.h new file mode 100644 index 0000000..51e58bb --- /dev/null +++ b/L14/src/Program.h @@ -0,0 +1,44 @@ +#pragma once +#ifndef __Program__ +#define __Program__ + +#include +#include + +#define GLEW_STATIC +#include + +/** + * An OpenGL Program (vertex and fragment shaders) + */ +class Program +{ +public: + Program(); + virtual ~Program(); + + void setVerbose(bool v) { verbose = v; } + bool isVerbose() const { return verbose; } + + void setShaderNames(const std::string &v, const std::string &f); + virtual bool init(); + virtual void bind(); + virtual void unbind(); + + void addAttribute(const std::string &name); + void addUniform(const std::string &name); + GLint getAttribute(const std::string &name) const; + GLint getUniform(const std::string &name) const; + +protected: + std::string vShaderName; + std::string fShaderName; + +private: + GLuint pid; + std::map attributes; + std::map uniforms; + bool verbose; +}; + +#endif diff --git a/L14/src/main.cpp b/L14/src/main.cpp new file mode 100644 index 0000000..df0df77 --- /dev/null +++ b/L14/src/main.cpp @@ -0,0 +1,230 @@ +#include +#include + +#define GLEW_STATIC +#include +#include + +#define GLM_FORCE_RADIANS +#include +#include +#include + +#define EIGEN_DONT_ALIGN_STATICALLY +#include + +#include "GLSL.h" +#include "Program.h" +#include "MatrixStack.h" + +using namespace std; + +GLFWwindow *window; // Main application window +string RESOURCE_DIR = ""; // Where the resources are loaded from +shared_ptr prog; + +bool keyToggles[256] = {false}; // only for English keyboards! +glm::vec2 mouse; + +Eigen::Vector4f coeffs0; +Eigen::Vector4f coeffs1; +float xmid; + +static void error_callback(int error, const char *description) +{ + cerr << description << endl; +} + +static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) +{ + if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, GL_TRUE); + } +} + +static void char_callback(GLFWwindow *window, unsigned int key) +{ + keyToggles[key] = !keyToggles[key]; +} + +static void cursor_position_callback(GLFWwindow* window, double xmouse, double ymouse) +{ + // Convert from window coords to world coords + // (Assumes orthographic projection) + int width, height; + glfwGetWindowSize(window, &width, &height); + glm::vec4 p; + // Inverse of viewing transform + p.x = xmouse / (float)width; + p.y = (height - ymouse) / (float)height; + p.x = 2.0f * (p.x - 0.5f); + p.y = 2.0f * (p.y - 0.5f); + p.z = 0.0f; + p.w = 1.0f; + // Inverse of model-view-projection transform + auto P = make_shared(); + auto MV = make_shared(); + float aspect = (float)width/height; + float s = 0.6f; + P->multMatrix(glm::ortho(-s*aspect, s*aspect, -s, s)); + MV->translate(glm::vec3(-0.5, -0.5, 0.0)); + p = glm::inverse(P->topMatrix() * MV->topMatrix()) * p; + mouse = glm::vec2(p); +} + +void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) +{ + // Not used for this lab +} + +static void init() +{ + GLSL::checkVersion(); + + // Set background color + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + // Enable z-buffer test + glEnable(GL_DEPTH_TEST); + + // Initialize the GLSL program. + prog = make_shared(); + prog->setVerbose(false); // Set this to true when debugging. + prog->setShaderNames(RESOURCE_DIR + "simple_vert.glsl", RESOURCE_DIR + "simple_frag.glsl"); + prog->init(); + prog->addUniform("P"); + prog->addUniform("MV"); + + // + // Compute the coefficients here + // + xmid = 0.4f; + coeffs0 << -2.0f, 3.0f, 0.0f, 0.0f; + coeffs1 << -2.0f, 3.0f, 0.0f, 0.0f; + + // If there were any OpenGL errors, this will print something. + // You can intersperse this line in your code to find the exact location + // of your OpenGL error. + GLSL::checkError(GET_FILE_LINE); +} + +void render() +{ + // Get current frame buffer size. + int width, height; + glfwGetFramebufferSize(window, &width, &height); + glViewport(0, 0, width, height); + + // Clear buffers + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + auto P = make_shared(); + auto MV = make_shared(); + P->pushMatrix(); + MV->pushMatrix(); + + float aspect = (float)width/height; + float s = 0.6f; + P->multMatrix(glm::ortho(-s*aspect, s*aspect, -s, s)); + MV->translate(glm::vec3(-0.5, -0.5, 0.0)); + + // Bind the program + prog->bind(); + glUniformMatrix4fv(prog->getUniform("P"), 1, GL_FALSE, glm::value_ptr(P->topMatrix())); + glUniformMatrix4fv(prog->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix())); + + // Draw grid + int gridSize = 5; + glLineWidth(2.0f); + glColor3f(0.2f, 0.2f, 0.2f); + glBegin(GL_LINES); + for(int i = 1; i < gridSize; ++i) { + float x = i / (float)gridSize; + glVertex2f(x, 0.0f); + glVertex2f(x, 1.0f); + } + for(int i = 1; i < gridSize; ++i) { + float y = i / (float)gridSize; + glVertex2f(0.0f, y); + glVertex2f(1.0f, y); + } + glEnd(); + glLineWidth(4.0f); + glColor3f(0.8f, 0.8f, 0.8f); + glBegin(GL_LINE_LOOP); + glVertex2f(0.0f, 0.0f); + glVertex2f(1.0f, 0.0f); + glVertex2f(1.0f, 1.0f); + glVertex2f(0.0f, 1.0f); + glEnd(); + + // + // Draw cubics here + // + + // Unbind the program + prog->unbind(); + + // Pop matrix stacks. + MV->popMatrix(); + P->popMatrix(); + + GLSL::checkError(GET_FILE_LINE); +} + +int main(int argc, char **argv) +{ + if(argc < 2) { + cout << "Please specify the resource directory." << endl; + return 0; + } + RESOURCE_DIR = argv[1] + string("/"); + + // Set error callback. + glfwSetErrorCallback(error_callback); + // Initialize the library. + if(!glfwInit()) { + return -1; + } + // Create a windowed mode window and its OpenGL context. + window = glfwCreateWindow(640, 480, "YOUR NAME", NULL, NULL); + if(!window) { + glfwTerminate(); + return -1; + } + // Make the window's context current. + glfwMakeContextCurrent(window); + // Initialize GLEW. + glewExperimental = true; + if(glewInit() != GLEW_OK) { + cerr << "Failed to initialize GLEW" << endl; + return -1; + } + glGetError(); // A bug in glewInit() causes an error that we can safely ignore. + cout << "OpenGL version: " << glGetString(GL_VERSION) << endl; + cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl; + // Set vsync. + glfwSwapInterval(1); + // Set keyboard callback. + glfwSetKeyCallback(window, key_callback); + // Set char callback. + glfwSetCharCallback(window, char_callback); + // Set cursor position callback. + glfwSetCursorPosCallback(window, cursor_position_callback); + // Set mouse button callback. + glfwSetMouseButtonCallback(window, mouse_button_callback); + // Initialize scene. + init(); + // Loop until the user closes the window. + while(!glfwWindowShouldClose(window)) { + // Render scene. + render(); + // Swap front and back buffers. + glfwSwapBuffers(window); + // Poll for and process events. + glfwPollEvents(); + } + // Quit program. + glfwDestroyWindow(window); + glfwTerminate(); + return 0; +} diff --git a/L15.zip b/L15.zip new file mode 100644 index 0000000000000000000000000000000000000000..8d487583746e82d44bc1878512a6ff37e36c2057 GIT binary patch literal 109737 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

  • `<#B`{se5Ax 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

    Xui4T70$Kd-#&sKu9KNYdBde&ms5iPF={s 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 literal 0 HcmV?d00001 diff --git a/L15/CMakeLists.txt b/L15/CMakeLists.txt new file mode 100644 index 0000000..a0b5061 --- /dev/null +++ b/L15/CMakeLists.txt @@ -0,0 +1,127 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +# Name of the project +PROJECT(L15) + +# FOR LAB MACHINES ONLY! +# DO NOT EDIT +SET(DEF_DIR_GLM "C:\\c++\\glm") +SET(DEF_DIR_GLFW "C:\\c++\\glfw-3.2.1") +SET(DEF_DIR_GLEW "C:\\c++\\glew-2.0.0") + +# Is this the solution? +# Override with `cmake -DSOL=ON ..` +OPTION(SOL "Solution" OFF) + +# Use glob to get the list of all source files. +# We don't really need to include header and resource files to build, but it's +# nice to have them also show up in IDEs. +IF(${SOL}) + FILE(GLOB_RECURSE SOURCES "src0/*.cpp") + FILE(GLOB_RECURSE HEADERS "src0/*.h") + FILE(GLOB_RECURSE GLSL "resources0/*.glsl") +ELSE() + FILE(GLOB_RECURSE SOURCES "src/*.cpp") + FILE(GLOB_RECURSE HEADERS "src/*.h") + FILE(GLOB_RECURSE GLSL "resources/*.glsl") +ENDIF() + +# Set the executable. +ADD_EXECUTABLE(${CMAKE_PROJECT_NAME} ${SOURCES} ${HEADERS} ${GLSL}) + +# Get the GLM environment variable. Since GLM is a header-only library, we +# just need to add it to the include directory. +SET(GLM_INCLUDE_DIR "$ENV{GLM_INCLUDE_DIR}") +IF(NOT GLM_INCLUDE_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLM_INCLUDE_DIR to the root directory of your GLM installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLM in ${DEF_DIR_GLM}") + IF(IS_DIRECTORY ${DEF_DIR_GLM}) + MESSAGE(STATUS "Found!") + SET(GLM_INCLUDE_DIR ${DEF_DIR_GLM}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +INCLUDE_DIRECTORIES(${GLM_INCLUDE_DIR}) + +# Get the GLFW environment variable. There should be a CMakeLists.txt in the +# specified directory. +SET(GLFW_DIR "$ENV{GLFW_DIR}") +IF(NOT GLFW_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLFW_DIR to the root directory of your GLFW installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLFW in ${DEF_DIR_GLFW}") + IF(IS_DIRECTORY ${DEF_DIR_GLFW}) + MESSAGE(STATUS "Found!") + SET(GLFW_DIR ${DEF_DIR_GLFW}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +OPTION(GLFW_BUILD_EXAMPLES "GLFW_BUILD_EXAMPLES" OFF) +OPTION(GLFW_BUILD_TESTS "GLFW_BUILD_TESTS" OFF) +OPTION(GLFW_BUILD_DOCS "GLFW_BUILD_DOCS" OFF) +IF(CMAKE_BUILD_TYPE MATCHES Release) + ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/release) +ELSE() + ADD_SUBDIRECTORY(${GLFW_DIR} ${GLFW_DIR}/debug) +ENDIF() +INCLUDE_DIRECTORIES(${GLFW_DIR}/include) +TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} glfw ${GLFW_LIBRARIES}) + +# Get the GLEW environment variable. +SET(GLEW_DIR "$ENV{GLEW_DIR}") +IF(NOT GLEW_DIR) + # The environment variable was not set + SET(ERR_MSG "Please point the environment variable GLEW_DIR to the root directory of your GLEW installation.") + IF(WIN32) + # On Windows, try the default location + MESSAGE(STATUS "Looking for GLEW in ${DEF_DIR_GLEW}") + IF(IS_DIRECTORY ${DEF_DIR_GLEW}) + MESSAGE(STATUS "Found!") + SET(GLEW_DIR ${DEF_DIR_GLEW}) + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR ${ERR_MSG}) + ENDIF() +ENDIF() +INCLUDE_DIRECTORIES(${GLEW_DIR}/include) +IF(WIN32) + # With prebuilt binaries + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/Release/Win32/glew32s.lib) +ELSE() + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} ${GLEW_DIR}/lib/libGLEW.a) +ENDIF() + +# OS specific options and libraries +IF(WIN32) + # c++11 is enabled by default. + # -Wall produces way too many warnings. + # -pedantic is not supported. + # Disable warning 4996. + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996") + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} opengl32.lib) +ELSE() + # Enable all pedantic warnings. + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -pedantic") + IF(APPLE) + # Add required frameworks for GLFW. + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "-framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo") + ELSE() + #Link the Linux OpenGL library + TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} "GL") + ENDIF() +ENDIF() diff --git a/L15/resources/man.obj b/L15/resources/man.obj new file mode 100755 index 0000000..1a82b8a --- /dev/null +++ b/L15/resources/man.obj @@ -0,0 +1,1011 @@ +# Blender v2.72 (sub 0) OBJ File: 'man.blend' +# www.blender.org +v -0.174310 0.920624 -0.000289 +v -0.232033 0.864814 -0.000289 +v -0.184773 0.776970 -0.000249 +v -0.031451 0.974404 -0.000289 +v -0.112441 0.953219 -0.000289 +v -0.020225 0.907381 -0.000273 +v 0.067055 0.953905 -0.000289 +v 0.067100 0.898140 -0.000274 +v 0.140559 0.911325 -0.000289 +v 0.081012 0.819952 -0.000243 +v 0.202521 0.844408 -0.000289 +v 0.176045 0.746004 -0.000251 +v 0.245642 0.648294 -0.000289 +v 0.239879 0.740713 -0.000289 +v 0.166934 0.469143 0.000104 +v 0.215039 0.545854 -0.000050 +v 0.112626 0.545376 0.000114 +v 0.164697 0.414038 0.001546 +v 0.133972 0.470816 0.000562 +v 0.275649 0.348967 -0.000112 +v 0.349159 0.404924 -0.000288 +v 0.287089 0.386612 -0.000288 +v 0.717288 0.203351 -0.000288 +v 0.737644 0.261981 -0.000288 +v 0.650934 0.318537 -0.000285 +v 0.586837 0.209929 -0.000282 +v 0.672870 0.153522 -0.000283 +v 0.590032 0.125043 -0.000288 +v 0.506512 0.110512 -0.000288 +v 0.325223 0.190942 -0.000198 +v 0.267996 0.112874 -0.000215 +v 0.341582 0.088427 -0.000288 +v 0.210656 -0.022271 -0.000251 +v 0.256154 -0.008662 -0.000288 +v 0.206005 0.050973 -0.000212 +v 0.281919 0.060083 -0.000288 +v 0.192437 -0.180342 -0.000261 +v 0.242412 -0.165780 -0.000288 +v 0.250207 -0.085619 -0.000288 +v -0.247861 0.560698 -0.000288 +v -0.191062 0.534951 -0.000237 +v -0.212039 0.603174 -0.000243 +v -0.220531 0.520836 -0.000288 +v -0.194543 0.454610 -0.000288 +v -0.136822 0.481723 -0.000145 +v -0.167534 0.393094 -0.000138 +v -0.221547 0.401628 -0.000075 +v -0.705156 0.152890 -0.000288 +v -0.659854 0.181431 -0.000288 +v -0.702237 0.237223 -0.000288 +v -0.762144 0.202317 -0.000288 +v -0.780294 0.258432 -0.000288 +v -0.232984 0.006345 -0.000240 +v -0.286391 0.090035 -0.000253 +v -0.326502 0.051703 -0.000288 +v -0.092330 -0.622332 -0.000288 +v -0.047760 -0.520907 0.000077 +v -0.129674 -0.527467 0.000011 +v -0.194675 -0.587636 0.000286 +v -0.175140 -0.794356 0.002550 +v -0.138877 -0.719272 0.000506 +v -0.187779 -0.695071 0.001011 +v -0.250996 -0.780314 0.002193 +v -0.204688 -0.846960 0.001706 +v -0.248608 -0.844067 0.004445 +v -0.241400 -0.895867 0.010094 +v -0.297349 -0.853130 0.003788 +v -0.303781 -0.952134 0.003534 +v -0.370554 -0.884294 0.001430 +v -0.376588 -0.986662 -0.000288 +v -0.507027 -0.863319 -0.000288 +v -0.492885 -0.913644 -0.000288 +v -0.439029 -0.909757 0.000113 +v -0.449295 -0.968642 -0.000288 +v -0.437824 -0.841979 0.000400 +v -0.268441 -0.334316 -0.000183 +v -0.299484 -0.394070 -0.000288 +v -0.242708 -0.351270 -0.000176 +v -0.273557 -0.255273 -0.000288 +v -0.145000 -0.323362 -0.000125 +v -0.221513 -0.233589 -0.000221 +v -0.045432 -0.383202 -0.000089 +v -0.037517 -0.246287 -0.000164 +v 0.034321 -0.325439 -0.000163 +v 0.095659 -0.204769 -0.000212 +v 0.193418 -0.322804 -0.000259 +v 0.232096 -0.237095 -0.000288 +v 0.167110 -0.259660 -0.000247 +v 0.121946 -0.353292 -0.000214 +v 0.204825 -0.425113 -0.000257 +v 0.241114 -0.338859 -0.000288 +v 0.260472 -0.495633 -0.000271 +v 0.203050 -0.518682 -0.000254 +v 0.276615 -0.577627 -0.000269 +v 0.325439 -0.505835 -0.000288 +v 0.121343 -0.495606 -0.000223 +v 0.036950 -0.439643 -0.000136 +v -0.113578 -0.443566 -0.000025 +v -0.200023 -0.462890 0.000001 +v -0.290934 -0.455386 -0.000127 +v -0.283591 -0.551544 0.000168 +v -0.274655 -0.666513 0.000816 +v -0.362134 -0.622412 0.000209 +v -0.368756 -0.762101 0.001033 +v -0.503754 -0.790425 -0.000288 +v -0.452780 -0.657739 -0.000288 +v 0.151998 -0.599431 -0.000254 +v 0.093345 -0.573665 -0.000242 +v 0.085178 -0.698469 -0.000262 +v 0.221705 -0.691757 -0.000238 +v 0.062754 -0.640209 -0.000288 +v 0.210307 -0.781728 -0.000190 +v 0.311407 -0.773152 -0.000111 +v 0.407225 -0.656058 -0.000288 +v 0.401251 -0.780689 -0.000150 +v 0.454954 -0.748515 -0.000288 +v 0.366414 -0.575988 -0.000288 +v 0.368192 -0.868285 0.000225 +v 0.441437 -0.916451 -0.001961 +v 0.464480 -0.857436 -0.000288 +v 0.109210 -0.755835 -0.000288 +v 0.149453 -0.827501 -0.000288 +v 0.259760 -0.860395 -0.000026 +v 0.318196 -0.922742 0.000760 +v 0.167141 -0.129127 -0.000244 +v -0.010417 -0.098224 -0.000191 +v -0.154229 -0.142724 -0.000204 +v 0.013041 0.036201 -0.000162 +v -0.109715 0.014012 -0.000190 +v 0.130260 -0.045777 -0.000213 +v 0.109795 0.086620 -0.000141 +v 0.185253 0.173944 -0.000090 +v 0.069941 0.238059 0.000033 +v 0.097840 0.160601 -0.000073 +v 0.026376 0.143771 -0.000094 +v -0.064305 0.224337 -0.000078 +v -0.205642 0.165675 -0.000198 +v -0.068050 0.116800 -0.000144 +v -0.300731 0.137482 -0.000250 +v -0.344792 0.205245 -0.000260 +v -0.431295 0.249919 -0.000277 +v -0.426617 0.172392 -0.000280 +v -0.525160 0.216256 -0.000285 +v -0.608376 0.120225 -0.000288 +v -0.623648 0.215389 -0.000287 +v -0.534162 0.325831 -0.000287 +v -0.622612 0.321807 -0.000287 +v -0.516223 0.436304 -0.000288 +v -0.472653 0.328957 -0.000284 +v -0.441824 0.418686 -0.000288 +v -0.387250 0.326747 -0.000277 +v -0.295912 0.295529 -0.000248 +v -0.206276 0.311407 -0.000180 +v -0.147257 0.255547 -0.000135 +v -0.112800 0.320762 -0.000081 +v -0.012698 0.329732 0.000068 +v 0.097670 0.355994 0.000385 +v 0.159454 0.278017 0.000115 +v 0.198632 0.348622 0.000278 +v 0.245777 0.273459 -0.000032 +v 0.330454 0.300260 -0.000185 +v 0.378039 0.258738 -0.000224 +v 0.408880 0.324525 -0.000254 +v 0.447599 0.219224 -0.000259 +v 0.522619 0.339316 -0.000278 +v 0.091636 0.454703 0.000486 +v 0.204401 0.389945 0.000206 +v -0.078720 0.410446 -0.000023 +v 0.012035 0.428777 0.000172 +v -0.054493 0.508569 -0.000018 +v -0.134574 0.588659 -0.000164 +v -0.203968 0.676489 -0.000237 +v -0.017695 0.628588 -0.000082 +v -0.125929 0.687110 -0.000187 +v 0.111173 0.676651 -0.000146 +v 0.171119 0.604044 -0.000093 +v 0.028820 0.513206 0.000134 +v 0.009464 0.744289 -0.000183 +v -0.038539 0.831417 -0.000238 +v -0.088631 0.764834 -0.000205 +v -0.222029 0.371072 -0.000171 +v -0.249009 -0.099700 -0.000259 +v -0.227667 -0.160984 -0.000243 +v -0.285916 -0.167920 -0.000288 +v -0.340673 -0.458118 -0.000288 +v -0.379124 -0.514424 -0.000182 +v -0.413897 -0.582149 -0.000288 +v 0.037287 -0.559413 -0.000203 +v -0.299401 -0.034586 -0.000288 +v -0.366096 0.088968 -0.000288 +v -0.465739 0.101568 -0.000288 +v -0.541340 0.110214 -0.000288 +v -0.761948 0.328294 -0.000288 +v -0.614534 0.403924 -0.000288 +v -0.385524 0.402954 -0.000288 +v -0.338753 0.385937 -0.000288 +v -0.292754 0.378157 -0.000288 +v -0.282728 0.655069 -0.000289 +v -0.283763 0.747946 -0.000289 +v 0.720891 0.367685 -0.000288 +v 0.659476 0.414618 -0.000283 +v 0.611785 0.432872 -0.000288 +v 0.425412 0.424686 -0.000288 +v 0.242780 0.379924 -0.000158 +v 0.526886 0.445441 -0.000288 +v 0.405085 0.100604 -0.000288 +v -0.616310 0.446347 -0.000288 +v -0.702987 0.411238 -0.000288 +v 0.380813 -0.967124 0.003350 +v 0.320734 -0.966588 0.000539 +v 0.261481 -0.951321 -0.000288 +v 0.199280 -0.898034 -0.000288 +v 0.292429 -0.450910 -0.000288 +v -0.293855 -0.098328 -0.000288 +vt 0.416652 0.953823 +vt 0.388517 0.926621 +vt 0.411552 0.883804 +vt 0.486284 0.980037 +vt 0.446808 0.969711 +vt 0.491756 0.947368 +vt 0.534298 0.970045 +vt 0.534320 0.942864 +vt 0.570125 0.949291 +vt 0.541101 0.904754 +vt 0.600327 0.916674 +vt 0.587422 0.868710 +vt 0.621345 0.821084 +vt 0.618536 0.866131 +vt 0.582981 0.733763 +vt 0.606429 0.771153 +vt 0.556510 0.770920 +vt 0.581891 0.706903 +vt 0.566915 0.734578 +vt 0.635971 0.675187 +vt 0.671801 0.702461 +vt 0.641547 0.693536 +vt 0.851234 0.604211 +vt 0.861156 0.632788 +vt 0.818892 0.660354 +vt 0.787650 0.607417 +vt 0.829584 0.579923 +vt 0.789207 0.566042 +vt 0.748498 0.558959 +vt 0.660134 0.598162 +vt 0.632241 0.560110 +vt 0.668108 0.548194 +vt 0.604292 0.494238 +vt 0.626469 0.500872 +vt 0.602025 0.529939 +vt 0.639027 0.534379 +vt 0.595411 0.417192 +vt 0.619770 0.424289 +vt 0.623570 0.463361 +vt 0.380802 0.778388 +vt 0.408487 0.765839 +vt 0.398262 0.799092 +vt 0.394123 0.758959 +vt 0.406790 0.726679 +vt 0.434924 0.739895 +vt 0.419955 0.696695 +vt 0.393628 0.700855 +vt 0.157907 0.579615 +vt 0.179989 0.593527 +vt 0.159330 0.620721 +vt 0.130130 0.603707 +vt 0.121284 0.631058 +vt 0.388053 0.508186 +vt 0.362021 0.548978 +vt 0.342471 0.530295 +vt 0.456611 0.201757 +vt 0.478335 0.251194 +vt 0.438409 0.247996 +vt 0.406726 0.218668 +vt 0.416248 0.117909 +vt 0.433923 0.154507 +vt 0.410087 0.166303 +vt 0.379274 0.124754 +vt 0.401845 0.092269 +vt 0.380438 0.093679 +vt 0.383951 0.068431 +vt 0.356680 0.089262 +vt 0.353546 0.041005 +vt 0.320999 0.074072 +vt 0.318058 0.024176 +vt 0.254479 0.084295 +vt 0.261372 0.059766 +vt 0.287623 0.061661 +vt 0.282619 0.032959 +vt 0.288210 0.094697 +vt 0.370771 0.342141 +vt 0.355640 0.313016 +vt 0.383314 0.333878 +vt 0.368277 0.380668 +vt 0.430938 0.347481 +vt 0.393644 0.391238 +vt 0.479470 0.318313 +vt 0.483328 0.385048 +vt 0.518343 0.346468 +vt 0.548240 0.405285 +vt 0.595890 0.347753 +vt 0.614742 0.389529 +vt 0.583067 0.378530 +vt 0.561053 0.332892 +vt 0.601450 0.297886 +vt 0.619138 0.339927 +vt 0.628573 0.263512 +vt 0.600585 0.252278 +vt 0.636441 0.223547 +vt 0.660240 0.258540 +vt 0.560759 0.263526 +vt 0.519624 0.290803 +vt 0.446254 0.288891 +vt 0.404119 0.279472 +vt 0.359807 0.283130 +vt 0.363386 0.236261 +vt 0.367742 0.180222 +vt 0.325103 0.201718 +vt 0.321875 0.133631 +vt 0.256075 0.119825 +vt 0.280921 0.184499 +vt 0.575701 0.212919 +vt 0.547112 0.225478 +vt 0.543132 0.164646 +vt 0.609678 0.167918 +vt 0.532202 0.193043 +vt 0.604122 0.124064 +vt 0.653400 0.128244 +vt 0.700104 0.185318 +vt 0.697192 0.124571 +vt 0.723367 0.140253 +vt 0.680211 0.224346 +vt 0.681078 0.081875 +vt 0.716779 0.058398 +vt 0.728011 0.087163 +vt 0.554845 0.136685 +vt 0.574460 0.101753 +vt 0.628226 0.085721 +vt 0.656709 0.055331 +vt 0.583082 0.442155 +vt 0.496537 0.457217 +vt 0.426440 0.435527 +vt 0.507970 0.522739 +vt 0.448137 0.511923 +vt 0.565105 0.482781 +vt 0.555130 0.547314 +vt 0.591910 0.589877 +vt 0.535705 0.621128 +vt 0.549303 0.583373 +vt 0.514470 0.575171 +vt 0.470271 0.614440 +vt 0.401380 0.585847 +vt 0.468445 0.562024 +vt 0.355032 0.572105 +vt 0.333556 0.605134 +vt 0.291393 0.626909 +vt 0.293673 0.589121 +vt 0.245641 0.610501 +vt 0.205080 0.563693 +vt 0.197636 0.610078 +vt 0.241253 0.663910 +vt 0.198141 0.661949 +vt 0.249997 0.717757 +vt 0.271234 0.665434 +vt 0.286260 0.709169 +vt 0.312861 0.664356 +vt 0.357381 0.649140 +vt 0.401071 0.656879 +vt 0.429838 0.629652 +vt 0.446633 0.661439 +vt 0.495425 0.665811 +vt 0.549220 0.678612 +vt 0.579335 0.640604 +vt 0.598431 0.675019 +vt 0.621411 0.638383 +vt 0.662684 0.651446 +vt 0.685878 0.631208 +vt 0.700910 0.663273 +vt 0.719782 0.611947 +vt 0.756348 0.670483 +vt 0.546279 0.726724 +vt 0.601243 0.695160 +vt 0.463244 0.705153 +vt 0.507480 0.714088 +vt 0.475053 0.752980 +vt 0.436020 0.792017 +vt 0.402196 0.834827 +vt 0.492989 0.811479 +vt 0.440234 0.840004 +vt 0.555802 0.834906 +vt 0.585021 0.799516 +vt 0.515662 0.755240 +vt 0.506227 0.867874 +vt 0.482830 0.910342 +vt 0.458414 0.877888 +vt 0.393393 0.685961 +vt 0.380242 0.456498 +vt 0.390645 0.426627 +vt 0.362253 0.423246 +vt 0.335564 0.281798 +vt 0.316822 0.254354 +vt 0.299873 0.221343 +vt 0.519789 0.232425 +vt 0.355680 0.488236 +vt 0.323172 0.548458 +vt 0.274604 0.554600 +vt 0.237755 0.558814 +vt 0.130226 0.665110 +vt 0.202079 0.701974 +vt 0.313703 0.701501 +vt 0.336499 0.693207 +vt 0.358920 0.689415 +vt 0.363807 0.824387 +vt 0.363303 0.869657 +vt 0.852990 0.684310 +vt 0.823055 0.707186 +vt 0.799810 0.716084 +vt 0.708968 0.712094 +vt 0.619950 0.690276 +vt 0.758429 0.722210 +vt 0.699060 0.554130 +vt 0.201213 0.722651 +vt 0.158965 0.705539 +vt 0.687230 0.033699 +vt 0.657946 0.033960 +vt 0.629065 0.041402 +vt 0.598747 0.067375 +vt 0.644150 0.285312 +vt 0.358384 0.457166 +vn -0.000300 0.000300 1.000000 +vn -0.000100 0.000200 1.000000 +vn 0.000100 0.000200 1.000000 +vn 0.000000 0.000300 1.000000 +vn 0.000200 0.000300 1.000000 +vn 0.000100 0.000400 1.000000 +vn 0.000300 0.000300 1.000000 +vn 0.000600 0.000000 1.000000 +vn 0.001600 0.001000 1.000000 +vn 0.015200 0.025500 0.999600 +vn -0.001500 0.005100 1.000000 +vn 0.000000 -0.000000 1.000000 +vn 0.000100 0.000000 1.000000 +vn -0.000000 -0.000100 1.000000 +vn 0.000700 -0.000800 1.000000 +vn 0.001000 -0.000500 1.000000 +vn 0.001000 -0.000400 1.000000 +vn 0.000600 -0.000100 1.000000 +vn -0.001000 -0.000200 1.000000 +vn -0.001300 -0.000900 1.000000 +vn -0.001500 -0.000600 1.000000 +vn -0.003000 0.001100 1.000000 +vn 0.001700 0.003200 1.000000 +vn -0.000600 -0.000200 1.000000 +vn -0.000500 -0.003400 1.000000 +vn 0.005200 -0.001100 1.000000 +vn 0.019200 0.017900 0.999700 +vn -0.001900 0.015300 0.999900 +vn -0.006900 -0.012100 0.999900 +vn 0.064700 0.037700 0.997200 +vn 0.069500 0.117700 0.990600 +vn -0.032700 0.103900 0.994100 +vn -0.032000 -0.000500 0.999500 +vn -0.045800 -0.014100 0.998900 +vn -0.007300 -0.002000 1.000000 +vn -0.007000 -0.005600 1.000000 +vn -0.008700 -0.004100 1.000000 +vn -0.001100 -0.001200 1.000000 +vn 0.000600 0.001400 1.000000 +vn -0.000700 0.000500 1.000000 +vn -0.001600 0.000700 1.000000 +vn -0.000000 0.000600 1.000000 +vn 0.000500 0.000500 1.000000 +vn 0.000600 0.000100 1.000000 +vn 0.000300 0.000000 1.000000 +vn 0.000300 0.000100 1.000000 +vn 0.000400 0.000000 1.000000 +vn 0.001000 -0.000100 1.000000 +vn 0.001400 0.001200 1.000000 +vn -0.000100 0.001200 1.000000 +vn -0.001200 0.003000 1.000000 +vn -0.000400 0.002300 1.000000 +vn -0.000000 0.006700 1.000000 +vn 0.001000 0.005700 1.000000 +vn -0.004300 0.005300 1.000000 +vn -0.003900 0.006100 1.000000 +vn -0.009900 0.000700 1.000000 +vn -0.013100 0.003400 0.999900 +vn -0.010600 0.004100 0.999900 +vn -0.008200 0.010400 0.999900 +vn 0.001900 0.012500 0.999900 +vn 0.000200 0.000400 1.000000 +vn 0.002000 0.002400 1.000000 +vn 0.000100 -0.000300 1.000000 +vn -0.000200 0.000000 1.000000 +vn -0.000500 0.000300 1.000000 +vn -0.000100 -0.000700 1.000000 +vn -0.000800 0.000600 1.000000 +vn -0.000000 0.001500 1.000000 +vn 0.000500 0.001100 1.000000 +vn 0.002000 0.001000 1.000000 +vn 0.000200 0.000200 1.000000 +vn 0.000200 0.000100 1.000000 +vn 0.008900 -0.031800 0.999500 +vn -0.001100 -0.000600 1.000000 +vn -0.001500 0.011200 0.999900 +vn 0.005100 0.002400 1.000000 +vn 0.000800 0.004000 1.000000 +vn -0.002100 0.002200 1.000000 +vn -0.000900 0.001500 1.000000 +vn -0.002200 0.000700 1.000000 +vn -0.000200 -0.000500 1.000000 +vn 0.000300 -0.000200 1.000000 +vn 0.000100 -0.000100 1.000000 +vn 0.000500 -0.000100 1.000000 +vn 0.000500 0.000000 1.000000 +vn -0.000200 0.000200 1.000000 +vn -0.000200 -0.000200 1.000000 +vn -0.000100 -0.000100 1.000000 +vn 0.000100 -0.000500 1.000000 +vn 0.000300 -0.000300 1.000000 +vn 0.000600 -0.000500 1.000000 +vn 0.000400 -0.000900 1.000000 +vn 0.000400 -0.001200 1.000000 +vn 0.000000 -0.001400 1.000000 +vn -0.000600 -0.000600 1.000000 +vn -0.000400 -0.000600 1.000000 +vn -0.000700 -0.001000 1.000000 +vn -0.000500 -0.000200 1.000000 +vn -0.000100 -0.000000 1.000000 +vn -0.000300 0.000000 1.000000 +vn -0.000200 0.000100 1.000000 +vn -0.000700 -0.000100 1.000000 +vn -0.000400 0.000100 1.000000 +vn -0.001000 -0.000300 1.000000 +vn -0.000900 -0.000100 1.000000 +vn -0.001400 -0.000700 1.000000 +vn -0.000800 -0.000400 1.000000 +vn -0.002300 -0.002500 1.000000 +vn 0.000500 -0.003100 1.000000 +vn 0.000900 -0.002800 1.000000 +vn 0.005100 -0.000900 1.000000 +vn 0.001500 -0.003200 1.000000 +vn 0.001700 0.000400 1.000000 +vn 0.000900 0.000100 1.000000 +vn 0.000600 0.000200 1.000000 +vn 0.000200 0.000000 1.000000 +vn 0.000700 -0.000200 1.000000 +vn 0.001900 -0.000200 1.000000 +vn 0.000900 -0.001100 1.000000 +vn 0.001600 -0.001600 1.000000 +vn -0.015600 -0.002000 0.999900 +vn -0.000400 -0.019600 0.999800 +vn 0.032100 -0.002700 0.999500 +vn -0.003700 0.004900 1.000000 +vn -0.002300 0.000500 1.000000 +vn -0.001700 0.000400 1.000000 +vn -0.001500 0.000200 1.000000 +vn -0.001100 -0.000200 1.000000 +vn -0.001000 0.000000 1.000000 +vn -0.000800 0.000300 1.000000 +vn -0.000200 0.002000 1.000000 +vn 0.001500 0.002000 1.000000 +vn 0.001500 0.001900 1.000000 +vn -0.000400 0.001700 1.000000 +vn -0.000100 0.000600 1.000000 +vn -0.000100 0.000500 1.000000 +vn 0.000100 0.000700 1.000000 +vn 0.000200 0.000800 1.000000 +vn -0.000000 0.000900 1.000000 +vn -0.001900 0.001100 1.000000 +vn -0.000700 0.000600 1.000000 +vn -0.000700 0.000300 1.000000 +vn -0.001000 0.000800 1.000000 +vn -0.001600 0.000200 1.000000 +vn -0.001900 0.000800 1.000000 +vn -0.004400 0.001300 1.000000 +vn -0.001500 0.004400 1.000000 +vn -0.000000 -0.002000 1.000000 +vn -0.003500 -0.001200 1.000000 +vn -0.002800 -0.000400 1.000000 +vn -0.002000 -0.000500 1.000000 +vn -0.001500 -0.000100 1.000000 +vn -0.000500 -0.000300 1.000000 +vn -0.001100 -0.000000 1.000000 +vn -0.001300 -0.000200 1.000000 +vn -0.000400 -0.000200 1.000000 +vn -0.000800 -0.000200 1.000000 +vn 0.000500 -0.000300 1.000000 +vn 0.000300 -0.000900 1.000000 +vn -0.000100 -0.000900 1.000000 +vn 0.000100 -0.000600 1.000000 +vn -0.000200 -0.000400 1.000000 +vn -0.000400 0.000000 1.000000 +vn -0.000600 -0.000100 1.000000 +vn -0.000600 0.000100 1.000000 +vn -0.000800 -0.000000 1.000000 +vn -0.000800 0.000200 1.000000 +vn -0.000600 0.000200 1.000000 +vn 0.000700 0.000200 1.000000 +vn 0.000700 0.000300 1.000000 +vn -0.000800 0.000400 1.000000 +vn 0.000200 0.000900 1.000000 +vn 0.000100 0.000900 1.000000 +vn -0.001200 -0.000200 1.000000 +vn -0.003600 0.002100 1.000000 +vn -0.001300 0.001100 1.000000 +vn -0.000900 0.001300 1.000000 +vn -0.003300 0.002200 1.000000 +vn -0.002500 0.002900 1.000000 +vn -0.003500 0.004200 1.000000 +vn -0.007700 0.002400 1.000000 +vn -0.002400 0.003200 1.000000 +vn -0.006900 0.003500 1.000000 +vn -0.007900 0.006300 0.999900 +vn -0.017800 -0.003900 0.999800 +vn -0.005900 0.025600 0.999700 +vn -0.033800 0.003700 0.999400 +vn -0.108600 0.004500 0.994100 +vn -0.019900 0.034600 0.999200 +vn 0.008100 0.007300 0.999900 +vn -0.000900 0.000600 1.000000 +vn 0.003000 -0.000500 1.000000 +vn 0.000700 -0.000600 1.000000 +vn -0.000100 0.000100 1.000000 +vn 0.000000 0.000200 1.000000 +vn -0.000200 0.000400 1.000000 +vn 0.000100 0.000500 1.000000 +vn -0.000900 0.000500 1.000000 +vn -0.001700 -0.000600 1.000000 +vn 0.000700 -0.003100 1.000000 +vn -0.001400 0.000600 1.000000 +vn -0.002200 -0.000500 1.000000 +vn -0.000700 -0.000000 1.000000 +vn 0.000900 -0.000800 1.000000 +vn 0.000900 -0.000900 1.000000 +vn 0.000100 -0.000200 1.000000 +vn 0.000100 0.000100 1.000000 +vn -0.000100 0.000400 1.000000 +vn 0.001900 0.000700 1.000000 +vn 0.000600 0.000900 1.000000 +vn 0.009600 0.000400 1.000000 +vn 0.005000 0.006800 1.000000 +vn 0.014400 0.010100 0.999800 +vn -0.007000 0.013600 0.999900 +vn 0.001600 0.001900 1.000000 +vn 0.001100 0.000400 1.000000 +vn 0.000700 0.000800 1.000000 +vn -0.000400 0.000300 1.000000 +vn -0.000000 0.000500 1.000000 +vn -0.000500 0.000200 1.000000 +vn -0.000400 0.000400 1.000000 +vn 0.002300 0.004000 1.000000 +vn -0.000000 0.000100 1.000000 +vn 0.000000 -0.000300 1.000000 +vn 0.000200 -0.000900 1.000000 +vn 0.000600 -0.001200 1.000000 +vn 0.001100 -0.001100 1.000000 +vn -0.002000 -0.003100 1.000000 +vn -0.000400 -0.000500 1.000000 +vn 0.000500 -0.000900 1.000000 +vn 0.011600 0.002600 0.999900 +vn -0.013300 -0.016000 0.999800 +vn -0.001600 -0.006500 1.000000 +vn -0.010100 0.000500 0.999900 +vn -0.020800 0.028900 0.999400 +vn -0.046800 -0.007700 0.998900 +vn -0.015500 -0.005900 0.999900 +vn -0.016900 -0.003200 0.999900 +vn -0.002500 -0.002900 1.000000 +vn -0.003000 -0.002100 1.000000 +vn 0.055100 0.038600 0.997700 +vn 0.002400 0.000200 1.000000 +vn 0.000400 0.000100 1.000000 +vn 0.000300 0.000200 1.000000 +vn 0.000400 0.000200 1.000000 +vn -0.000900 -0.000300 1.000000 +vn 0.000800 -0.000100 1.000000 +s off +f 1/1/1 2/2/1 3/3/1 +f 4/4/2 5/5/2 6/6/2 +f 7/7/3 4/4/3 6/6/3 +f 7/7/4 6/6/4 8/8/4 +f 9/9/5 7/7/5 8/8/5 +f 8/8/6 10/10/6 9/9/6 +f 11/11/7 9/9/7 10/10/7 +f 11/11/7 10/10/7 12/12/7 +f 12/12/8 13/13/8 14/14/8 +f 15/15/9 16/16/9 17/17/9 +f 18/18/10 15/15/10 19/19/10 +f 20/20/11 21/21/11 22/22/11 +f 23/23/12 24/24/12 25/25/12 +f 23/23/13 25/25/13 26/26/13 +f 27/27/14 26/26/14 28/28/14 +f 28/28/14 26/26/14 29/29/14 +f 30/30/15 31/31/15 32/32/15 +f 33/33/16 34/34/16 35/35/16 +f 35/35/17 34/34/17 36/36/17 +f 37/37/18 38/38/18 39/39/18 +f 40/40/19 41/41/19 42/42/19 +f 41/41/20 40/40/20 43/43/20 +f 41/41/21 43/43/21 44/44/21 +f 45/45/22 44/44/22 46/46/22 +f 44/44/23 47/47/23 46/46/23 +f 48/48/12 49/49/12 50/50/12 +f 48/48/12 50/50/12 51/51/12 +f 51/51/12 50/50/12 52/52/12 +f 53/53/24 54/54/24 55/55/24 +f 56/56/25 57/57/25 58/58/25 +f 56/56/26 58/58/26 59/59/26 +f 60/60/27 61/61/27 62/62/27 +f 60/60/28 62/62/28 63/63/28 +f 64/64/29 60/60/29 63/63/29 +f 64/64/30 63/63/30 65/65/30 +f 66/66/31 64/64/31 65/65/31 +f 66/66/32 65/65/32 67/67/32 +f 68/68/33 67/67/33 69/69/33 +f 68/68/34 69/69/34 70/70/34 +f 71/71/35 72/72/35 73/73/35 +f 73/73/36 72/72/36 74/74/36 +f 71/71/37 73/73/37 75/75/37 +f 76/76/38 77/77/38 78/78/38 +f 76/76/39 78/78/39 79/79/39 +f 78/78/40 80/80/40 81/81/40 +f 78/78/41 81/81/41 79/79/41 +f 80/80/42 82/82/42 83/83/42 +f 83/83/43 82/82/43 84/84/43 +f 85/85/7 83/83/7 84/84/7 +f 86/86/44 87/87/44 88/88/44 +f 87/87/8 37/37/8 88/88/8 +f 86/86/44 88/88/44 89/89/44 +f 86/86/44 89/89/44 90/90/44 +f 86/86/44 90/90/44 91/91/44 +f 92/92/45 90/90/45 93/93/45 +f 92/92/46 93/93/46 94/94/46 +f 92/92/46 94/94/46 95/95/46 +f 93/93/47 90/90/47 96/96/47 +f 96/96/48 89/89/48 97/97/48 +f 97/97/49 82/82/49 57/57/49 +f 57/57/50 82/82/50 98/98/50 +f 99/99/51 100/100/51 101/101/51 +f 59/59/52 99/99/52 101/101/52 +f 102/102/53 62/62/53 59/59/53 +f 102/102/54 59/59/54 101/101/54 +f 103/103/55 102/102/55 101/101/55 +f 103/103/56 104/104/56 102/102/56 +f 104/104/57 105/105/57 75/75/57 +f 69/69/58 104/104/58 75/75/58 +f 104/104/59 106/106/59 105/105/59 +f 63/63/60 102/102/60 104/104/60 +f 63/63/61 62/62/61 102/102/61 +f 58/58/62 98/98/62 99/99/62 +f 58/58/63 99/99/63 59/59/63 +f 107/107/64 96/96/64 108/108/64 +f 109/109/65 110/110/65 107/107/65 +f 109/109/66 107/107/66 111/111/66 +f 108/108/67 111/111/67 107/107/67 +f 112/112/68 113/113/68 110/110/68 +f 114/114/69 110/110/69 113/113/69 +f 114/114/70 113/113/70 115/115/70 +f 115/115/71 116/116/71 114/114/71 +f 94/94/3 107/107/3 110/110/3 +f 94/94/72 110/110/72 114/114/72 +f 117/117/73 95/95/73 94/94/73 +f 117/117/73 94/94/73 114/114/73 +f 118/118/74 119/119/74 120/120/74 +f 121/121/75 122/122/75 112/112/75 +f 123/123/76 124/124/76 118/118/76 +f 118/118/77 120/120/77 115/115/77 +f 118/118/78 115/115/78 113/113/78 +f 123/123/79 118/118/79 113/113/79 +f 123/123/80 113/113/80 112/112/80 +f 123/123/81 112/112/81 122/122/81 +f 121/121/68 112/112/68 110/110/68 +f 121/121/82 110/110/82 109/109/82 +f 107/107/83 93/93/83 96/96/83 +f 94/94/84 93/93/84 107/107/84 +f 90/90/85 89/89/85 96/96/85 +f 88/88/86 37/37/86 85/85/86 +f 125/125/85 85/85/85 37/37/85 +f 125/125/18 37/37/18 39/39/18 +f 126/126/87 127/127/87 83/83/87 +f 126/126/88 128/128/88 129/129/88 +f 126/126/89 129/129/89 127/127/89 +f 130/130/90 131/131/90 128/128/90 +f 130/130/91 128/128/91 126/126/91 +f 130/130/92 35/35/92 131/131/92 +f 35/35/93 132/132/93 131/131/93 +f 133/133/94 134/134/94 132/132/94 +f 134/134/95 133/133/95 135/135/95 +f 136/136/96 137/137/96 138/138/96 +f 136/136/97 138/138/97 135/135/97 +f 136/136/98 135/135/98 133/133/98 +f 137/137/99 139/139/99 54/54/99 +f 139/139/99 137/137/99 140/140/99 +f 140/140/65 141/141/65 142/142/65 +f 142/142/100 141/141/100 143/143/100 +f 144/144/12 143/143/12 145/145/12 +f 143/143/12 146/146/12 147/147/12 +f 143/143/12 147/147/12 145/145/12 +f 145/145/12 147/147/12 50/50/12 +f 145/145/12 50/50/12 49/49/12 +f 146/146/12 148/148/12 147/147/12 +f 149/149/12 150/150/12 148/148/12 +f 149/149/12 148/148/12 146/146/12 +f 143/143/12 149/149/12 146/146/12 +f 141/141/100 151/151/100 149/149/100 +f 141/141/100 149/149/100 143/143/100 +f 140/140/101 152/152/101 151/151/101 +f 140/140/102 151/151/102 141/141/102 +f 137/137/103 153/153/103 152/152/103 +f 137/137/104 152/152/104 140/140/104 +f 154/154/105 155/155/105 153/153/105 +f 154/154/106 153/153/106 137/137/106 +f 136/136/98 133/133/98 156/156/98 +f 136/136/107 156/156/107 155/155/107 +f 136/136/108 155/155/108 154/154/108 +f 133/133/109 157/157/109 156/156/109 +f 133/133/110 158/158/110 157/157/110 +f 158/158/111 159/159/111 157/157/111 +f 160/160/112 20/20/112 159/159/112 +f 160/160/113 159/159/113 158/158/113 +f 161/161/114 20/20/114 160/160/114 +f 162/162/115 163/163/115 161/161/115 +f 164/164/116 163/163/116 162/162/116 +f 165/165/117 163/163/117 164/164/117 +f 26/26/13 25/25/13 165/165/13 +f 26/26/73 165/165/73 164/164/73 +f 162/162/118 161/161/118 30/30/118 +f 30/30/119 161/161/119 160/160/119 +f 30/30/120 160/160/120 132/132/120 +f 132/132/121 160/160/121 158/158/121 +f 18/18/122 166/166/122 157/157/122 +f 18/18/123 157/157/123 159/159/123 +f 18/18/124 159/159/124 167/167/124 +f 17/17/125 166/166/125 19/19/125 +f 168/168/126 169/169/126 170/170/126 +f 168/168/127 170/170/127 45/45/127 +f 41/41/128 45/45/128 171/171/128 +f 41/41/129 171/171/129 42/42/129 +f 42/42/130 171/171/130 172/172/130 +f 173/173/131 174/174/131 171/171/131 +f 173/173/132 17/17/132 175/175/132 +f 17/17/133 176/176/133 175/175/133 +f 176/176/134 13/13/134 175/175/134 +f 17/17/135 173/173/135 177/177/135 +f 178/178/136 179/179/136 180/180/136 +f 6/6/137 1/1/137 179/179/137 +f 10/10/6 6/6/6 179/179/6 +f 10/10/138 179/179/138 178/178/138 +f 173/173/139 175/175/139 178/178/139 +f 173/173/140 178/178/140 180/180/140 +f 177/177/141 173/173/141 170/170/141 +f 180/180/142 174/174/142 173/173/142 +f 172/172/143 171/171/143 174/174/143 +f 172/172/143 174/174/143 3/3/143 +f 170/170/144 173/173/144 171/171/144 +f 170/170/145 171/171/145 45/45/145 +f 169/169/146 177/177/146 170/170/146 +f 166/166/147 177/177/147 169/169/147 +f 17/17/148 177/177/148 166/166/148 +f 133/133/149 132/132/149 158/158/149 +f 157/157/150 166/166/150 169/169/150 +f 157/157/151 169/169/151 156/156/151 +f 156/156/152 169/169/152 168/168/152 +f 156/156/153 168/168/153 155/155/153 +f 46/46/154 181/181/154 153/153/154 +f 46/46/155 153/153/155 155/155/155 +f 46/46/156 155/155/156 168/168/156 +f 53/53/99 137/137/99 54/54/99 +f 129/129/157 137/137/157 53/53/157 +f 136/136/158 154/154/158 137/137/158 +f 125/125/18 130/130/18 85/85/18 +f 130/130/159 39/39/159 33/33/159 +f 130/130/92 33/33/92 35/35/92 +f 131/131/160 132/132/160 134/134/160 +f 131/131/161 134/134/161 135/135/161 +f 131/131/162 135/135/162 128/128/162 +f 128/128/97 135/135/97 138/138/97 +f 128/128/163 138/138/163 129/129/163 +f 129/129/99 138/138/99 137/137/99 +f 127/127/164 129/129/164 53/53/164 +f 127/127/165 53/53/165 182/182/165 +f 183/183/166 127/127/166 182/182/166 +f 183/183/167 182/182/167 184/184/167 +f 183/183/168 184/184/168 81/81/168 +f 183/183/169 81/81/169 127/127/169 +f 80/80/6 83/83/6 127/127/6 +f 85/85/117 130/130/117 126/126/117 +f 85/85/46 126/126/46 83/83/46 +f 125/125/18 39/39/18 130/130/18 +f 89/89/44 88/88/44 85/85/44 +f 89/89/44 85/85/44 84/84/44 +f 89/89/170 84/84/170 97/97/170 +f 97/97/171 84/84/171 82/82/171 +f 80/80/172 127/127/172 81/81/172 +f 82/82/173 80/80/173 98/98/173 +f 98/98/174 80/80/174 99/99/174 +f 79/79/175 81/81/175 184/184/175 +f 78/78/176 77/77/176 100/100/176 +f 78/78/177 100/100/177 99/99/177 +f 78/78/178 99/99/178 80/80/178 +f 185/185/179 100/100/179 77/77/179 +f 186/186/180 101/101/180 100/100/180 +f 186/186/181 100/100/181 185/185/181 +f 186/186/182 187/187/182 103/103/182 +f 186/186/183 103/103/183 101/101/183 +f 106/106/184 103/103/184 187/187/184 +f 106/106/185 104/104/185 103/103/185 +f 75/75/186 73/73/186 69/69/186 +f 67/67/187 63/63/187 104/104/187 +f 67/67/188 104/104/188 69/69/188 +f 66/66/189 67/67/189 68/68/189 +f 65/65/190 63/63/190 67/67/190 +f 62/62/191 56/56/191 59/59/191 +f 58/58/192 57/57/192 98/98/192 +f 57/57/193 188/188/193 97/97/193 +f 188/188/92 108/108/92 96/96/92 +f 188/188/194 96/96/194 97/97/194 +f 53/53/24 55/55/24 189/189/24 +f 190/190/157 54/54/157 139/139/157 +f 190/190/99 139/139/99 140/140/99 +f 190/190/88 140/140/88 142/142/88 +f 191/191/89 142/142/89 143/143/89 +f 191/191/12 143/143/12 192/192/12 +f 192/192/12 143/143/12 144/144/12 +f 49/49/12 144/144/12 145/145/12 +f 147/147/12 193/193/12 50/50/12 +f 147/147/12 148/148/12 194/194/12 +f 150/150/195 149/149/195 151/151/195 +f 150/150/196 151/151/196 195/195/196 +f 196/196/3 195/195/3 151/151/3 +f 196/196/197 151/151/197 152/152/197 +f 197/197/198 196/196/198 152/152/198 +f 197/197/199 152/152/199 153/153/199 +f 181/181/200 197/197/200 153/153/200 +f 46/46/201 47/47/201 181/181/201 +f 46/46/202 168/168/202 45/45/202 +f 41/41/203 44/44/203 45/45/203 +f 42/42/204 172/172/204 198/198/204 +f 198/198/204 172/172/204 199/199/204 +f 35/35/205 31/31/205 132/132/205 +f 31/31/206 30/30/206 132/132/206 +f 164/164/86 162/162/86 30/30/86 +f 26/26/207 164/164/207 29/29/207 +f 23/23/208 26/26/208 27/27/208 +f 200/200/13 201/201/13 25/25/13 +f 201/201/100 202/202/100 25/25/100 +f 202/202/208 165/165/208 25/25/208 +f 203/203/209 21/21/209 163/163/209 +f 203/203/5 163/163/5 165/165/5 +f 21/21/210 20/20/210 161/161/210 +f 21/21/211 161/161/211 163/163/211 +f 204/204/212 167/167/212 159/159/212 +f 204/204/213 159/159/213 20/20/213 +f 19/19/214 15/15/214 17/17/214 +f 18/18/215 19/19/215 166/166/215 +f 16/16/216 176/176/216 17/17/216 +f 16/16/134 13/13/134 176/176/134 +f 12/12/217 175/175/217 13/13/217 +f 12/12/218 10/10/218 175/175/218 +f 10/10/138 178/178/138 175/175/138 +f 8/8/6 6/6/6 10/10/6 +f 5/5/2 1/1/2 6/6/2 +f 1/1/219 3/3/219 180/180/219 +f 1/1/220 180/180/220 179/179/220 +f 3/3/221 199/199/221 172/172/221 +f 3/3/222 174/174/222 180/180/222 +f 22/22/223 204/204/223 20/20/223 +f 205/205/224 203/203/224 165/165/224 +f 205/205/224 165/165/224 202/202/224 +f 24/24/12 200/200/12 25/25/12 +f 206/206/225 29/29/225 164/164/225 +f 206/206/92 164/164/92 30/30/92 +f 206/206/226 30/30/226 32/32/226 +f 36/36/227 32/32/227 31/31/227 +f 36/36/228 31/31/228 35/35/228 +f 47/47/229 197/197/229 181/181/229 +f 207/207/12 194/194/12 148/148/12 +f 208/208/12 147/147/12 194/194/12 +f 207/207/12 208/208/12 194/194/12 +f 208/208/12 193/193/12 147/147/12 +f 193/193/12 52/52/12 50/50/12 +f 48/48/12 144/144/12 49/49/12 +f 54/54/230 190/190/230 55/55/230 +f 188/188/231 111/111/231 108/108/231 +f 62/62/232 61/61/232 56/56/232 +f 70/70/233 69/69/233 73/73/233 +f 74/74/234 70/70/234 73/73/234 +f 105/105/235 71/71/235 75/75/235 +f 209/209/236 118/118/236 124/124/236 +f 210/210/237 209/209/237 124/124/237 +f 210/210/238 124/124/238 211/211/238 +f 211/211/239 124/124/239 123/123/239 +f 212/212/240 211/211/240 123/123/240 +f 212/212/241 123/123/241 122/122/241 +f 209/209/242 119/119/242 118/118/242 +f 116/116/243 115/115/243 120/120/243 +f 213/213/244 90/90/244 92/92/244 +f 213/213/245 92/92/245 95/95/245 +f 213/213/246 91/91/246 90/90/246 +f 182/182/103 214/214/103 184/184/103 +f 214/214/103 182/182/103 189/189/103 +f 189/189/103 182/182/103 53/53/103 +f 191/191/14 190/190/14 142/142/14 +f 42/42/247 198/198/247 40/40/247 +f 91/91/44 87/87/44 86/86/44 +f 87/87/18 38/38/18 37/37/18 +f 39/39/248 34/34/248 33/33/248 +f 14/14/116 11/11/116 12/12/116 +f 199/199/221 3/3/221 2/2/221 diff --git a/L15/resources/simple_frag.glsl b/L15/resources/simple_frag.glsl new file mode 100644 index 0000000..b5c0707 --- /dev/null +++ b/L15/resources/simple_frag.glsl @@ -0,0 +1,8 @@ +#version 120 + +varying vec3 color; + +void main() +{ + gl_FragColor = vec4(color, 1.0); +} diff --git a/L15/resources/simple_vert.glsl b/L15/resources/simple_vert.glsl new file mode 100644 index 0000000..9558ec3 --- /dev/null +++ b/L15/resources/simple_vert.glsl @@ -0,0 +1,11 @@ +#version 120 + +uniform mat4 P; +uniform mat4 MV; +varying vec3 color; + +void main() +{ + gl_Position = P * MV * gl_Vertex; + color = gl_Color.rgb; +} diff --git a/L15/resources/tex_frag.glsl b/L15/resources/tex_frag.glsl new file mode 100644 index 0000000..efb2b4b --- /dev/null +++ b/L15/resources/tex_frag.glsl @@ -0,0 +1,10 @@ +#version 120 + +uniform sampler2D colorTexture; +varying vec2 fragTexCoords; + +void main() +{ + vec4 c = texture2D(colorTexture, fragTexCoords); + gl_FragColor = vec4(c.rgb, 1.0); +} diff --git a/L15/resources/tex_vert.glsl b/L15/resources/tex_vert.glsl new file mode 100644 index 0000000..8e7bc72 --- /dev/null +++ b/L15/resources/tex_vert.glsl @@ -0,0 +1,13 @@ +#version 120 + +attribute vec4 vertPos; +attribute vec2 vertTex; +uniform mat4 P; +uniform mat4 MV; +varying vec2 fragTexCoords; + +void main() +{ + gl_Position = P * MV * vertPos; + fragTexCoords = vertTex; +} diff --git a/L15/resources/wood_tex.jpg b/L15/resources/wood_tex.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4bd4c8eae9b68dccc48f6e5f9b51e5039d3ca05e GIT binary patch literal 13994 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 D*r6#i literal 0 HcmV?d00001 diff --git a/L15/src/GLSL.cpp b/L15/src/GLSL.cpp new file mode 100644 index 0000000..2969872 --- /dev/null +++ b/L15/src/GLSL.cpp @@ -0,0 +1,152 @@ +// +// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book +// Created by zwood on 2/21/10. +// Modified by sueda 10/15/15. +// + +#include "GLSL.h" +#include +#include +#include +#include + +using namespace std; + +namespace GLSL { + +const char * errorString(GLenum err) +{ + switch(err) { + case GL_NO_ERROR: + return "No error"; + case GL_INVALID_ENUM: + return "Invalid enum"; + case GL_INVALID_VALUE: + return "Invalid value"; + case GL_INVALID_OPERATION: + return "Invalid operation"; + case GL_STACK_OVERFLOW: + return "Stack overflow"; + case GL_STACK_UNDERFLOW: + return "Stack underflow"; + case GL_OUT_OF_MEMORY: + return "Out of memory"; + default: + return "No error"; + } +} + +void checkVersion() +{ + int major, minor; + major = minor = 0; + const char *verstr = (const char *)glGetString(GL_VERSION); + + if((verstr == NULL) || (sscanf(verstr, "%d.%d", &major, &minor) != 2)) { + printf("Invalid GL_VERSION format %d.%d\n", major, minor); + } + if(major < 2) { + printf("This shader example will not work due to the installed Opengl version, which is %d.%d.\n", major, minor); + exit(0); + } +} + +void checkError(const char *str) +{ + GLenum glErr = glGetError(); + if(glErr != GL_NO_ERROR) { + if(str) { + printf("%s: ", str); + } + printf("GL_ERROR = %s.\n", errorString(glErr)); + assert(false); + } +} + +void printShaderInfoLog(GLuint shader) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + GLchar *infoLog = 0; + + checkError(GET_FILE_LINE); + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength); + checkError(GET_FILE_LINE); + + if(infologLength > 0) { + infoLog = (GLchar *)malloc(infologLength); + if(infoLog == NULL) { + puts("ERROR: Could not allocate InfoLog buffer"); + exit(1); + } + glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog); + checkError(GET_FILE_LINE); + printf("Shader InfoLog:\n%s\n\n", infoLog); + free(infoLog); + } +} + +void printProgramInfoLog(GLuint program) +{ + GLint infologLength = 0; + GLint charsWritten = 0; + GLchar *infoLog = 0; + + checkError(GET_FILE_LINE); + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infologLength); + checkError(GET_FILE_LINE); + + if(infologLength > 0) { + infoLog = (GLchar *)malloc(infologLength); + if(infoLog == NULL) { + puts("ERROR: Could not allocate InfoLog buffer"); + exit(1); + } + glGetProgramInfoLog(program, infologLength, &charsWritten, infoLog); + checkError(GET_FILE_LINE); + printf("Program InfoLog:\n%s\n\n", infoLog); + free(infoLog); + } +} + +char *textFileRead(const char *fn) +{ + FILE *fp; + char *content = NULL; + int count = 0; + if(fn != NULL) { + fp = fopen(fn,"rt"); + if(fp != NULL) { + fseek(fp, 0, SEEK_END); + count = (int)ftell(fp); + rewind(fp); + if(count > 0) { + content = (char *)malloc(sizeof(char) * (count+1)); + count = (int)fread(content,sizeof(char),count,fp); + content[count] = '\0'; + } + fclose(fp); + } else { + printf("error loading %s\n", fn); + } + } + return content; +} + +int textFileWrite(const char *fn, const char *s) +{ + FILE *fp; + int status = 0; + if(fn != NULL) { + fp = fopen(fn,"w"); + if(fp != NULL) { + if(fwrite(s,sizeof(char),strlen(s),fp) == strlen(s)) { + status = 1; + } + fclose(fp); + } + } + return(status); +} + +} diff --git a/L15/src/GLSL.h b/L15/src/GLSL.h new file mode 100644 index 0000000..f945fdd --- /dev/null +++ b/L15/src/GLSL.h @@ -0,0 +1,40 @@ +// +// Many useful helper functions for GLSL shaders - gleaned from various sources including orange book +// Created by zwood on 2/21/10. +// Modified by sueda 10/15/15. +// + +#pragma once +#ifndef __GLSL__ +#define __GLSL__ + +#define GLEW_STATIC +#include + +/////////////////////////////////////////////////////////////////////////////// +// For printing out the current file and line number // +/////////////////////////////////////////////////////////////////////////////// +#include + +template +std::string NumberToString(T x) +{ + std::ostringstream ss; + ss << x; + return ss.str(); +} + +#define GET_FILE_LINE (std::string(__FILE__) + ":" + NumberToString(__LINE__)).c_str() +/////////////////////////////////////////////////////////////////////////////// + +namespace GLSL { + + void checkVersion(); + void checkError(const char *str = 0); + void printProgramInfoLog(GLuint program); + void printShaderInfoLog(GLuint shader); + int textFileWrite(const char *filename, const char *s); + char *textFileRead(const char *filename); +} + +#endif diff --git a/L15/src/Grid.cpp b/L15/src/Grid.cpp new file mode 100644 index 0000000..76d22bf --- /dev/null +++ b/L15/src/Grid.cpp @@ -0,0 +1,185 @@ +#define GLEW_STATIC +#include + +#include +#include +#include +#include + +#define GLM_FORCE_RADIANS +#include + +#include "Grid.h" + +using namespace std; + +Grid::Grid() : + nrows(2), + ncols(2), + closest(-1) +{ + +} + +Grid::~Grid() +{ + +} + +void Grid::setSize(int nrows, int ncols) +{ + this->nrows = nrows; + this->ncols = ncols; + + cps.resize(nrows*ncols); + reset(); +} + +void Grid::reset() +{ + // -1 to +1 in both x and y + for(int col = 0; col < ncols; ++col) { + float x = -1.0f + col/(ncols-1.0f)*2.0f; + for(int row = 0; row < nrows; ++row) { + float y = -1.0f + row/(nrows-1.0f)*2.0f; + glm::vec2 &cp = cps[indexAt(row, col)]; + cp.x = x; + cp.y = y; + } + } +} + +int Grid::indexAt(int row, int col) const +{ + return row*ncols + col; +} + +void Grid::moveCP(const glm::vec2 &p) +{ + if(closest != -1) { + cps[closest] = p; + } +} + +void Grid::findClosest(const glm::vec2 &p) +{ + closest = -1; + float dmin = 0.1f; + for(int col = 0; col < ncols; ++col) { + for(int row = 0; row < nrows; ++row) { + const glm::vec2 &cp = cps[indexAt(row, col)]; + float d = glm::length(p - cp); + if(d < dmin) { + closest = indexAt(row, col); + dmin = d; + } + } + } +} + +void Grid::draw() const +{ + // Draw closest control point + glPointSize(6.0f); + glColor3f(0.5f, 0.5f, 0.5f); + if(closest != -1) { + glBegin(GL_POINTS); + const glm::vec2 &cp = cps[closest]; + glVertex3f(cp.x, cp.y, 0.01f); // offset slightly above the shape + glEnd(); + } + // Draw grid + glLineWidth(1.0f); + for(int col = 0; col < ncols; ++col) { + glBegin(GL_LINE_STRIP); + for(int row = 0; row < nrows; ++row) { + const glm::vec2 &cp = cps[indexAt(row, col)]; + glVertex3f(cp.x, cp.y, 0.01f); // offset slightly above the shape + } + glEnd(); + } + for(int row = 0; row < nrows; ++row) { + glBegin(GL_LINE_STRIP); + for(int col = 0; col < ncols; ++col) { + const glm::vec2 &cp = cps[indexAt(row, col)]; + glVertex3f(cp.x, cp.y, 0.01f); // offset slightly above the shape + } + glEnd(); + } +} + +vector Grid::getTileCPs(int index) const +{ + // Return the 4 cps corresponding to the index + // 2---3 + // | | + // 0---1 + assert(index >= 0); + assert(index + ncols + 1 < cps.size()); + vector cps_; + cps_.push_back(cps[index]); + cps_.push_back(cps[index + 1]); + cps_.push_back(cps[index + ncols]); + cps_.push_back(cps[index + ncols + 1]); + return cps_; +} + +const vector & Grid::getAllCPs() const +{ + return cps; +} + +void Grid::save(const char *filename) const +{ + ofstream out(filename); + if(!out.good()) { + cout << "Could not open " << filename << endl; + return; + } + out << nrows << endl; + out << ncols << endl; + for(int k = 0; k < (int)cps.size(); ++k) { + const glm::vec2 &cp = cps[k]; + out << cp.x << " " << cp.y << endl; + } + out << "##################################" << endl; + out.close(); +} + +void Grid::load(const char *filename) +{ + ifstream in; + in.open(filename); + if(!in.good()) { + std::cout << "Cannot read " << filename << endl; + return; + } + in >> nrows; + in >> ncols; + cps.resize(nrows*ncols); + cps.clear(); + string line; + // Discard rest of the first line. + getline(in, line); + while(1) { + getline(in, line); + if(in.eof()) { + break; + } + // Skip empty lines + if(line.size() < 2) { + continue; + } + // Skip comments + if(line.at(0) == '#') { + continue; + } + // Parse line + stringstream ss(line); + glm::vec2 cp; + ss >> cp.x; + ss >> cp.y; + cps.push_back(cp); + } + in.close(); +} diff --git a/L15/src/Grid.h b/L15/src/Grid.h new file mode 100644 index 0000000..e172731 --- /dev/null +++ b/L15/src/Grid.h @@ -0,0 +1,36 @@ +#pragma once +#ifndef __Grid__ +#define __Grid__ + +#include +#include + + +class Grid +{ +public: + Grid(); + virtual ~Grid(); + void setSize(int nrows, int ncols); + void reset(); + void moveCP(const glm::vec2 &p); + void findClosest(const glm::vec2 &p); + void draw() const; + + int indexAt(int row, int col) const; + int getRows() const { return nrows; }; + int getCols() const { return ncols; }; + std::vector getTileCPs(int index) const; + const std::vector & getAllCPs() const; + void save(const char *filename) const; + void load(const char *filename); + +private: + + std::vector cps; + int nrows; + int ncols; + int closest; +}; + +#endif diff --git a/L15/src/MatrixStack.cpp b/L15/src/MatrixStack.cpp new file mode 100644 index 0000000..eaa6e6c --- /dev/null +++ b/L15/src/MatrixStack.cpp @@ -0,0 +1,114 @@ +#include "MatrixStack.h" + +#include +#include +#include + +#define GLM_FORCE_RADIANS +#include +#include + +using namespace std; + +MatrixStack::MatrixStack() +{ + mstack = make_shared< stack >(); + mstack->push(glm::mat4(1.0)); +} + +MatrixStack::~MatrixStack() +{ +} + +void MatrixStack::pushMatrix() +{ + const glm::mat4 &top = mstack->top(); + mstack->push(top); + assert(mstack->size() < 100); +} + +void MatrixStack::popMatrix() +{ + assert(!mstack->empty()); + mstack->pop(); + // There should always be one matrix left. + assert(!mstack->empty()); +} + +void MatrixStack::loadIdentity() +{ + glm::mat4 &top = mstack->top(); + top = glm::mat4(1.0); +} + +void MatrixStack::translate(const glm::vec3 &t) +{ + glm::mat4 &top = mstack->top(); + top *= glm::translate(t); +} + +void MatrixStack::translate(float x, float y, float z) +{ + translate(glm::vec3(x, y, z)); +} + +void MatrixStack::scale(const glm::vec3 &s) +{ + glm::mat4 &top = mstack->top(); + top *= glm::scale(s); +} + +void MatrixStack::scale(float x, float y, float z) +{ + scale(glm::vec3(x, y, z)); +} + +void MatrixStack::scale(float s) +{ + scale(glm::vec3(s, s, s)); +} + +void MatrixStack::rotate(float angle, const glm::vec3 &axis) +{ + glm::mat4 &top = mstack->top(); + top *= glm::rotate(angle, axis); +} + +void MatrixStack::rotate(float angle, float x, float y, float z) +{ + rotate(angle, glm::vec3(x, y, z)); +} + +void MatrixStack::multMatrix(const glm::mat4 &matrix) +{ + glm::mat4 &top = mstack->top(); + top *= matrix; +} + +const glm::mat4 &MatrixStack::topMatrix() const +{ + return mstack->top(); +} + +void MatrixStack::print(const glm::mat4 &mat, const char *name) +{ + if(name) { + printf("%s = [\n", name); + } + for(int i = 0; i < 4; ++i) { + for(int j = 0; j < 4; ++j) { + // mat[j] returns the jth column + printf("%- 5.2f ", mat[j][i]); + } + printf("\n"); + } + if(name) { + printf("];"); + } + printf("\n"); +} + +void MatrixStack::print(const char *name) const +{ + print(mstack->top(), name); +} diff --git a/L15/src/MatrixStack.h b/L15/src/MatrixStack.h new file mode 100644 index 0000000..66278ce --- /dev/null +++ b/L15/src/MatrixStack.h @@ -0,0 +1,50 @@ +#pragma once +#ifndef _MatrixStack_H_ +#define _MatrixStack_H_ + +#include +#include +#include + +class MatrixStack +{ +public: + MatrixStack(); + virtual ~MatrixStack(); + + // glPushMatrix(): Copies the current matrix and adds it to the top of the stack + void pushMatrix(); + // glPopMatrix(): Removes the top of the stack and sets the current matrix to be the matrix that is now on top + void popMatrix(); + + // glLoadIdentity(): Sets the top matrix to be the identity + void loadIdentity(); + // glMultMatrix(): Right multiplies the top matrix + void multMatrix(const glm::mat4 &matrix); + + // glTranslate(): Right multiplies the top matrix by a translation matrix + void translate(const glm::vec3 &trans); + void translate(float x, float y, float z); + // glScale(): Right multiplies the top matrix by a scaling matrix + void scale(const glm::vec3 &scale); + void scale(float x, float y, float z); + // glScale(): Right multiplies the top matrix by a scaling matrix + void scale(float size); + // glRotate(): Right multiplies the top matrix by a rotation matrix (angle in radians) + void rotate(float angle, const glm::vec3 &axis); + void rotate(float angle, float x, float y, float z); + + // glGet(GL_MODELVIEW_MATRIX): Gets the top matrix + const glm::mat4 &topMatrix() const; + + // Prints out the specified matrix + static void print(const glm::mat4 &mat, const char *name = 0); + // Prints out the top matrix + void print(const char *name = 0) const; + +private: + std::shared_ptr< std::stack > mstack; + +}; + +#endif diff --git a/L15/src/Program.cpp b/L15/src/Program.cpp new file mode 100644 index 0000000..1e85538 --- /dev/null +++ b/L15/src/Program.cpp @@ -0,0 +1,126 @@ +#include "Program.h" + +#include +#include + +#include "GLSL.h" + +using namespace std; + +Program::Program() : + vShaderName(""), + fShaderName(""), + pid(0), + verbose(true) +{ + +} + +Program::~Program() +{ + +} + +void Program::setShaderNames(const string &v, const string &f) +{ + vShaderName = v; + fShaderName = f; +} + +bool Program::init() +{ + GLint rc; + + // Create shader handles + GLuint VS = glCreateShader(GL_VERTEX_SHADER); + GLuint FS = glCreateShader(GL_FRAGMENT_SHADER); + + // Read shader sources + const char *vshader = GLSL::textFileRead(vShaderName.c_str()); + const char *fshader = GLSL::textFileRead(fShaderName.c_str()); + glShaderSource(VS, 1, &vshader, NULL); + glShaderSource(FS, 1, &fshader, NULL); + + // Compile vertex shader + glCompileShader(VS); + glGetShaderiv(VS, GL_COMPILE_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printShaderInfoLog(VS); + cout << "Error compiling vertex shader " << vShaderName << endl; + } + return false; + } + + // Compile fragment shader + glCompileShader(FS); + glGetShaderiv(FS, GL_COMPILE_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printShaderInfoLog(FS); + cout << "Error compiling fragment shader " << fShaderName << endl; + } + return false; + } + + // Create the program and link + pid = glCreateProgram(); + glAttachShader(pid, VS); + glAttachShader(pid, FS); + glLinkProgram(pid); + glGetProgramiv(pid, GL_LINK_STATUS, &rc); + if(!rc) { + if(isVerbose()) { + GLSL::printProgramInfoLog(pid); + cout << "Error linking shaders " << vShaderName << " and " << fShaderName << endl; + } + return false; + } + + GLSL::checkError(GET_FILE_LINE); + return true; +} + +void Program::bind() +{ + glUseProgram(pid); +} + +void Program::unbind() +{ + glUseProgram(0); +} + +void Program::addAttribute(const string &name) +{ + attributes[name] = glGetAttribLocation(pid, name.c_str()); +} + +void Program::addUniform(const string &name) +{ + uniforms[name] = glGetUniformLocation(pid, name.c_str()); +} + +GLint Program::getAttribute(const string &name) const +{ + map::const_iterator attribute = attributes.find(name.c_str()); + if(attribute == attributes.end()) { + if(isVerbose()) { + cout << name << " is not an attribute variable" << endl; + } + return -1; + } + return attribute->second; +} + +GLint Program::getUniform(const string &name) const +{ + map::const_iterator uniform = uniforms.find(name.c_str()); + if(uniform == uniforms.end()) { + if(isVerbose()) { + cout << name << " is not a uniform variable" << endl; + } + return -1; + } + return uniform->second; +} diff --git a/L15/src/Program.h b/L15/src/Program.h new file mode 100644 index 0000000..51e58bb --- /dev/null +++ b/L15/src/Program.h @@ -0,0 +1,44 @@ +#pragma once +#ifndef __Program__ +#define __Program__ + +#include +#include + +#define GLEW_STATIC +#include + +/** + * An OpenGL Program (vertex and fragment shaders) + */ +class Program +{ +public: + Program(); + virtual ~Program(); + + void setVerbose(bool v) { verbose = v; } + bool isVerbose() const { return verbose; } + + void setShaderNames(const std::string &v, const std::string &f); + virtual bool init(); + virtual void bind(); + virtual void unbind(); + + void addAttribute(const std::string &name); + void addUniform(const std::string &name); + GLint getAttribute(const std::string &name) const; + GLint getUniform(const std::string &name) const; + +protected: + std::string vShaderName; + std::string fShaderName; + +private: + GLuint pid; + std::map attributes; + std::map uniforms; + bool verbose; +}; + +#endif diff --git a/L15/src/ShapeCage.cpp b/L15/src/ShapeCage.cpp new file mode 100644 index 0000000..eb4ff74 --- /dev/null +++ b/L15/src/ShapeCage.cpp @@ -0,0 +1,151 @@ +#include + +#define GLM_FORCE_RADIANS +#include + +#define TINYOBJLOADER_IMPLEMENTATION +#include "tiny_obj_loader.h" + +#include "ShapeCage.h" +#include "GLSL.h" +#include "Grid.h" + +using namespace std; + +ShapeCage::ShapeCage() : + posBufID(0), + texBufID(0), + elemBufID(0) +{ +} + +ShapeCage::~ShapeCage() +{ +} + +void ShapeCage::load(const string &meshName) +{ + // Load geometry + tinyobj::attrib_t attrib; + std::vector shapes; + std::vector materials; + string errStr; + bool rc = tinyobj::LoadObj(&attrib, &shapes, &materials, &errStr, meshName.c_str()); + if(!rc) { + cerr << errStr << endl; + } else { + posBuf = attrib.vertices; + norBuf = attrib.normals; + texBuf = attrib.texcoords; + //assert(posBuf.size() == norBuf.size()); + // Loop over shapes + for(size_t s = 0; s < shapes.size(); s++) { + // Loop over faces (polygons) + const tinyobj::mesh_t &mesh = shapes[s].mesh; + size_t index_offset = 0; + for(size_t f = 0; f < mesh.num_face_vertices.size(); f++) { + size_t fv = mesh.num_face_vertices[f]; + // Loop over vertices in the face. + for(size_t v = 0; v < fv; v++) { + // access to vertex + tinyobj::index_t idx = mesh.indices[index_offset + v]; + elemBuf.push_back(idx.vertex_index); + } + index_offset += fv; + // per-face material (IGNORE) + shapes[s].mesh.material_ids[f]; + } + } + } +} + +void ShapeCage::toLocal() +{ + // Find which tile each vertex belongs to. + // Store (row, col) into tileBuf. + int nVerts = (int)posBuf.size()/3; + posLocalBuf.resize(nVerts*2); + tileIndexBuf.resize(nVerts); + int nrows = grid->getRows(); + int ncols = grid->getCols(); + // Go through all vertices + for(int k = 0; k < nVerts; ++k) { + float x = posBuf[3*k]; + float y = posBuf[3*k+1]; + // + // IMPLEMENT ME + // Fill in posLocalBuf and tileIndexBuf. + // + posLocalBuf[2*k+0] = x; + posLocalBuf[2*k+1] = y; + tileIndexBuf[k] = 0; + } +} + +void ShapeCage::toWorld() +{ + int nVerts = (int)posBuf.size()/3; + for(int k = 0; k < nVerts; ++k) { + float u = posLocalBuf[2*k]; + float v = posLocalBuf[2*k+1]; + // + // IMPLEMENT ME + // Fill in posBuf from the info stored in posLocalBuf and tileIndexBuf. + // + posBuf[3*k+0] = u; + posBuf[3*k+1] = v; + } + // Send the updated world position array to the GPU + glGenBuffers(1, &posBufID); + glBindBuffer(GL_ARRAY_BUFFER, posBufID); + glBufferData(GL_ARRAY_BUFFER, posBuf.size()*sizeof(float), &posBuf[0], GL_DYNAMIC_DRAW); +} + +void ShapeCage::init() +{ + // Send the texture coordinates array (if it exists) to the GPU + if(!texBuf.empty()) { + glGenBuffers(1, &texBufID); + glBindBuffer(GL_ARRAY_BUFFER, texBufID); + glBufferData(GL_ARRAY_BUFFER, texBuf.size()*sizeof(float), &texBuf[0], GL_STATIC_DRAW); + } else { + texBufID = 0; + } + + // Send the index array to the GPU + glGenBuffers(1, &elemBufID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elemBufID); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, elemBuf.size()*sizeof(unsigned int), &elemBuf[0], GL_STATIC_DRAW); + + // Unbind the arrays + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + assert(glGetError() == GL_NO_ERROR); +} + +void ShapeCage::draw(int h_pos, int h_tex) const +{ + // Enable and bind position array for drawing + glEnableVertexAttribArray(h_pos); + glBindBuffer(GL_ARRAY_BUFFER, posBufID); + glVertexAttribPointer(h_pos, 3, GL_FLOAT, GL_FALSE, 0, 0); + + // Enable and bind texcoord array for drawing + glEnableVertexAttribArray(h_tex); + glBindBuffer(GL_ARRAY_BUFFER, texBufID); + glVertexAttribPointer(h_tex, 2, GL_FLOAT, GL_FALSE, 0, 0); + + // Bind element array for drawing + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elemBufID); + + // Draw + int nElements = (int)elemBuf.size(); + glDrawElements(GL_TRIANGLES, nElements, GL_UNSIGNED_INT, 0); + + // Disable and unbind + glDisableVertexAttribArray(h_tex); + glDisableVertexAttribArray(h_pos); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} diff --git a/L15/src/ShapeCage.h b/L15/src/ShapeCage.h new file mode 100644 index 0000000..71cdebb --- /dev/null +++ b/L15/src/ShapeCage.h @@ -0,0 +1,35 @@ +#pragma once +#ifndef _SHAPECAGE_H_ +#define _SHAPECAGE_H_ + +#include +#include + +class Grid; + +class ShapeCage +{ +public: + ShapeCage(); + virtual ~ShapeCage(); + void load(const std::string &meshName); + void setGrid(std::shared_ptr g) { grid = g; } + void toLocal(); + void toWorld(); + void init(); + void draw(int h_pos, int h_tex) const; + +private: + std::vector elemBuf; + std::vector posBuf; + std::vector norBuf; + std::vector texBuf; + std::vector posLocalBuf; + std::vector tileIndexBuf; + unsigned posBufID; + unsigned texBufID; + unsigned elemBufID; + std::shared_ptr grid; +}; + +#endif diff --git a/L15/src/Texture.cpp b/L15/src/Texture.cpp new file mode 100644 index 0000000..1537763 --- /dev/null +++ b/L15/src/Texture.cpp @@ -0,0 +1,80 @@ +#include "Texture.h" +#include +#include +#include +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + +using namespace std; + +Texture::Texture() : + filename(""), + tid(0) +{ + +} + +Texture::~Texture() +{ + +} + +void Texture::init() +{ + // Load texture + int w, h, ncomps; + stbi_set_flip_vertically_on_load(true); + unsigned char *data = stbi_load(filename.c_str(), &w, &h, &ncomps, 0); + if(!data) { + cerr << filename << " not found" << endl; + } + if(ncomps != 3) { + cerr << filename << " must have 3 components (RGB)" << endl; + } + if((w & (w - 1)) != 0 || (h & (h - 1)) != 0) { + cerr << filename << " must be a power of 2" << endl; + } + width = w; + height = h; + + // Generate a texture buffer object + glGenTextures(1, &tid); + // Bind the current texture to be the newly generated texture object + glBindTexture(GL_TEXTURE_2D, tid); + // Load the actual texture data + // Base level is 0, number of channels is 3, and border is 0. + glTexImage2D(GL_TEXTURE_2D, 0, ncomps, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + // Generate image pyramid + glGenerateMipmap(GL_TEXTURE_2D); + // Set texture wrap modes for the S and T directions + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // Set filtering mode for magnification and minimification + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + // Unbind + glBindTexture(GL_TEXTURE_2D, 0); + // Free image, since the data is now on the GPU + stbi_image_free(data); +} + +void Texture::setWrapModes(GLint wrapS, GLint wrapT) +{ + // Must be called after init() + glBindTexture(GL_TEXTURE_2D, tid); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); +} + +void Texture::bind(GLint handle) +{ + glActiveTexture(GL_TEXTURE0 + unit); + glBindTexture(GL_TEXTURE_2D, tid); + glUniform1i(handle, unit); +} + +void Texture::unbind() +{ + glActiveTexture(GL_TEXTURE0 + unit); + glBindTexture(GL_TEXTURE_2D, 0); +} diff --git a/L15/src/Texture.h b/L15/src/Texture.h new file mode 100644 index 0000000..9209149 --- /dev/null +++ b/L15/src/Texture.h @@ -0,0 +1,32 @@ +#pragma once +#ifndef __Texture__ +#define __Texture__ + +#define GLEW_STATIC +#include + +#include + +class Texture +{ +public: + Texture(); + virtual ~Texture(); + void setFilename(const std::string &f) { filename = f; } + void init(); + void setUnit(GLint u) { unit = u; } + GLint getUnit() const { return unit; } + void bind(GLint handle); + void unbind(); + void setWrapModes(GLint wrapS, GLint wrapT); // Must be called after init() + +private: + std::string filename; + int width; + int height; + GLuint tid; + GLint unit; + +}; + +#endif diff --git a/L15/src/main.cpp b/L15/src/main.cpp new file mode 100644 index 0000000..219c57d --- /dev/null +++ b/L15/src/main.cpp @@ -0,0 +1,260 @@ +#include +#include + +#define GLEW_STATIC +#include +#include + +#define GLM_FORCE_RADIANS +#include +#include +#include + +#include "GLSL.h" +#include "Program.h" +#include "MatrixStack.h" +#include "ShapeCage.h" +#include "Texture.h" +#include "Grid.h" + +using namespace std; + +GLFWwindow *window; // Main application window +string RESOURCE_DIR = ""; // Where the resources are loaded from +shared_ptr progSimple; +shared_ptr progTex; +shared_ptr grid; +shared_ptr shape; +shared_ptr texture; + +bool keyToggles[256] = {false}; // only for English keyboards! + +glm::vec2 window2world(double xmouse, double ymouse) +{ + // Convert from window coords to world coords + // (Assumes orthographic projection) + int width, height; + glfwGetWindowSize(window, &width, &height); + glm::vec4 p; + // Inverse of viewing transform + p.x = xmouse / (float)width; + p.y = (height - ymouse) / (float)height; + p.x = 2.0f * (p.x - 0.5f); + p.y = 2.0f * (p.y - 0.5f); + p.z = 0.0f; + p.w = 1.0f; + // Inverse of model-view-projection transform + auto P = make_shared(); + auto MV = make_shared(); + double aspect = (double)width/height; + double s = 1.1; + P->multMatrix(glm::ortho(-s*aspect, s*aspect, -s, s)); + p = glm::inverse(P->topMatrix() * MV->topMatrix()) * p; + return glm::vec2(p); +} + +static void error_callback(int error, const char *description) +{ + cerr << description << endl; +} + +static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) +{ + if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, GL_TRUE); + } +} + +static void char_callback(GLFWwindow *window, unsigned int key) +{ + keyToggles[key] = !keyToggles[key]; + + switch(key) { + case 'r': + grid->reset(); + break; + case 's': + grid->save("cps.txt"); + break; + case 'l': + grid->load("cps.txt"); + break; + } +} + +static void cursor_position_callback(GLFWwindow* window, double xmouse, double ymouse) +{ + int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT); + if(state == GLFW_PRESS) { + grid->moveCP(window2world(xmouse, ymouse)); + } else { + grid->findClosest(window2world(xmouse, ymouse)); + } +} + +void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) +{ + // Not used for this lab +} + +static void init() +{ + GLSL::checkVersion(); + + // Set background color + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + // Enable z-buffer test + glEnable(GL_DEPTH_TEST); + + // Initialize the GLSL program. + progSimple = make_shared(); + progSimple->setVerbose(true); // Set this to true when debugging. + progSimple->setShaderNames(RESOURCE_DIR + "simple_vert.glsl", RESOURCE_DIR + "simple_frag.glsl"); + progSimple->init(); + progSimple->addUniform("P"); + progSimple->addUniform("MV"); + progSimple->setVerbose(false); + + progTex = make_shared(); + progTex->setVerbose(true); // Set this to true when debugging. + progTex->setShaderNames(RESOURCE_DIR + "tex_vert.glsl", RESOURCE_DIR + "tex_frag.glsl"); + progTex->init(); + progTex->addAttribute("vertPos"); + progTex->addAttribute("vertTex"); + progTex->addUniform("P"); + progTex->addUniform("MV"); + progTex->addUniform("colorTexture"); + progTex->setVerbose(false); + + texture = make_shared(); + texture->setFilename(RESOURCE_DIR + "wood_tex.jpg"); + texture->init(); + texture->setUnit(0); + + // Grid of control points + grid = make_shared(); + grid->setSize(5, 5); + + // Load scene + shape = make_shared(); + shape->load(RESOURCE_DIR + "man.obj"); + shape->setGrid(grid); + shape->toLocal(); + shape->init(); + + // If there were any OpenGL errors, this will print something. + // You can intersperse this line in your code to find the exact location + // of your OpenGL error. + GLSL::checkError(GET_FILE_LINE); +} + +void render() +{ + // Get current frame buffer size. + int width, height; + glfwGetFramebufferSize(window, &width, &height); + glViewport(0, 0, width, height); + + // Clear buffers + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if(keyToggles[(unsigned)'c']) { + glEnable(GL_CULL_FACE); + } else { + glDisable(GL_CULL_FACE); + } + if(keyToggles[(unsigned)'z']) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } else { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + + auto P = make_shared(); + auto MV = make_shared(); + P->pushMatrix(); + MV->pushMatrix(); + + double aspect = (double)width/height; + double s = 1.1; + P->multMatrix(glm::ortho(-s*aspect, s*aspect, -s, s)); + + // Draw cage + progSimple->bind(); + glUniformMatrix4fv(progSimple->getUniform("P"), 1, GL_FALSE, glm::value_ptr(P->topMatrix())); + glUniformMatrix4fv(progSimple->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix())); + grid->draw(); + progSimple->unbind(); + + // Draw textured shape + progTex->bind(); + texture->bind(progTex->getUniform("colorTexture")); + glUniformMatrix4fv(progTex->getUniform("P"), 1, GL_FALSE, glm::value_ptr(P->topMatrix())); + glUniformMatrix4fv(progTex->getUniform("MV"), 1, GL_FALSE, glm::value_ptr(MV->topMatrix())); + shape->toWorld(); + shape->draw(progTex->getAttribute("vertPos"), progTex->getAttribute("vertTex")); + texture->unbind(); + progTex->unbind(); + + // Pop matrix stacks. + MV->popMatrix(); + P->popMatrix(); + + GLSL::checkError(GET_FILE_LINE); +} + +int main(int argc, char **argv) +{ + if(argc < 2) { + cout << "Please specify the resource directory." << endl; + return 0; + } + RESOURCE_DIR = argv[1] + string("/"); + + // Set error callback. + glfwSetErrorCallback(error_callback); + // Initialize the library. + if(!glfwInit()) { + return -1; + } + // Create a windowed mode window and its OpenGL context. + window = glfwCreateWindow(640, 480, "YOUR NAME", NULL, NULL); + if(!window) { + glfwTerminate(); + return -1; + } + // Make the window's context current. + glfwMakeContextCurrent(window); + // Initialize GLEW. + glewExperimental = true; + if(glewInit() != GLEW_OK) { + cerr << "Failed to initialize GLEW" << endl; + return -1; + } + glGetError(); // A bug in glewInit() causes an error that we can safely ignore. + cout << "OpenGL version: " << glGetString(GL_VERSION) << endl; + cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl; + // Set vsync. + glfwSwapInterval(1); + // Set keyboard callback. + glfwSetKeyCallback(window, key_callback); + // Set char callback. + glfwSetCharCallback(window, char_callback); + // Set cursor position callback. + glfwSetCursorPosCallback(window, cursor_position_callback); + // Set mouse button callback. + glfwSetMouseButtonCallback(window, mouse_button_callback); + // Initialize scene. + init(); + // Loop until the user closes the window. + while(!glfwWindowShouldClose(window)) { + // Render scene. + render(); + // Swap front and back buffers. + glfwSwapBuffers(window); + // Poll for and process events. + glfwPollEvents(); + } + // Quit program. + glfwDestroyWindow(window); + glfwTerminate(); + return 0; +} diff --git a/L15/src/stb_image.h b/L15/src/stb_image.h new file mode 100644 index 0000000..a3c1129 --- /dev/null +++ b/L15/src/stb_image.h @@ -0,0 +1,6755 @@ +/* stb_image - v2.12 - public domain image loader - http://nothings.org/stb_image.h + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8-bit-per-channel (16 bpc not supported) + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + + Revision 2.00 release notes: + + - Progressive JPEG is now supported. + + - PPM and PGM binary formats are now supported, thanks to Ken Miller. + + - x86 platforms now make use of SSE2 SIMD instructions for + JPEG decoding, and ARM platforms can use NEON SIMD if requested. + This work was done by Fabian "ryg" Giesen. SSE2 is used by + default, but NEON must be enabled explicitly; see docs. + + With other JPEG optimizations included in this version, we see + 2x speedup on a JPEG on an x86 machine, and a 1.5x speedup + on a JPEG on an ARM machine, relative to previous versions of this + library. The same results will not obtain for all JPGs and for all + x86/ARM machines. (Note that progressive JPEGs are significantly + slower to decode than regular JPEGs.) This doesn't mean that this + is the fastest JPEG decoder in the land; rather, it brings it + closer to parity with standard libraries. If you want the fastest + decode, look elsewhere. (See "Philosophy" section of docs below.) + + See final bullet items below for more info on SIMD. + + - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing + the memory allocator. Unlike other STBI libraries, these macros don't + support a context parameter, so if you need to pass a context in to + the allocator, you'll have to store it in a global or a thread-local + variable. + + - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and + STBI_NO_LINEAR. + STBI_NO_HDR: suppress implementation of .hdr reader format + STBI_NO_LINEAR: suppress high-dynamic-range light-linear float API + + - You can suppress implementation of any of the decoders to reduce + your code footprint by #defining one or more of the following + symbols before creating the implementation. + + STBI_NO_JPEG + STBI_NO_PNG + STBI_NO_BMP + STBI_NO_PSD + STBI_NO_TGA + STBI_NO_GIF + STBI_NO_HDR + STBI_NO_PIC + STBI_NO_PNM (.ppm and .pgm) + + - You can request *only* certain decoders and suppress all other ones + (this will be more forward-compatible, as addition of new decoders + doesn't require you to disable them explicitly): + + STBI_ONLY_JPEG + STBI_ONLY_PNG + STBI_ONLY_BMP + STBI_ONLY_PSD + STBI_ONLY_TGA + STBI_ONLY_GIF + STBI_ONLY_HDR + STBI_ONLY_PIC + STBI_ONLY_PNM (.ppm and .pgm) + + Note that you can define multiples of these, and you will get all + of them ("only x" and "only y" is interpreted to mean "only x&y"). + + - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still + want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB + + - Compilation of all SIMD code can be suppressed with + #define STBI_NO_SIMD + It should not be necessary to disable SIMD unless you have issues + compiling (e.g. using an x86 compiler which doesn't support SSE + intrinsics or that doesn't support the method used to detect + SSE2 support at run-time), and even those can be reported as + bugs so I can refine the built-in compile-time checking to be + smarter. + + - The old STBI_SIMD system which allowed installing a user-defined + IDCT etc. has been removed. If you need this, don't upgrade. My + assumption is that almost nobody was doing this, and those who + were will find the built-in SIMD more satisfactory anyway. + + - RGB values computed for JPEG images are slightly different from + previous versions of stb_image. (This is due to using less + integer precision in SIMD.) The C code has been adjusted so + that the same RGB values will be computed regardless of whether + SIMD support is available, so your app should always produce + consistent results. But these results are slightly different from + previous versions. (Specifically, about 3% of available YCbCr values + will compute different RGB results from pre-1.49 versions by +-1; + most of the deviating values are one smaller in the G channel.) + + - If you must produce consistent results with previous versions of + stb_image, #define STBI_JPEG_OLD and you will get the same results + you used to; however, you will not get the SIMD speedups for + the YCbCr-to-RGB conversion step (although you should still see + significant JPEG speedup from the other changes). + + Please note that STBI_JPEG_OLD is a temporary feature; it will be + removed in future versions of the library. It is only intended for + near-term back-compatibility use. + + + Latest revision history: + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) partial animated GIF support + limited 16-bit PSD support + minor bugs, code cleanup, and compiler warnings + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) additional corruption checking + stbi_set_flip_vertically_on_load + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD + progressive JPEG + PGM/PPM support + STBI_MALLOC,STBI_REALLOC,STBI_FREE + STBI_NO_*, STBI_ONLY_* + GIF bugfix + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + urraka@github (animated gif) Junggon Kim (PNM comments) + Daniel Gibson (16-bit TGA) + + Optimizations & bugfixes + Fabian "ryg" Giesen + Arseny Kapoulkine + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Martin Golini Jerry Jansson Joseph Thomson + Dave Moore Roy Eltham Hayaki Saito Phil Jordan + Won Chun Luke Graham Johan Duparc Nathan Reed + the Horde3D community Thomas Ruf Ronny Chevalier Nick Verigakis + Janez Zemva John Bartholomew Michal Cichon svdijk@github + Jonathan Blow Ken Hamada Tero Hanninen Baldur Karlsson + Laurent Gomila Cort Stratton Sergio Gonzalez romigrou@github + Aruelien Pocheville Thibault Reuille Cass Everitt Matthew Gregan + Ryamond Barbiero Paul Du Bois Engin Manap snagar@github + Michaelangel007@github Oriol Ferrer Mesia socks-the-fox + Blazej Dariusz Roszkowski + + +LICENSE + +This software is dual-licensed to the public domain and under the following +license: you are granted a perpetual, irrevocable license to copy, modify, +publish, and distribute this file as you see fit. + +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 16-bit-per-channel PNG +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - no 1-bit BMP +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *comp -- outputs # of image components in image file +// int req_comp -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. +// If req_comp is non-zero, *comp has the number of components that _would_ +// have been output otherwise. E.g. if you set req_comp to 4, you will always +// get RGBA output, but you can check *comp to see if it's trivially opaque +// because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *comp will be unchanged. The function stbi_failure_reason() +// can be queried for an extremely brief, end-user unfriendly explanation +// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid +// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy to use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// make more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// The output of the JPEG decoder is slightly different from versions where +// SIMD support was introduced (that is, for versions before 1.49). The +// difference is only +-1 in the 8-bit RGB channels, and only on a small +// fraction of pixels. You can force the pre-1.49 behavior by defining +// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path +// and hence cost some performance. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image now supports loading HDR images in general, and currently +// the Radiance .HDR file format, although the support is provided +// generically. You can still load any file through the existing interface; +// if you attempt to load an HDR file, it will be automatically remapped to +// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// By default we convert iphone-formatted PNGs back to RGB, even though +// they are internally encoded differently. You can disable this conversion +// by by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through (which +// is BGR stored in RGB). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// + + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for req_comp + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +typedef unsigned char stbi_uc; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *comp, int req_comp); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// NOT THREADSAFE +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); + +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// NOTE: not clear do we actually need this for the 64-bit path? +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// (but compiling with -msse2 allows the compiler to use SSE2 everywhere; +// this is just broken and gcc are jerks for not fixing it properly +// http://www.virtualdub.org/blog/pivot/entry.php?id=363 ) +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +static int stbi__sse2_available() +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +static int stbi__sse2_available() +{ +#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later + // GCC 4.8+ has a nice way to do this + return __builtin_cpu_supports("sse2"); +#else + // portable way to do this, preferably without using GCC inline ASM? + // just bail for now. + return 0; +#endif +} +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +// assume GCC or Clang on ARM targets +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + fseek((FILE*) user, n, SEEK_CUR); +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +// this is not threadsafe +static const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load = flag_true_if_should_flip; +} + +static unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static unsigned char *stbi__load_flip(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result = stbi__load_main(s, x, y, comp, req_comp); + + if (stbi__vertically_flip_on_load && result != NULL) { + int w = *x, h = *y; + int depth = req_comp ? req_comp : *comp; + int row,col,z; + stbi_uc temp; + + // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once + for (row = 0; row < (h>>1); row++) { + for (col = 0; col < w; col++) { + for (z = 0; z < depth; z++) { + temp = result[(row * w + col) * depth + z]; + result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z]; + result[((h - row - 1) * w + col) * depth + z] = temp; + } + } + } + } + + return result; +} + +#ifndef STBI_NO_HDR +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int w = *x, h = *y; + int depth = req_comp ? req_comp : *comp; + int row,col,z; + float temp; + + // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once + for (row = 0; row < (h>>1); row++) { + for (col = 0; col < w; col++) { + for (z = 0; z < depth; z++) { + temp = result[(row * w + col) * depth + z]; + result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z]; + result[((h - row - 1) * w + col) * depth + z] = temp; + } + } + } + } +} +#endif + +#ifndef STBI_NO_STDIO + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_flip(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} +#endif //!STBI_NO_STDIO + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_flip(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_flip(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_flip(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_file(&s,f); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} + +static void stbi__skip(stbi__context *s, int n) +{ + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} + +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} + +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} + +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + return z + (stbi__get16le(s) << 16); +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + + +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc(req_comp * x * y); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define COMBO(a,b) ((a)*8+(b)) + #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (COMBO(img_n, req_comp)) { + CASE(1,2) dest[0]=src[0], dest[1]=255; break; + CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; + CASE(2,1) dest[0]=src[0]; break; + CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; + CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; + CASE(3,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; + CASE(3,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; break; + CASE(4,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; + CASE(4,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; + CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; + default: STBI_ASSERT(0); + } + #undef CASE + } + + STBI_FREE(data); + return good; +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output = (float *) stbi__malloc(x * y * comp * sizeof(float)); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi_uc dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0,code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (stbi_uc) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (-1 << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + k = stbi_lrot(j->code_buffer, n); + STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & ~sgn); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc << j->succ_low); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) << 12) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0] << 2; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4; + int t = q & 15,i; + if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s); + L -= 65; + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + stbi__skip(z->s, stbi__get16be(z->s)-2); + return 1; + } + return 0; +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + c = stbi__get8(s); + if (c != 3 && c != 1) return stbi__err("bad component count","Corrupt JPEG"); // JFIF requires + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (z->img_comp[i].id != i+1) // JFIF requires + if (z->img_comp[i].id != i) { // some version of jpegtran outputs non-JFIF-compliant files! + // somethings output this (see http://fileformats.archiveteam.org/wiki/JPEG#Color_format) + if (z->img_comp[i].id != rgb[i]) + return stbi__err("bad component ID","Corrupt JPEG"); + ++z->rgb; + } + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); + + if (z->img_comp[i].raw_data == NULL) { + for(--i; i >= 0; --i) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + } + return stbi__err("outofmem", "Out of memory"); + } + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + z->img_comp[i].linebuf = NULL; + if (z->progressive) { + z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3; + z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3; + z->img_comp[i].raw_coeff = STBI_MALLOC(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } else { + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } else if (x != 0) { + return stbi__err("junk before marker", "Corrupt JPEG"); + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +#ifdef STBI_JPEG_OLD +// this is the same YCbCr-to-RGB calculation that stb_image has used +// historically before the algorithm changes in 1.49 +#define float2fixed(x) ((int) ((x) * 65536 + 0.5)) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 16) + 32768; // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr*float2fixed(1.40200f); + g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); + b = y_fixed + cb*float2fixed(1.77200f); + r >>= 16; + g >>= 16; + b >>= 16; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#else +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* float2fixed(1.40200f); + g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* float2fixed(1.40200f); + g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + #ifndef STBI_JPEG_OLD + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + #endif + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + #ifndef STBI_JPEG_OLD + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + #endif + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + int i; + for (i=0; i < j->s->img_n; ++i) { + if (j->img_comp[i].raw_data) { + STBI_FREE(j->img_comp[i].raw_data); + j->img_comp[i].raw_data = NULL; + j->img_comp[i].data = NULL; + } + if (j->img_comp[i].raw_coeff) { + STBI_FREE(j->img_comp[i].raw_coeff); + j->img_comp[i].raw_coeff = 0; + j->img_comp[i].coeff = 0; + } + if (j->img_comp[i].linebuf) { + STBI_FREE(j->img_comp[i].linebuf); + j->img_comp[i].linebuf = NULL; + } + } +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n; + + if (z->s->img_n == 3 && n < 3) + decode_n = 1; + else + decode_n = z->s->img_n; + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4]; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (z->rgb == 3) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n; // report original components, not output + return output; + } +} + +static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg j; + j.s = s; + stbi__setup_jpeg(&j); + r = stbi__decode_jpeg_header(&j, STBI__SCAN_type); + stbi__rewind(s); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[288]; + stbi__uint16 value[288]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + if (z->zbuffer >= z->zbuffer_end) return 0; + return *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + STBI_ASSERT(z->size[b] == s); + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) stbi__fill_bits(a); + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (int) (z->zout - z->zout_start); + limit = old_limit = (int) (z->zout_end - z->zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < hlit + hdist) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else if (c == 16) { + c = stbi__zreceive(a,2)+3; + memset(lencodes+n, lencodes[n-1], c); + n += c; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + memset(lencodes+n, 0, c); + n += c; + } else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a,7)+11; + memset(lencodes+n, 0, c); + n += c; + } + } + if (n != hlit+hdist) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + STBI_ASSERT(a->num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +// @TODO: should statically initialize these for optimal thread safety +static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32]; +static void stbi__init_zdefaults(void) +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zdefault_distance[31]) stbi__init_zdefaults(); + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc(x * y * output_bytes); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + if (s->img_x == x && s->img_y == y) { + if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); + } else { // interlaced: + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + } + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior = cur - stride; + int filter = *raw++; + + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + STBI_ASSERT(img_width_bytes <= x); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes+1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*filter_bytes; + #define CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); break; + CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); break; + } + #undef CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ + for (k=0; k < filter_bytes; ++k) + switch (filter) { + CASE(STBI__F_none) cur[k] = raw[k]; break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); break; + CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); break; + } + #undef CASE + + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride*j; // start at the beginning of the row again + for (i=0; i < x; ++i,cur+=output_bytes) { + cur[filter_bytes+1] = 255; + } + } + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16*)cur; + + for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n, + a->out + (j*x+i)*out_n, out_n); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__reduce_png(stbi__png *p) +{ + int i; + int img_len = p->s->img_x * p->s->img_y * p->s->img_out_n; + stbi_uc *reduced; + stbi__uint16 *orig = (stbi__uint16*)p->out; + + if (p->depth != 16) return 1; // don't need to do anything if not 16-bit data + + reduced = (stbi_uc *)stbi__malloc(img_len); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is a decent approx of 16->8 bit scaling + + p->out = reduced; + STBI_FREE(orig); + + return 1; +} + +static int stbi__unpremultiply_on_load = 0; +static int stbi__de_iphone_flag = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + p[0] = p[2] * 255 / a; + p[1] = p[1] * 255 / a; + p[2] = t * 255 / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) tc16[k] = stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } + STBI_FREE(z->expanded); z->expanded = NULL; + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp) +{ + unsigned char *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth == 16) { + if (!stbi__reduce_png(p)) { + return result; + } + } + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) n += 16, z >>= 16; + if (z >= 0x00100) n += 8, z >>= 8; + if (z >= 0x00010) n += 4, z >>= 4; + if (z >= 0x00004) n += 2, z >>= 2; + if (z >= 0x00002) n += 1, z >>= 1; + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +static int stbi__shiftsigned(int v, int shift, int bits) +{ + int result; + int z=0; + + if (shift < 0) v <<= -shift; + else v >>= shift; + result = v; + + z = bits; + while (z < 8) { + result += v >> z; + z += bits; + } + return result; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; +} stbi__bmp_data; + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - 14 - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - 14 - info.hsz) >> 2; + } + + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - 14 - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i], p1[i] = p2[i], p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if(is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // else: fall-through + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fall-through + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (r * 255)/31; + out[1] = (g * 255)/31; + out[2] = (b * 255)/31; + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4]; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + tga_data = (unsigned char*)stbi__malloc( (size_t)tga_width * tga_height * tga_comp ); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_comp ); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + int pixelCount; + int channelCount, compression; + int channel, i, count, len; + int bitdepth; + int w,h; + stbi_uc *out; + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Create the destination image. + out = (stbi_uc *) stbi__malloc(4 * w*h); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + count = 0; + while (count < pixelCount) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len ^= 0x0FF; + len += 2; + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out + channel; + if (channel >= channelCount) { + // Fill this channel with default data. + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } else { + // Read the data. + if (bitdepth == 16) { + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + + if (channelCount >= 4) { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + // remove weird white matte from PSD + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + + if (req_comp && req_comp != 4) { + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp) +{ + stbi_uc *result; + int i, x,y; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if ((1 << 28) / x < y) return stbi__errpuc("too large", "Image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc(x*y*4); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out, *old_out; // output buffer (always 4 components) + int flags, bgindex, ratio, transparent, eflags, delay; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[4096]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + p = &g->out[g->cur_x + g->cur_y]; + c = &g->color_table[g->codes[code].suffix * 4]; + + if (c[3] >= 128) { + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF"); + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1) +{ + int x, y; + stbi_uc *c = g->pal[g->bgindex]; + for (y = y0; y < y1; y += 4 * g->w) { + for (x = x0; x < x1; x += 4) { + stbi_uc *p = &g->out[y + x]; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = 0; + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp) +{ + int i; + stbi_uc *prev_out = 0; + + if (g->out == 0 && !stbi__gif_header(s, g, comp,0)) + return 0; // stbi__g_failure_reason set by stbi__gif_header + + prev_out = g->out; + g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); + + switch ((g->eflags & 0x1C) >> 2) { + case 0: // unspecified (also always used on 1st frame) + stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h); + break; + case 1: // do not dispose + if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); + g->old_out = prev_out; + break; + case 2: // dispose to background + if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); + stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y); + break; + case 3: // dispose to previous + if (g->old_out) { + for (i = g->start_y; i < g->max_y; i += 4 * g->w) + memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x); + } + break; + } + + for (;;) { + switch (stbi__get8(s)) { + case 0x2C: /* Image Descriptor */ + { + int prev_trans = -1; + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + if (g->transparent >= 0 && (g->eflags & 0x01)) { + prev_trans = g->pal[g->transparent][3]; + g->pal[g->transparent][3] = 0; + } + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (o == NULL) return NULL; + + if (prev_trans != -1) + g->pal[g->transparent][3] = (stbi_uc) prev_trans; + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = stbi__get16le(s); + g->transparent = stbi__get8(s); + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) + stbi__skip(s, len); + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } + + STBI_NOTUSED(req_comp); +} + +static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *u = 0; + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + memset(g, 0, sizeof(*g)); + + u = stbi__gif_load_next(s, g, comp, req_comp); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g->w; + *y = g->h; + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g->w, g->h); + } + else if (g->out) + STBI_FREE(g->out); + STBI_FREE(g); + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s) +{ + const char *signature = "#?RADIANCE\n"; + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s); + stbi__rewind(s); + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + + + // Check identifier + if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + // Read data + hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float)); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4); + + for (k = 0; k < 4; ++k) { + i = 0; + while (i < width) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + stbi__rewind( s ); + if (p == NULL) + return 0; + *x = s->img_x; + *y = s->img_y; + *comp = info.ma ? 4 : 3; + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + if (stbi__get16be(s) != 8) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained; + stbi__pic_packet packets[10]; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) +// Does not support 16-bit-per-channel + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *out; + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; + *x = s->img_x; + *y = s->img_y; + *comp = s->img_n; + + out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv; + char c, p, t; + + stbi__rewind( s ); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ diff --git a/L15/src/tiny_obj_loader.h b/L15/src/tiny_obj_loader.h new file mode 100644 index 0000000..b975601 --- /dev/null +++ b/L15/src/tiny_obj_loader.h @@ -0,0 +1,1922 @@ +/* +The MIT License (MIT) + +Copyright (c) 2012-2016 Syoyo Fujita and many contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// +// version 1.0.3 : Support parsing texture options(#85) +// version 1.0.2 : Improve parsing speed by about a factor of 2 for large +// files(#105) +// version 1.0.1 : Fixes a shape is lost if obj ends with a 'usemtl'(#104) +// version 1.0.0 : Change data structure. Change license from BSD to MIT. +// + +// +// Use this in *one* .cc +// #define TINYOBJLOADER_IMPLEMENTATION +// #include "tiny_obj_loader.h" +// + +#ifndef TINY_OBJ_LOADER_H_ +#define TINY_OBJ_LOADER_H_ + +#include +#include +#include + +namespace tinyobj { + +// https://en.wikipedia.org/wiki/Wavefront_.obj_file says ... +// +// -blendu on | off # set horizontal texture blending +// (default on) +// -blendv on | off # set vertical texture blending +// (default on) +// -boost float_value # boost mip-map sharpness +// -mm base_value gain_value # modify texture map values (default +// 0 1) +// # base_value = brightness, +// gain_value = contrast +// -o u [v [w]] # Origin offset (default +// 0 0 0) +// -s u [v [w]] # Scale (default +// 1 1 1) +// -t u [v [w]] # Turbulence (default +// 0 0 0) +// -texres resolution # texture resolution to create +// -clamp on | off # only render texels in the clamped +// 0-1 range (default off) +// # When unclamped, textures are +// repeated across a surface, +// # when clamped, only texels which +// fall within the 0-1 +// # range are rendered. +// -bm mult_value # bump multiplier (for bump maps +// only) +// +// -imfchan r | g | b | m | l | z # specifies which channel of the file +// is used to +// # create a scalar or bump texture. +// r:red, g:green, +// # b:blue, m:matte, l:luminance, +// z:z-depth.. +// # (the default for bump is 'l' and +// for decal is 'm') +// bump -imfchan r bumpmap.tga # says to use the red channel of +// bumpmap.tga as the bumpmap +// +// For reflection maps... +// +// -type sphere # specifies a sphere for a "refl" +// reflection map +// -type cube_top | cube_bottom | # when using a cube map, the texture +// file for each +// cube_front | cube_back | # side of the cube is specified +// separately +// cube_left | cube_right + +typedef enum { + TEXTURE_TYPE_NONE, // default + TEXTURE_TYPE_SPHERE, + TEXTURE_TYPE_CUBE_TOP, + TEXTURE_TYPE_CUBE_BOTTOM, + TEXTURE_TYPE_CUBE_FRONT, + TEXTURE_TYPE_CUBE_BACK, + TEXTURE_TYPE_CUBE_LEFT, + TEXTURE_TYPE_CUBE_RIGHT +} texture_type_t; + +typedef struct { + texture_type_t type; // -type (default TEXTURE_TYPE_NONE) + float sharpness; // -boost (default 1.0?) + float brightness; // base_value in -mm option (default 0) + float contrast; // gain_value in -mm option (default 1) + float origin_offset[3]; // -o u [v [w]] (default 0 0 0) + float scale[3]; // -s u [v [w]] (default 1 1 1) + float turbulence[3]; // -t u [v [w]] (default 0 0 0) + // int texture_resolution; // -texres resolution (default = ?) TODO + bool clamp; // -clamp (default false) + char imfchan; // -imfchan (the default for bump is 'l' and for decal is 'm') + bool blendu; // -blendu (default on) + bool blendv; // -blendv (default on) + float bump_multiplier; // -bm (for bump maps only, default 1.0) +} texture_option_t; + +typedef struct { + std::string name; + + float ambient[3]; + float diffuse[3]; + float specular[3]; + float transmittance[3]; + float emission[3]; + float shininess; + float ior; // index of refraction + float dissolve; // 1 == opaque; 0 == fully transparent + // illumination model (see http://www.fileformat.info/format/material/) + int illum; + + int dummy; // Suppress padding warning. + + std::string ambient_texname; // map_Ka + std::string diffuse_texname; // map_Kd + std::string specular_texname; // map_Ks + std::string specular_highlight_texname; // map_Ns + std::string bump_texname; // map_bump, bump + std::string displacement_texname; // disp + std::string alpha_texname; // map_d + + texture_option_t ambient_texopt; + texture_option_t diffuse_texopt; + texture_option_t specular_texopt; + texture_option_t specular_highlight_texopt; + texture_option_t bump_texopt; + texture_option_t displacement_texopt; + texture_option_t alpha_texopt; + + // PBR extension + // http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr + float roughness; // [0, 1] default 0 + float metallic; // [0, 1] default 0 + float sheen; // [0, 1] default 0 + float clearcoat_thickness; // [0, 1] default 0 + float clearcoat_roughness; // [0, 1] default 0 + float anisotropy; // aniso. [0, 1] default 0 + float anisotropy_rotation; // anisor. [0, 1] default 0 + float pad0; + float pad1; + std::string roughness_texname; // map_Pr + std::string metallic_texname; // map_Pm + std::string sheen_texname; // map_Ps + std::string emissive_texname; // map_Ke + std::string normal_texname; // norm. For normal mapping. + + texture_option_t roughness_texopt; + texture_option_t metallic_texopt; + texture_option_t sheen_texopt; + texture_option_t emissive_texopt; + texture_option_t normal_texopt; + + int pad2; + + std::map unknown_parameter; +} material_t; + +typedef struct { + std::string name; + + std::vector intValues; + std::vector floatValues; + std::vector stringValues; +} tag_t; + +// Index struct to support different indices for vtx/normal/texcoord. +// -1 means not used. +typedef struct { + int vertex_index; + int normal_index; + int texcoord_index; +} index_t; + +typedef struct { + std::vector indices; + std::vector num_face_vertices; // The number of vertices per + // face. 3 = polygon, 4 = quad, + // ... Up to 255. + std::vector material_ids; // per-face material ID + std::vector tags; // SubD tag +} mesh_t; + +typedef struct { + std::string name; + mesh_t mesh; +} shape_t; + +// Vertex attributes +typedef struct { + std::vector vertices; // 'v' + std::vector normals; // 'vn' + std::vector texcoords; // 'vt' +} attrib_t; + +typedef struct callback_t_ { + // W is optional and set to 1 if there is no `w` item in `v` line + void (*vertex_cb)(void *user_data, float x, float y, float z, float w); + void (*normal_cb)(void *user_data, float x, float y, float z); + + // y and z are optional and set to 0 if there is no `y` and/or `z` item(s) in + // `vt` line. + void (*texcoord_cb)(void *user_data, float x, float y, float z); + + // called per 'f' line. num_indices is the number of face indices(e.g. 3 for + // triangle, 4 for quad) + // 0 will be passed for undefined index in index_t members. + void (*index_cb)(void *user_data, index_t *indices, int num_indices); + // `name` material name, `material_id` = the array index of material_t[]. -1 + // if + // a material not found in .mtl + void (*usemtl_cb)(void *user_data, const char *name, int material_id); + // `materials` = parsed material data. + void (*mtllib_cb)(void *user_data, const material_t *materials, + int num_materials); + // There may be multiple group names + void (*group_cb)(void *user_data, const char **names, int num_names); + void (*object_cb)(void *user_data, const char *name); + + callback_t_() + : vertex_cb(NULL), + normal_cb(NULL), + texcoord_cb(NULL), + index_cb(NULL), + usemtl_cb(NULL), + mtllib_cb(NULL), + group_cb(NULL), + object_cb(NULL) {} +} callback_t; + +class MaterialReader { + public: + MaterialReader() {} + virtual ~MaterialReader(); + + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, + std::string *err) = 0; +}; + +class MaterialFileReader : public MaterialReader { + public: + explicit MaterialFileReader(const std::string &mtl_basedir) + : m_mtlBaseDir(mtl_basedir) {} + virtual ~MaterialFileReader() {} + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, std::string *err); + + private: + std::string m_mtlBaseDir; +}; + +class MaterialStreamReader : public MaterialReader { + public: + explicit MaterialStreamReader(std::istream &inStream) + : m_inStream(inStream) {} + virtual ~MaterialStreamReader() {} + virtual bool operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, std::string *err); + + private: + std::istream &m_inStream; +}; + +/// Loads .obj from a file. +/// 'attrib', 'shapes' and 'materials' will be filled with parsed shape data +/// 'shapes' will be filled with parsed shape data +/// Returns true when loading .obj become success. +/// Returns warning and error message into `err` +/// 'mtl_basedir' is optional, and used for base directory for .mtl file. +/// In default(`NULL'), .mtl file is searched from an application's working directory. +/// 'triangulate' is optional, and used whether triangulate polygon face in .obj +/// or not. +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *err, + const char *filename, const char *mtl_basedir = NULL, + bool triangulate = true); + +/// Loads .obj from a file with custom user callback. +/// .mtl is loaded as usual and parsed material_t data will be passed to +/// `callback.mtllib_cb`. +/// Returns true when loading .obj/.mtl become success. +/// Returns warning and error message into `err` +/// See `examples/callback_api/` for how to use this function. +bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback, + void *user_data = NULL, + MaterialReader *readMatFn = NULL, + std::string *err = NULL); + +/// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve +/// std::istream for materials. +/// Returns true when loading .obj become success. +/// Returns warning and error message into `err` +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *err, + std::istream *inStream, MaterialReader *readMatFn = NULL, + bool triangulate = true); + +/// Loads materials into std::map +void LoadMtl(std::map *material_map, + std::vector *materials, std::istream *inStream); + +} // namespace tinyobj + +#ifdef TINYOBJLOADER_IMPLEMENTATION +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace tinyobj { + +MaterialReader::~MaterialReader() {} + +#define TINYOBJ_SSCANF_BUFFER_SIZE (4096) + +struct vertex_index { + int v_idx, vt_idx, vn_idx; + vertex_index() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} + explicit vertex_index(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {} + vertex_index(int vidx, int vtidx, int vnidx) + : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {} +}; + +struct tag_sizes { + tag_sizes() : num_ints(0), num_floats(0), num_strings(0) {} + int num_ints; + int num_floats; + int num_strings; +}; + +struct obj_shape { + std::vector v; + std::vector vn; + std::vector vt; +}; + +// See +// http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf +static std::istream &safeGetline(std::istream &is, std::string &t) { + t.clear(); + + // The characters in the stream are read one-by-one using a std::streambuf. + // That is faster than reading them one-by-one using the std::istream. + // Code that uses streambuf this way must be guarded by a sentry object. + // The sentry object performs various tasks, + // such as thread synchronization and updating the stream state. + + std::istream::sentry se(is, true); + std::streambuf *sb = is.rdbuf(); + + for (;;) { + int c = sb->sbumpc(); + switch (c) { + case '\n': + return is; + case '\r': + if (sb->sgetc() == '\n') sb->sbumpc(); + return is; + case EOF: + // Also handle the case when the last line has no line ending + if (t.empty()) is.setstate(std::ios::eofbit); + return is; + default: + t += static_cast(c); + } + } +} + +#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) +#define IS_DIGIT(x) \ + (static_cast((x) - '0') < static_cast(10)) +#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) + +// Make index zero-base, and also support relative index. +static inline int fixIndex(int idx, int n) { + if (idx > 0) return idx - 1; + if (idx == 0) return 0; + return n + idx; // negative value = relative +} + +static inline std::string parseString(const char **token) { + std::string s; + (*token) += strspn((*token), " \t"); + size_t e = strcspn((*token), " \t\r"); + s = std::string((*token), &(*token)[e]); + (*token) += e; + return s; +} + +static inline int parseInt(const char **token) { + (*token) += strspn((*token), " \t"); + int i = atoi((*token)); + (*token) += strcspn((*token), " \t\r"); + return i; +} + +// Tries to parse a floating point number located at s. +// +// s_end should be a location in the string where reading should absolutely +// stop. For example at the end of the string, to prevent buffer overflows. +// +// Parses the following EBNF grammar: +// sign = "+" | "-" ; +// END = ? anything not in digit ? +// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; +// integer = [sign] , digit , {digit} ; +// decimal = integer , ["." , integer] ; +// float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; +// +// Valid strings are for example: +// -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 +// +// If the parsing is a success, result is set to the parsed value and true +// is returned. +// +// The function is greedy and will parse until any of the following happens: +// - a non-conforming character is encountered. +// - s_end is reached. +// +// The following situations triggers a failure: +// - s >= s_end. +// - parse failure. +// +static bool tryParseDouble(const char *s, const char *s_end, double *result) { + if (s >= s_end) { + return false; + } + + double mantissa = 0.0; + // This exponent is base 2 rather than 10. + // However the exponent we parse is supposed to be one of ten, + // thus we must take care to convert the exponent/and or the + // mantissa to a * 2^E, where a is the mantissa and E is the + // exponent. + // To get the final double we will use ldexp, it requires the + // exponent to be in base 2. + int exponent = 0; + + // NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED + // TO JUMP OVER DEFINITIONS. + char sign = '+'; + char exp_sign = '+'; + char const *curr = s; + + // How many characters were read in a loop. + int read = 0; + // Tells whether a loop terminated due to reaching s_end. + bool end_not_reached = false; + + /* + BEGIN PARSING. + */ + + // Find out what sign we've got. + if (*curr == '+' || *curr == '-') { + sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + goto fail; + } + + // Read the integer part. + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + mantissa *= 10; + mantissa += static_cast(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + + // We must make sure we actually got something. + if (read == 0) goto fail; + // We allow numbers of form "#", "###" etc. + if (!end_not_reached) goto assemble; + + // Read the decimal part. + if (*curr == '.') { + curr++; + read = 1; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + static const double pow_lut[] = { + 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, + }; + const int lut_entries = sizeof pow_lut / sizeof pow_lut[0]; + + // NOTE: Don't use powf here, it will absolutely murder precision. + mantissa += static_cast(*curr - 0x30) * + (read < lut_entries ? pow_lut[read] : pow(10.0, -read)); + read++; + curr++; + end_not_reached = (curr != s_end); + } + } else if (*curr == 'e' || *curr == 'E') { + } else { + goto assemble; + } + + if (!end_not_reached) goto assemble; + + // Read the exponent part. + if (*curr == 'e' || *curr == 'E') { + curr++; + // Figure out if a sign is present and if it is. + end_not_reached = (curr != s_end); + if (end_not_reached && (*curr == '+' || *curr == '-')) { + exp_sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + // Empty E is not allowed. + goto fail; + } + + read = 0; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + exponent *= 10; + exponent += static_cast(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + exponent *= (exp_sign == '+' ? 1 : -1); + if (read == 0) goto fail; + } + +assemble: + *result = + (sign == '+' ? 1 : -1) * + (exponent ? ldexp(mantissa * pow(5.0, exponent), exponent) : mantissa); + return true; +fail: + return false; +} + +static inline float parseFloat(const char **token, double default_value = 0.0) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + double val = default_value; + tryParseDouble((*token), end, &val); + float f = static_cast(val); + (*token) = end; + return f; +} + +static inline void parseFloat2(float *x, float *y, const char **token, + const double default_x = 0.0, + const double default_y = 0.0) { + (*x) = parseFloat(token, default_x); + (*y) = parseFloat(token, default_y); +} + +static inline void parseFloat3(float *x, float *y, float *z, const char **token, + const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0) { + (*x) = parseFloat(token, default_x); + (*y) = parseFloat(token, default_y); + (*z) = parseFloat(token, default_z); +} + +static inline void parseV(float *x, float *y, float *z, float *w, + const char **token, const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0, + const double default_w = 1.0) { + (*x) = parseFloat(token, default_x); + (*y) = parseFloat(token, default_y); + (*z) = parseFloat(token, default_z); + (*w) = parseFloat(token, default_w); +} + +static inline bool parseOnOff(const char **token, bool default_value = true) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + + bool ret = default_value; + if ((0 == strncmp((*token), "on", 2))) { + ret = true; + } else if ((0 == strncmp((*token), "off", 3))) { + ret = false; + } + + (*token) = end; + return ret; +} + +static inline texture_type_t parseTextureType( + const char **token, texture_type_t default_value = TEXTURE_TYPE_NONE) { + (*token) += strspn((*token), " \t"); + const char *end = (*token) + strcspn((*token), " \t\r"); + texture_type_t ty = default_value; + + if ((0 == strncmp((*token), "cube_top", strlen("cube_top")))) { + ty = TEXTURE_TYPE_CUBE_TOP; + } else if ((0 == strncmp((*token), "cube_bottom", strlen("cube_bottom")))) { + ty = TEXTURE_TYPE_CUBE_BOTTOM; + } else if ((0 == strncmp((*token), "cube_left", strlen("cube_left")))) { + ty = TEXTURE_TYPE_CUBE_LEFT; + } else if ((0 == strncmp((*token), "cube_right", strlen("cube_right")))) { + ty = TEXTURE_TYPE_CUBE_RIGHT; + } else if ((0 == strncmp((*token), "cube_front", strlen("cube_front")))) { + ty = TEXTURE_TYPE_CUBE_FRONT; + } else if ((0 == strncmp((*token), "cube_back", strlen("cube_back")))) { + ty = TEXTURE_TYPE_CUBE_BACK; + } else if ((0 == strncmp((*token), "sphere", strlen("sphere")))) { + ty = TEXTURE_TYPE_SPHERE; + } + + (*token) = end; + return ty; +} + +static tag_sizes parseTagTriple(const char **token) { + tag_sizes ts; + + ts.num_ints = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return ts; + } + (*token)++; + + ts.num_floats = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return ts; + } + (*token)++; + + ts.num_strings = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r") + 1; + + return ts; +} + +// Parse triples with index offsets: i, i/j/k, i//k, i/j +static vertex_index parseTriple(const char **token, int vsize, int vnsize, + int vtsize) { + vertex_index vi(-1); + + vi.v_idx = fixIndex(atoi((*token)), vsize); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + (*token)++; + + // i//k + if ((*token)[0] == '/') { + (*token)++; + vi.vn_idx = fixIndex(atoi((*token)), vnsize); + (*token) += strcspn((*token), "/ \t\r"); + return vi; + } + + // i/j/k or i/j + vi.vt_idx = fixIndex(atoi((*token)), vtsize); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + + // i/j/k + (*token)++; // skip '/' + vi.vn_idx = fixIndex(atoi((*token)), vnsize); + (*token) += strcspn((*token), "/ \t\r"); + return vi; +} + +// Parse raw triples: i, i/j/k, i//k, i/j +static vertex_index parseRawTriple(const char **token) { + vertex_index vi(static_cast(0)); // 0 is an invalid index in OBJ + + vi.v_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + (*token)++; + + // i//k + if ((*token)[0] == '/') { + (*token)++; + vi.vn_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + return vi; + } + + // i/j/k or i/j + vi.vt_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + + // i/j/k + (*token)++; // skip '/' + vi.vn_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + return vi; +} + +static bool ParseTextureNameAndOption(std::string *texname, + texture_option_t *texopt, + const char *linebuf, const bool is_bump) { + // @todo { write more robust lexer and parser. } + bool found_texname = false; + std::string texture_name; + + // Fill with default value for texopt. + if (is_bump) { + texopt->imfchan = 'l'; + } else { + texopt->imfchan = 'm'; + } + texopt->bump_multiplier = 1.0f; + texopt->clamp = false; + texopt->blendu = true; + texopt->blendv = true; + texopt->sharpness = 1.0f; + texopt->brightness = 0.0f; + texopt->contrast = 1.0f; + texopt->origin_offset[0] = 0.0f; + texopt->origin_offset[1] = 0.0f; + texopt->origin_offset[2] = 0.0f; + texopt->scale[0] = 1.0f; + texopt->scale[1] = 1.0f; + texopt->scale[2] = 1.0f; + texopt->turbulence[0] = 0.0f; + texopt->turbulence[1] = 0.0f; + texopt->turbulence[2] = 0.0f; + texopt->type = TEXTURE_TYPE_NONE; + + const char *token = linebuf; // Assume line ends with NULL + + while (!IS_NEW_LINE((*token))) { + if ((0 == strncmp(token, "-blendu", 7)) && IS_SPACE((token[7]))) { + token += 8; + texopt->blendu = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-blendv", 7)) && IS_SPACE((token[7]))) { + token += 8; + texopt->blendv = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-clamp", 6)) && IS_SPACE((token[6]))) { + token += 7; + texopt->clamp = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-boost", 6)) && IS_SPACE((token[6]))) { + token += 7; + texopt->sharpness = parseFloat(&token, 1.0); + } else if ((0 == strncmp(token, "-bm", 3)) && IS_SPACE((token[3]))) { + token += 4; + texopt->bump_multiplier = parseFloat(&token, 1.0); + } else if ((0 == strncmp(token, "-o", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseFloat3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]), + &(texopt->origin_offset[2]), &token); + } else if ((0 == strncmp(token, "-s", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseFloat3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]), + &token, 1.0, 1.0, 1.0); + } else if ((0 == strncmp(token, "-t", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseFloat3(&(texopt->turbulence[0]), &(texopt->turbulence[1]), + &(texopt->turbulence[2]), &token); + } else if ((0 == strncmp(token, "-type", 5)) && IS_SPACE((token[5]))) { + token += 5; + texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE); + } else if ((0 == strncmp(token, "-imfchan", 8)) && IS_SPACE((token[8]))) { + token += 9; + token += strspn(token, " \t"); + const char *end = token + strcspn(token, " \t\r"); + if ((end - token) == 1) { // Assume one char for -imfchan + texopt->imfchan = (*token); + } + token = end; + } else if ((0 == strncmp(token, "-mm", 3)) && IS_SPACE((token[3]))) { + token += 4; + parseFloat2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0); + } else { + // Assume texture filename + token += strspn(token, " \t"); // skip space + size_t len = strcspn(token, " \t\r"); // untile next space + texture_name = std::string(token, token + len); + token += len; + + token += strspn(token, " \t"); // skip space + + found_texname = true; + } + } + + if (found_texname) { + (*texname) = texture_name; + return true; + } else { + return false; + } +} + +static void InitMaterial(material_t *material) { + material->name = ""; + material->ambient_texname = ""; + material->diffuse_texname = ""; + material->specular_texname = ""; + material->specular_highlight_texname = ""; + material->bump_texname = ""; + material->displacement_texname = ""; + material->alpha_texname = ""; + for (int i = 0; i < 3; i++) { + material->ambient[i] = 0.f; + material->diffuse[i] = 0.f; + material->specular[i] = 0.f; + material->transmittance[i] = 0.f; + material->emission[i] = 0.f; + } + material->illum = 0; + material->dissolve = 1.f; + material->shininess = 1.f; + material->ior = 1.f; + + material->roughness = 0.f; + material->metallic = 0.f; + material->sheen = 0.f; + material->clearcoat_thickness = 0.f; + material->clearcoat_roughness = 0.f; + material->anisotropy_rotation = 0.f; + material->anisotropy = 0.f; + material->roughness_texname = ""; + material->metallic_texname = ""; + material->sheen_texname = ""; + material->emissive_texname = ""; + material->normal_texname = ""; + + material->unknown_parameter.clear(); +} + +static bool exportFaceGroupToShape( + shape_t *shape, const std::vector > &faceGroup, + const std::vector &tags, const int material_id, + const std::string &name, bool triangulate) { + if (faceGroup.empty()) { + return false; + } + + // Flatten vertices and indices + for (size_t i = 0; i < faceGroup.size(); i++) { + const std::vector &face = faceGroup[i]; + + vertex_index i0 = face[0]; + vertex_index i1(-1); + vertex_index i2 = face[1]; + + size_t npolys = face.size(); + + if (triangulate) { + // Polygon -> triangle fan conversion + for (size_t k = 2; k < npolys; k++) { + i1 = i2; + i2 = face[k]; + + index_t idx0, idx1, idx2; + idx0.vertex_index = i0.v_idx; + idx0.normal_index = i0.vn_idx; + idx0.texcoord_index = i0.vt_idx; + idx1.vertex_index = i1.v_idx; + idx1.normal_index = i1.vn_idx; + idx1.texcoord_index = i1.vt_idx; + idx2.vertex_index = i2.v_idx; + idx2.normal_index = i2.vn_idx; + idx2.texcoord_index = i2.vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + } + } else { + for (size_t k = 0; k < npolys; k++) { + index_t idx; + idx.vertex_index = face[k].v_idx; + idx.normal_index = face[k].vn_idx; + idx.texcoord_index = face[k].vt_idx; + shape->mesh.indices.push_back(idx); + } + + shape->mesh.num_face_vertices.push_back( + static_cast(npolys)); + shape->mesh.material_ids.push_back(material_id); // per face + } + } + + shape->name = name; + shape->mesh.tags = tags; + + return true; +} + +void LoadMtl(std::map *material_map, + std::vector *materials, std::istream *inStream) { + // Create a default material anyway. + material_t material; + InitMaterial(&material); + + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + + // Trim trailing whitespace. + if (linebuf.size() > 0) { + linebuf = linebuf.substr(0, linebuf.find_last_not_of(" \t") + 1); + } + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // new mtl + if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) { + // flush previous material. + if (!material.name.empty()) { + material_map->insert(std::pair( + material.name, static_cast(materials->size()))); + materials->push_back(material); + } + + // initial temporary material + InitMaterial(&material); + + // set new mtl name + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + material.name = namebuf; + continue; + } + + // ambient + if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.ambient[0] = r; + material.ambient[1] = g; + material.ambient[2] = b; + continue; + } + + // diffuse + if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.diffuse[0] = r; + material.diffuse[1] = g; + material.diffuse[2] = b; + continue; + } + + // specular + if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.specular[0] = r; + material.specular[1] = g; + material.specular[2] = b; + continue; + } + + // transmittance + if ((token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) || + (token[0] == 'T' && token[1] == 'f' && IS_SPACE((token[2])))) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.transmittance[0] = r; + material.transmittance[1] = g; + material.transmittance[2] = b; + continue; + } + + // ior(index of refraction) + if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) { + token += 2; + material.ior = parseFloat(&token); + continue; + } + + // emission + if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) { + token += 2; + float r, g, b; + parseFloat3(&r, &g, &b, &token); + material.emission[0] = r; + material.emission[1] = g; + material.emission[2] = b; + continue; + } + + // shininess + if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.shininess = parseFloat(&token); + continue; + } + + // illum model + if (0 == strncmp(token, "illum", 5) && IS_SPACE(token[5])) { + token += 6; + material.illum = parseInt(&token); + continue; + } + + // dissolve + if ((token[0] == 'd' && IS_SPACE(token[1]))) { + token += 1; + material.dissolve = parseFloat(&token); + continue; + } + if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + // Invert value of Tr(assume Tr is in range [0, 1]) + material.dissolve = 1.0f - parseFloat(&token); + continue; + } + + // PBR: roughness + if (token[0] == 'P' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + material.roughness = parseFloat(&token); + continue; + } + + // PBR: metallic + if (token[0] == 'P' && token[1] == 'm' && IS_SPACE(token[2])) { + token += 2; + material.metallic = parseFloat(&token); + continue; + } + + // PBR: sheen + if (token[0] == 'P' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.sheen = parseFloat(&token); + continue; + } + + // PBR: clearcoat thickness + if (token[0] == 'P' && token[1] == 'c' && IS_SPACE(token[2])) { + token += 2; + material.clearcoat_thickness = parseFloat(&token); + continue; + } + + // PBR: clearcoat roughness + if ((0 == strncmp(token, "Pcr", 3)) && IS_SPACE(token[3])) { + token += 4; + material.clearcoat_roughness = parseFloat(&token); + continue; + } + + // PBR: anisotropy + if ((0 == strncmp(token, "aniso", 5)) && IS_SPACE(token[5])) { + token += 6; + material.anisotropy = parseFloat(&token); + continue; + } + + // PBR: anisotropy rotation + if ((0 == strncmp(token, "anisor", 6)) && IS_SPACE(token[6])) { + token += 7; + material.anisotropy_rotation = parseFloat(&token); + continue; + } + + // ambient texture + if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.ambient_texname), + &(material.ambient_texopt), token, + /* is_bump */ false); + continue; + } + + // diffuse texture + if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.diffuse_texname), + &(material.diffuse_texopt), token, + /* is_bump */ false); + continue; + } + + // specular texture + if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.specular_texname), + &(material.specular_texopt), token, + /* is_bump */ false); + continue; + } + + // specular highlight texture + if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.specular_highlight_texname), + &(material.specular_highlight_texopt), token, + /* is_bump */ false); + continue; + } + + // bump texture + if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) { + token += 9; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token, + /* is_bump */ true); + continue; + } + + // bump texture + if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token, + /* is_bump */ true); + continue; + } + + // alpha texture + if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) { + token += 6; + material.alpha_texname = token; + ParseTextureNameAndOption(&(material.alpha_texname), + &(material.alpha_texopt), token, + /* is_bump */ false); + continue; + } + + // displacement texture + if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.displacement_texname), + &(material.displacement_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: roughness texture + if ((0 == strncmp(token, "map_Pr", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.roughness_texname), + &(material.roughness_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: metallic texture + if ((0 == strncmp(token, "map_Pm", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.metallic_texname), + &(material.metallic_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: sheen texture + if ((0 == strncmp(token, "map_Ps", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.sheen_texname), + &(material.sheen_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: emissive texture + if ((0 == strncmp(token, "map_Ke", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.emissive_texname), + &(material.emissive_texopt), token, + /* is_bump */ false); + continue; + } + + // PBR: normal map texture + if ((0 == strncmp(token, "norm", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption( + &(material.normal_texname), &(material.normal_texopt), token, + /* is_bump */ false); // @fixme { is_bump will be true? } + continue; + } + + // unknown parameter + const char *_space = strchr(token, ' '); + if (!_space) { + _space = strchr(token, '\t'); + } + if (_space) { + std::ptrdiff_t len = _space - token; + std::string key(token, static_cast(len)); + std::string value = _space + 1; + material.unknown_parameter.insert( + std::pair(key, value)); + } + } + // flush last material. + material_map->insert(std::pair( + material.name, static_cast(materials->size()))); + materials->push_back(material); +} + +bool MaterialFileReader::operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, + std::string *err) { + std::string filepath; + + if (!m_mtlBaseDir.empty()) { + filepath = std::string(m_mtlBaseDir) + matId; + } else { + filepath = matId; + } + + std::ifstream matIStream(filepath.c_str()); + LoadMtl(matMap, materials, &matIStream); + if (!matIStream) { + std::stringstream ss; + ss << "WARN: Material file [ " << filepath + << " ] not found. Created a default material."; + if (err) { + (*err) += ss.str(); + } + } + return true; +} + +bool MaterialStreamReader::operator()(const std::string &matId, + std::vector *materials, + std::map *matMap, + std::string *err) { + (void)matId; + LoadMtl(matMap, materials, &m_inStream); + if (!m_inStream) { + std::stringstream ss; + ss << "WARN: Material stream in error state." + << " Created a default material."; + if (err) { + (*err) += ss.str(); + } + } + return true; +} + +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *err, + const char *filename, const char *mtl_basedir, + bool trianglulate) { + attrib->vertices.clear(); + attrib->normals.clear(); + attrib->texcoords.clear(); + shapes->clear(); + + std::stringstream errss; + + std::ifstream ifs(filename); + if (!ifs) { + errss << "Cannot open file [" << filename << "]" << std::endl; + if (err) { + (*err) = errss.str(); + } + return false; + } + + std::string baseDir; + if (mtl_basedir) { + baseDir = mtl_basedir; + } + MaterialFileReader matFileReader(baseDir); + + return LoadObj(attrib, shapes, materials, err, &ifs, &matFileReader, + trianglulate); +} + +bool LoadObj(attrib_t *attrib, std::vector *shapes, + std::vector *materials, std::string *err, + std::istream *inStream, MaterialReader *readMatFn /*= NULL*/, + bool triangulate) { + std::stringstream errss; + + std::vector v; + std::vector vn; + std::vector vt; + std::vector tags; + std::vector > faceGroup; + std::string name; + + // material + std::map material_map; + int material = -1; + + shape_t shape; + + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // vertex + if (token[0] == 'v' && IS_SPACE((token[1]))) { + token += 2; + float x, y, z; + parseFloat3(&x, &y, &z, &token); + v.push_back(x); + v.push_back(y); + v.push_back(z); + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + token += 3; + float x, y, z; + parseFloat3(&x, &y, &z, &token); + vn.push_back(x); + vn.push_back(y); + vn.push_back(z); + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + token += 3; + float x, y; + parseFloat2(&x, &y, &token); + vt.push_back(x); + vt.push_back(y); + continue; + } + + // face + if (token[0] == 'f' && IS_SPACE((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + std::vector face; + face.reserve(3); + + while (!IS_NEW_LINE(token[0])) { + vertex_index vi = parseTriple(&token, static_cast(v.size() / 3), + static_cast(vn.size() / 3), + static_cast(vt.size() / 2)); + face.push_back(vi); + size_t n = strspn(token, " \t\r"); + token += n; + } + + // replace with emplace_back + std::move on C++11 + faceGroup.push_back(std::vector()); + faceGroup[faceGroup.size() - 1].swap(face); + + continue; + } + + // use mtl + if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + + int newMaterialId = -1; + if (material_map.find(namebuf) != material_map.end()) { + newMaterialId = material_map[namebuf]; + } else { + // { error!! material not found } + } + + if (newMaterialId != material) { + // Create per-face material. Thus we don't add `shape` to `shapes` at + // this time. + // just clear `faceGroup` after `exportFaceGroupToShape()` call. + exportFaceGroupToShape(&shape, faceGroup, tags, material, name, + triangulate); + faceGroup.clear(); + material = newMaterialId; + } + + continue; + } + + // load mtl + if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + + std::string err_mtl; + bool ok = (*readMatFn)(namebuf, materials, &material_map, &err_mtl); + if (err) { + (*err) += err_mtl; + } + + if (!ok) { + faceGroup.clear(); // for safety + return false; + } + } + + continue; + } + + // group name + if (token[0] == 'g' && IS_SPACE((token[1]))) { + // flush previous face group. + bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, + triangulate); + if (ret) { + shapes->push_back(shape); + } + + shape = shape_t(); + + // material = -1; + faceGroup.clear(); + + std::vector names; + names.reserve(2); + + while (!IS_NEW_LINE(token[0])) { + std::string str = parseString(&token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + assert(names.size() > 0); + + // names[0] must be 'g', so skip the 0th element. + if (names.size() > 1) { + name = names[1]; + } else { + name = ""; + } + + continue; + } + + // object name + if (token[0] == 'o' && IS_SPACE((token[1]))) { + // flush previous face group. + bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, + triangulate); + if (ret) { + shapes->push_back(shape); + } + + // material = -1; + faceGroup.clear(); + shape = shape_t(); + + // @todo { multiple object name? } + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 2; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + name = std::string(namebuf); + + continue; + } + + if (token[0] == 't' && IS_SPACE(token[1])) { + tag_t tag; + + char namebuf[4096]; + token += 2; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + tag.name = std::string(namebuf); + + token += tag.name.size() + 1; + + tag_sizes ts = parseTagTriple(&token); + + tag.intValues.resize(static_cast(ts.num_ints)); + + for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { + tag.intValues[i] = atoi(token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.floatValues.resize(static_cast(ts.num_floats)); + for (size_t i = 0; i < static_cast(ts.num_floats); ++i) { + tag.floatValues[i] = parseFloat(&token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.stringValues.resize(static_cast(ts.num_strings)); + for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { + char stringValueBuffer[4096]; + +#ifdef _MSC_VER + sscanf_s(token, "%s", stringValueBuffer, + (unsigned)_countof(stringValueBuffer)); +#else + sscanf(token, "%s", stringValueBuffer); +#endif + tag.stringValues[i] = stringValueBuffer; + token += tag.stringValues[i].size() + 1; + } + + tags.push_back(tag); + } + + // Ignore unknown command. + } + + bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, + triangulate); + // exportFaceGroupToShape return false when `usemtl` is called in the last + // line. + // we also add `shape` to `shapes` when `shape.mesh` has already some + // faces(indices) + if (ret || shape.mesh.indices.size()) { + shapes->push_back(shape); + } + faceGroup.clear(); // for safety + + if (err) { + (*err) += errss.str(); + } + + attrib->vertices.swap(v); + attrib->normals.swap(vn); + attrib->texcoords.swap(vt); + + return true; +} + +bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback, + void *user_data /*= NULL*/, + MaterialReader *readMatFn /*= NULL*/, + std::string *err /*= NULL*/) { + std::stringstream errss; + + // material + std::map material_map; + int material_id = -1; // -1 = invalid + + std::vector indices; + std::vector materials; + std::vector names; + names.reserve(2); + std::string name; + std::vector names_out; + + std::string linebuf; + while (inStream.peek() != -1) { + safeGetline(inStream, linebuf); + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char *token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // vertex + if (token[0] == 'v' && IS_SPACE((token[1]))) { + token += 2; + float x, y, z, w; // w is optional. default = 1.0 + parseV(&x, &y, &z, &w, &token); + if (callback.vertex_cb) { + callback.vertex_cb(user_data, x, y, z, w); + } + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + token += 3; + float x, y, z; + parseFloat3(&x, &y, &z, &token); + if (callback.normal_cb) { + callback.normal_cb(user_data, x, y, z); + } + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + token += 3; + float x, y, z; // y and z are optional. default = 0.0 + parseFloat3(&x, &y, &z, &token); + if (callback.texcoord_cb) { + callback.texcoord_cb(user_data, x, y, z); + } + continue; + } + + // face + if (token[0] == 'f' && IS_SPACE((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + indices.clear(); + while (!IS_NEW_LINE(token[0])) { + vertex_index vi = parseRawTriple(&token); + + index_t idx; + idx.vertex_index = vi.v_idx; + idx.normal_index = vi.vn_idx; + idx.texcoord_index = vi.vt_idx; + + indices.push_back(idx); + size_t n = strspn(token, " \t\r"); + token += n; + } + + if (callback.index_cb && indices.size() > 0) { + callback.index_cb(user_data, &indices.at(0), + static_cast(indices.size())); + } + + continue; + } + + // use mtl + if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, + static_cast(_countof(namebuf))); +#else + sscanf(token, "%s", namebuf); +#endif + + int newMaterialId = -1; + if (material_map.find(namebuf) != material_map.end()) { + newMaterialId = material_map[namebuf]; + } else { + // { error!! material not found } + } + + if (newMaterialId != material_id) { + material_id = newMaterialId; + } + + if (callback.usemtl_cb) { + callback.usemtl_cb(user_data, namebuf, material_id); + } + + continue; + } + + // load mtl + if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 7; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + + std::string err_mtl; + materials.clear(); + bool ok = (*readMatFn)(namebuf, &materials, &material_map, &err_mtl); + if (err) { + (*err) += err_mtl; + } + + if (!ok) { + return false; + } + + if (callback.mtllib_cb) { + callback.mtllib_cb(user_data, &materials.at(0), + static_cast(materials.size())); + } + } + + continue; + } + + // group name + if (token[0] == 'g' && IS_SPACE((token[1]))) { + names.clear(); + + while (!IS_NEW_LINE(token[0])) { + std::string str = parseString(&token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + assert(names.size() > 0); + + // names[0] must be 'g', so skip the 0th element. + if (names.size() > 1) { + name = names[1]; + } else { + name.clear(); + } + + if (callback.group_cb) { + if (names.size() > 1) { + // create const char* array. + names_out.resize(names.size() - 1); + for (size_t j = 0; j < names_out.size(); j++) { + names_out[j] = names[j + 1].c_str(); + } + callback.group_cb(user_data, &names_out.at(0), + static_cast(names_out.size())); + + } else { + callback.group_cb(user_data, NULL, 0); + } + } + + continue; + } + + // object name + if (token[0] == 'o' && IS_SPACE((token[1]))) { + // @todo { multiple object name? } + char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE]; + token += 2; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + std::string object_name = std::string(namebuf); + + if (callback.object_cb) { + callback.object_cb(user_data, object_name.c_str()); + } + + continue; + } + +#if 0 // @todo + if (token[0] == 't' && IS_SPACE(token[1])) { + tag_t tag; + + char namebuf[4096]; + token += 2; +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + tag.name = std::string(namebuf); + + token += tag.name.size() + 1; + + tag_sizes ts = parseTagTriple(&token); + + tag.intValues.resize(static_cast(ts.num_ints)); + + for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { + tag.intValues[i] = atoi(token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.floatValues.resize(static_cast(ts.num_floats)); + for (size_t i = 0; i < static_cast(ts.num_floats); ++i) { + tag.floatValues[i] = parseFloat(&token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.stringValues.resize(static_cast(ts.num_strings)); + for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { + char stringValueBuffer[4096]; + +#ifdef _MSC_VER + sscanf_s(token, "%s", stringValueBuffer, + (unsigned)_countof(stringValueBuffer)); +#else + sscanf(token, "%s", stringValueBuffer); +#endif + tag.stringValues[i] = stringValueBuffer; + token += tag.stringValues[i].size() + 1; + } + + tags.push_back(tag); + } +#endif + + // Ignore unknown command. + } + + if (err) { + (*err) += errss.str(); + } + + return true; +} +} // namespace tinyobj + +#endif + +#endif // TINY_OBJ_LOADER_H_