From 2744bbbc473ae1df91a582f554ef725dcf662fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Madar=C3=A1sz?= Date: Thu, 29 Aug 2024 17:32:34 +0200 Subject: [PATCH] wip: shadowmaps --- bind/v4k.lua | 94 +- demos/09-envmap.c | 32 +- demos/09-shadows.c | 127 + demos/99-spot.c | 633 +++ demos/art/meshes/ShadowsTest.mtl | 82 + demos/art/meshes/ShadowsTest.obj | 4131 +++++++++++++++++ engine/art/shaderlib/model_fs.glsl | 11 +- engine/art/shaderlib/model_vs.glsl | 16 +- engine/art/shaderlib/shadowmap-old.glsl | 118 + engine/art/shaderlib/shadowmap.glsl | 175 +- engine/art/shaderlib/surface.glsl | 5 +- engine/art/shaders/fs_shadow_vsm.glsl | 17 +- .../shaders/vs_323444143_16_3322_model.glsl | 2 +- engine/art/shaders/vs_shadow_vsm.glsl | 15 - engine/joint/v4k.h | 601 ++- engine/split/v4k_render.c | 386 +- engine/split/v4k_render.h | 83 +- engine/split/v4k_scene.c | 90 - engine/split/v4k_scene.h | 42 - engine/v4k.c | 476 +- engine/v4k.h | 125 +- 21 files changed, 6366 insertions(+), 895 deletions(-) create mode 100644 demos/09-shadows.c create mode 100644 demos/99-spot.c create mode 100644 demos/art/meshes/ShadowsTest.mtl create mode 100644 demos/art/meshes/ShadowsTest.obj create mode 100644 engine/art/shaderlib/shadowmap-old.glsl delete mode 100644 engine/art/shaders/vs_shadow_vsm.glsl diff --git a/bind/v4k.lua b/bind/v4k.lua index d484d2a..3d43bee 100644 --- a/bind/v4k.lua +++ b/bind/v4k.lua @@ -1019,6 +1019,7 @@ typedef struct renderstate_t { unsigned polygon_mode_face; unsigned polygon_mode_draw; bool scissor_test_enabled; + bool seamless_cubemap; } renderstate_t; renderstate_t renderstate(); bool renderstate_compare(const renderstate_t *stateA, const renderstate_t *stateB); @@ -1133,24 +1134,61 @@ typedef struct cubemap_t { void fbo_bind(unsigned id); void fbo_unbind(); void fbo_destroy(unsigned id); +enum { + MAX_LIGHTS = 16, +}; +enum LIGHT_TYPE { + LIGHT_DIRECTIONAL, + LIGHT_POINT, + LIGHT_SPOT, +}; +typedef struct light_t { + char type; + vec3 diffuse, specular, ambient; + vec3 pos, dir; + struct { + float constant, linear, quadratic; + } falloff; + float radius; + float specularPower; + float innerCone, outerCone; + bool cast_shadows; + float shadow_distance; + float shadow_bias; + bool cached; +} light_t; + light_t light(); + void light_type(light_t* l, char type); + void light_diffuse(light_t* l, vec3 color); + void light_specular(light_t* l, vec3 color); + void light_ambient(light_t* l, vec3 color); + void light_teleport(light_t* l, vec3 pos); + void light_dir(light_t* l, vec3 dir); + void light_power(light_t* l, float power); + void light_radius(light_t* l, float radius); + void light_falloff(light_t* l, float constant, float linear, float quadratic); + void light_cone(light_t* l, float innerCone, float outerCone); + void light_update(unsigned num_lights, light_t *lv); typedef struct shadowmap_t { - mat44 shadowmatrix; - mat44 mvp; - mat44 mv; - mat44 proj; - vec4 light_position; - int saved_fb; - int saved_viewport[4]; - handle fbo, texture; + mat44 V; + mat44 PV; int texture_width; + int step; + int light_step; + struct { + handle fbos[6], texture, depth_texture; + } maps[MAX_LIGHTS]; + handle saved_fb; + handle saved_pass; + int saved_vp[4]; } shadowmap_t; shadowmap_t shadowmap(int texture_width); void shadowmap_destroy(shadowmap_t *s); void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection); void shadowmap_begin(shadowmap_t *s); + bool shadowmap_step(shadowmap_t *s); + void shadowmap_light(shadowmap_t *s, light_t *l); void shadowmap_end(shadowmap_t *s); - void shadowmatrix_proj(mat44 shm_proj, float aLightFov, float znear, float zfar); - void shadowmatrix_ortho(mat44 shm_proj, float left, float right, float bottom, float top, float znear, float zfar); unsigned shader(const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines); unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines); unsigned shader_bind(unsigned program); @@ -1400,6 +1438,9 @@ typedef struct model_t { unsigned num_anims; unsigned num_frames; handle program; + handle shadow_program; + shadowmap_t *shadow_map; + bool shadow_receiver; float curframe; mat44 pivot; int stride; @@ -1442,6 +1483,7 @@ enum BILLBOARD_MODE { void model_shading(model_t*, int shading); void model_shading_custom(model_t*, int shading, const char *vs, const char *fs, const char *defines); void model_skybox(model_t*, skybox_t sky, bool load_sh); + void model_shadow(model_t*, shadowmap_t *sm); void model_fog(model_t*, unsigned mode, vec3 color, float start, float end, float density); void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader); void model_render_skeleton(model_t, mat44 model); @@ -1606,38 +1648,6 @@ typedef struct object_t { void object_diffuse_push(object_t *obj, texture_t tex); void object_diffuse_pop(object_t *obj); void object_billboard(object_t *obj, unsigned mode); -enum LIGHT_TYPE { - LIGHT_DIRECTIONAL, - LIGHT_POINT, - LIGHT_SPOT, -}; -enum LIGHT_FLAGS { - LIGHT_CAST_SHADOWS = 1, -}; -typedef struct light_t { - char type; - vec3 diffuse, specular, ambient; - vec3 pos, dir; - struct { - float constant, linear, quadratic; - } falloff; - float radius; - float specularPower; - float innerCone, outerCone; - bool cached; -} light_t; - light_t light(); - void light_type(light_t* l, char type); - void light_diffuse(light_t* l, vec3 color); - void light_specular(light_t* l, vec3 color); - void light_ambient(light_t* l, vec3 color); - void light_teleport(light_t* l, vec3 pos); - void light_dir(light_t* l, vec3 dir); - void light_power(light_t* l, float power); - void light_radius(light_t* l, float radius); - void light_falloff(light_t* l, float constant, float linear, float quadratic); - void light_cone(light_t* l, float innerCone, float outerCone); - void light_update(unsigned num_lights, light_t *lv); enum SCENE_FLAGS { SCENE_WIREFRAME = 1, SCENE_CULLFACE = 2, diff --git a/demos/09-envmap.c b/demos/09-envmap.c index 41d127b..ba0c7f2 100644 --- a/demos/09-envmap.c +++ b/demos/09-envmap.c @@ -18,6 +18,7 @@ const char *OBJ_MDLS[] = { int main(int argc, char** argv) { window_create(85, WINDOW_MSAA8); + window_fps_unlock(); camera_t cam = camera(); { cam.position = vec3(0, 7.5, 15); @@ -63,8 +64,9 @@ int main(int argc, char** argv) { camera_fps(&cam, mouse.x,mouse.y); static bool first_time = true; - static bool animate_probe_pos = false; + static bool animate_probe_pos = true; static bool follow_cam = false; + static bool show_env_probe = false; static vec3 probe_pos; if (input_down(KEY_T)) { animate_probe_pos = !animate_probe_pos; @@ -72,9 +74,13 @@ int main(int argc, char** argv) { if (input_down(KEY_F)) { follow_cam = !follow_cam; } + if (input_down(KEY_P)) { + show_env_probe = !show_env_probe; + } if (animate_probe_pos) { - probe_pos = vec3(0, 5, 0); - probe_pos.x = sinf(window_time()*2)*2.0f; + probe_pos = vec3(0, 5.5, 1); + probe_pos.x = sinf(window_time()*2)*3.9f; + probe_pos.y += cosf(window_time()*2)*1.0; } if (input_down(KEY_SPACE) || first_time || animate_probe_pos || follow_cam) { first_time = false; @@ -85,7 +91,7 @@ int main(int argc, char** argv) { if (follow_cam) { probe_pos = cam.position; } - unsigned tex_size = 256; + unsigned tex_size = 64; cubemap_bake_begin(&env_probe.cubemap, probe_pos, tex_size, tex_size); while (cubemap_bake_step(&env_probe.cubemap, probe_proj, probe_view)) { skybox_render(&sky, probe_proj, probe_view); @@ -102,14 +108,16 @@ int main(int argc, char** argv) { // render mat44 mvp; multiply44x2(mvp, cam.proj, cam.view); { - // skybox_render(&env_probe, cam.proj, cam.view); - skybox_render(&sky, cam.proj, cam.view); + if (show_env_probe) { + skybox_render(&env_probe, cam.proj, cam.view); + } else { + skybox_render(&sky, cam.proj, cam.view); + shader_bind(mdl.program); + cubemap_sh_blend(vec3(0,0,0), 10.0f, 1, &env_probe.cubemap); + shader_int("u_textured", false); - shader_bind(mdl.program); - cubemap_sh_blend(vec3(0,0,0), 10.0f, 1, &env_probe.cubemap); - shader_int("u_textured", false); - - model_render(mdl, cam.proj, cam.view, mdl.pivot, 0); + model_render(mdl, cam.proj, cam.view, mdl.pivot, 0); + } } if( ui_panel("Scene", 0)) { @@ -121,7 +129,7 @@ int main(int argc, char** argv) { } ui_separator(); for (int i = 0; i < 9; i++) { - ui_color3f(va("SH Coefficient [%d]", i), &sky.cubemap.sh[i].x); + ui_color3f(va("SH Coefficient [%d]", i), &env_probe.cubemap.sh[i].x); } ui_panel_end(); } diff --git a/demos/09-shadows.c b/demos/09-shadows.c new file mode 100644 index 0000000..1279ad2 --- /dev/null +++ b/demos/09-shadows.c @@ -0,0 +1,127 @@ +#include "v4k.h" + +int SKY_DIR = 0; +const char *SKY_DIRS[] = { + "cubemaps/bridge3/", + "cubemaps/colors/", + "cubemaps/colors2/", + "hdr/Tokyo_BigSight_1k.hdr", +}; + +int OBJ_MDL = 0; +const char *OBJ_MDLS[] = { + "meshes/ShadowsTest.obj", + "meshes/sphere.obj", + "meshes/suzanne.obj", + "meshes/gazebo.obj", +}; + +int main(int argc, char** argv) { + window_create(85, WINDOW_MSAA8); + // window_fps_unlock(); + + camera_t cam = camera(); { + cam.position = vec3(0, 7.5, 15); + cam.pitch = -15; + cam.yaw = -90; + camera_fps(&cam, 0, 0); + } + skybox_t sky = {0}; + model_t mdl = {0}; + shadowmap_t sm = {0}; + light_t lit = light(); { + lit.type = LIGHT_POINT; + lit.cast_shadows = true; + // lit.shadow_distance = 3.0f; + } + light_t lit2 = light(); { + lit2.type = LIGHT_POINT; + lit2.cast_shadows = true; + lit2.diffuse = vec3(1, 0.7, 0.8); + } + + array(light_t) lights = 0; + array_push(lights, lit); + array_push(lights, lit2); + + bool initialized = 0; + bool must_reload = 0; + + while( window_swap()) { + if (input_down(KEY_ESC)) break; + // reloading + if( must_reload ) { + must_reload = 0; + skybox_destroy(&sky); + model_destroy(mdl); + initialized = 0; + } + if( !initialized ) { + initialized = 1; + sky = skybox(flag("--mie") ? 0 : SKY_DIRS[SKY_DIR], 0); + sm = shadowmap(1024); + mdl = model(OBJ_MDLS[OBJ_MDL], 0); + shader_bind(mdl.program); + cubemap_sh_shader(&sky.cubemap); + } + + // fps camera + bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R); + window_cursor( !active ); + + if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f); + vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active); + vec3 wasdec = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-input(KEY_C),input(KEY_W)-input(KEY_S)), cam.speed); + camera_moveby(&cam, wasdec); + camera_fps(&cam, mouse.x,mouse.y); + + // Animate light + lights[0].pos = vec3(0, 5.5, 1); + lights[0].pos.x += sinf(window_time()*2)*4.5f; + lights[0].pos.y += cosf(window_time()*2)*1.0; + lights[0].pos.z += cosf(window_time()*2)*6.0; + + lights[1].pos = vec3(0, 7.5, 1); + lights[1].pos.x += sinf(window_time()*4)*4.5f; + lights[1].pos.y += cosf(window_time()*4)*1.0; + lights[1].pos.z += cosf(window_time()*4)*6.0; + + // Render shadowmap + shadowmap_begin(&sm); + { + for (int i = 0; i < array_count(lights); i++) { + while (shadowmap_step(&sm)) { + shadowmap_light(&sm, &lights[i]); + model_render(mdl, cam.proj, cam.view, mdl.pivot, 0); + } + } + } + shadowmap_end(&sm); + + // render + mat44 mvp; multiply44x2(mvp, cam.proj, cam.view); + { + skybox_render(&sky, cam.proj, cam.view); + shader_bind(mdl.program); + shader_int("u_textured", false); + light_update(array_count(lights), lights); + + ddraw_sphere(lights[0].pos, 0.1f); + ddraw_sphere(lights[1].pos, 0.1f); + ddraw_flush(); + + model_shadow(&mdl, &sm); + model_render(mdl, cam.proj, cam.view, mdl.pivot, 0); + } + + if( ui_panel("Scene", 0)) { + if( ui_list("Skybox", SKY_DIRS, countof(SKY_DIRS), &SKY_DIR) ) { + must_reload = 1; + } + if( ui_list("Model", OBJ_MDLS, countof(OBJ_MDLS), &OBJ_MDL) ) { + must_reload = 1; + } + ui_panel_end(); + } + } +} diff --git a/demos/99-spot.c b/demos/99-spot.c new file mode 100644 index 0000000..2544aef --- /dev/null +++ b/demos/99-spot.c @@ -0,0 +1,633 @@ +// [ref] http://fabiensanglard.net/shadowmappingVSM/index.php +// [ref] http://www.opengl-tutorial.org/es/intermediate-tutorials/tutorial-16-shadow-mapping/ +// [ref] https://github.com/cforfang/opengl-shadowmapping +// [ref] https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping + +// @todo: spotlight (cone light) +// @todo: pointlight (cubemap light) +// @todo: area light (rect or circle light) +// @todo: directional light (sunlight) + +// further reading (in order): +// DPSM [3] Brabec, Annen: Shadow mapping for hemispherical and omnidirectional light sources (2002) +// DPSM* [4] Osman, Bukowski: Practical implementation of dual paraboloid shadow maps (2006) +// IPSM [5] Vanek, Herout: High-quality Shadows with Improved Paraboloid Mapping (2011) +// LiSPSMs +// CSMs + +// status: CUBE(0)+BLUR(0): ok +// status: CUBE(0)+BLUR(1): ok +// status: CUBE(1)+BLUR(1): ok +// status: CUBE(1)+BLUR(0): ok +// status: CUBE(?)+BLUR(?): no { +// 003.470s|!cannot find uniform 'shadowMap' in shader program 21 |shader_uniform|fwk_render.c:772 +// 001: 00007FF7AF6A3FDA callstack (C:\prj\thread\FWK\fwk_system.c:250) +// 002: 00007FF7AF8E7CBC shader_uniform (C:\prj\thread\FWK\fwk_render.c:772) +// 003: 00007FF7AF691C27 shader_int (C:\prj\thread\FWK\fwk_render.c:777) +// 004: 00007FF7AF8F54EF color_begin (C:\prj\thread\FWK\spot.c:525) +// 005: 00007FF7AF8F5BF7 main (C:\prj\thread\FWK\spot.c:607) +// } + +#ifndef VSMCUBE +#define VSMCUBE 0 +#endif +#ifndef VSMBLUR +#define VSMBLUR 1 +#endif + +#include "v4k.h" + +model_t sponza; + +typedef struct Mesh +{ + GLuint vao; + GLuint vbo; +} Mesh; + +static float quadVertices[] = { + // Front-face + // Pos // Color //Tex // Norm + -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top-left + 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top-right + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // Bottom-right + + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // Bottom-right + -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, //Bottom-left + -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top-left +}; + +static Mesh create_mesh(float* verts, int size) { + Mesh mesh; + + // Create VAO + glGenVertexArrays(1, &mesh.vao); + glBindVertexArray(mesh.vao); + + // Create VBO and copy the vertex data to it + glGenBuffers(1, &mesh.vbo); + glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo); + glBufferData(GL_ARRAY_BUFFER, size, verts, GL_STATIC_DRAW); + + // Enable attribs + // Position + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 0); + // Color + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(3 * sizeof(float))); + // Texcoords + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(6 * sizeof(float))); + // Normal + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(8 * sizeof(float))); + + return mesh; +} + +Mesh create_quad() { + return create_mesh(quadVertices, sizeof(quadVertices)); +} + + + + +/* +#define Mesh model_t +model_t create_cube() { + model_t m = model("#meshes/cube.obj", 0); //MESH_TRIANGLE_STRIP); + return m; +} +*/ +static const char* const vs_shadow_blur = "//" FILELINE "\n" + "in vec3 position;\n" + "in vec2 texcoord;\n" + "out vec2 Texcoord;\n" + + "void main() {\n" + " gl_Position = vec4(position, 1.0);\n" + " Texcoord = texcoord;\n" + "}\n"; + +static const char* const fs_shadow_blur = "//" FILELINE "\n" + "uniform sampler2D textureSource;\n" + "uniform vec2 ScaleU;\n" + + "in vec2 Texcoord;\n" + "out vec4 outColor;\n" + + "void main() {\n" + " vec4 color = vec4(0.0);\n" + " color += texture( textureSource, Texcoord.st + vec2( -3.0*ScaleU.x, -3.0*ScaleU.y ) ) * 0.015625;\n" + " color += texture( textureSource, Texcoord.st + vec2( -2.0*ScaleU.x, -2.0*ScaleU.y ) )*0.09375;\n" + " color += texture( textureSource, Texcoord.st + vec2( -1.0*ScaleU.x, -1.0*ScaleU.y ) )*0.234375;\n" + " color += texture( textureSource, Texcoord.st + vec2( 0.0 , 0.0) )*0.3125;\n" + " color += texture( textureSource, Texcoord.st + vec2( 1.0*ScaleU.x, 1.0*ScaleU.y ) )*0.234375;\n" + " color += texture( textureSource, Texcoord.st + vec2( 2.0*ScaleU.x, 2.0*ScaleU.y ) )*0.09375;\n" + " color += texture( textureSource, Texcoord.st + vec2( 3.0*ScaleU.x, -3.0*ScaleU.y ) ) * 0.015625;\n" + " outColor = vec4(color.xyz, 1.0);\n" + "}\n"; + + + +static const char* const vs_shadow_vsm = "//" FILELINE "\n" + "uniform mat4 model;\n" + "uniform mat4 cameraToShadowView;\n" + "uniform mat4 cameraToShadowProjector;\n" + + "in vec3 position;\n" + "out vec4 v_position;\n" + + "void main() {\n" + " gl_Position = cameraToShadowProjector * model * vec4(position, 1.0);\n" +#if VSMCUBE + " v_position = cameraToShadowView * model * vec4(position, 1.0);\n" +#else + " v_position = gl_Position;\n" +#endif + "}\n"; + +static const char* const fs_shadow_vsm = "//" FILELINE "\n" + "in vec4 v_position;\n" + "out vec4 outColor;\n" + + "void main() {\n" +#if VSMCUBE + " float depth = length( vec3(v_position) ) / 20;\n" +#else + " float depth = v_position.z / v_position.w;\n" + " depth = depth * 0.5 + 0.5;\n" +#endif + + " float moment1 = depth;\n" + " float moment2 = depth * depth;\n" + + " float dx = dFdx(depth);\n" + " float dy = dFdy(depth);\n" + " moment2 += 0.25*(dx*dx+dy*dy);\n" + " outColor = vec4( moment1, moment2, 0.0, 0.0);\n" + "}\n"; + + +struct shadow { + // Resources + GLuint shadowProgram, blurProgram; + Mesh quadMesh; + GLuint shadowMapFBO, shadowMapTex, shadowMapTexDepth; + GLuint blurFBO, blurTex; + // Options + bool do_blur; + bool do_debugshadow; + float BLUR_SCALE; // Amount of blurring [0..100] + GLuint SHADOWMAP_WIDTH; // 256,512,1024,2048 + // State + int shadow_active; + vec3 lightPos; + vec3 lightAimPos; + + // VSM cubemap + GLuint cubeTex, cubeDepthTex, cubeFBOs[6]; + GLuint currentSideTex, currentSideDepthTex; + GLuint toCurrentSideFBO; +} shadow; + +#define shadowProgram shadow.shadowProgram +#define blurProgram shadow.blurProgram +#define quadMesh shadow.quadMesh +#define shadowMapFBO shadow.shadowMapFBO +#define shadowMapTex shadow.shadowMapTex +#define shadowMapTexDepth shadow.shadowMapTexDepth +#define blurFBO shadow.blurFBO +#define blurTex shadow.blurTex +#define do_blur shadow.do_blur +#define do_debugshadow shadow.do_debugshadow +#define BLUR_SCALE shadow.BLUR_SCALE +#define SHADOWMAP_WIDTH shadow.SHADOWMAP_WIDTH +#define shadow_active shadow.shadow_active +#define lightPos shadow.lightPos +#define lightAimPos shadow.lightAimPos +// vsm cubemap +#define cubeTex shadow.cubeTex +#define cubeDepthTex shadow.cubeDepthTex +#define cubeFBOs shadow.cubeFBOs +#define currentSideTex shadow.currentSideTex +#define currentSideDepthTex shadow.currentSideDepthTex +#define toCurrentSideFBO shadow.toCurrentSideFBO + + + +static GLuint cubemap_create(GLsizei size, int flags) { + GLenum texel = flags & TEXTURE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGB32F; + GLenum pixel = flags & TEXTURE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGB; + GLenum storage = flags & TEXTURE_DEPTH ? GL_FLOAT : GL_UNSIGNED_BYTE; // swap? + GLuint id; + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_CUBE_MAP, id); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, texel, size, size, 0, pixel, storage, NULL); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, texel, size, size, 0, pixel, storage, NULL); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, texel, size, size, 0, pixel, storage, NULL); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, texel, size, size, 0, pixel, storage, NULL); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, texel, size, size, 0, pixel, storage, NULL); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, texel, size, size, 0, pixel, storage, NULL); + if( flags & TEXTURE_DEPTH ) { + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + } else { + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + return id; +} +static void framebuffer_cube_create(GLuint cube_fbo[6], GLuint cube_texture, GLuint cube_texture_depth) { + glGenFramebuffers(6, cube_fbo); + for (int i = 0; i < 6; i++) { + glBindFramebuffer(GL_FRAMEBUFFER, cube_fbo[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cube_texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cube_texture_depth, 0); + GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (GL_FRAMEBUFFER_COMPLETE != result) { + printf("ERROR: Framebuffer is not complete.\n"); + } + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} +static void set_shadow_matrix_uniform(const GLuint program, int dir) { + if(dir<0) return; + mat44 P, V, PV; + perspective44(P, 90.0f, 1.0f, 0.5f, 100.0f); + + /**/ if(dir == 0) lookat44(V, lightPos, add3(lightPos, vec3(+1, 0, 0)), vec3(0, -1, 0)); // +X + else if(dir == 1) lookat44(V, lightPos, add3(lightPos, vec3(-1, 0, 0)), vec3(0, -1, 0)); // -X + else if(dir == 2) lookat44(V, lightPos, add3(lightPos, vec3( 0, +1, 0)), vec3(0, 0, +1)); // +Y + else if(dir == 3) lookat44(V, lightPos, add3(lightPos, vec3( 0, -1, 0)), vec3(0, 0, -1)); // -Y + else if(dir == 4) lookat44(V, lightPos, add3(lightPos, vec3( 0, 0, +1)), vec3(0, -1, 0)); // +Z + else /*dir == 5*/ lookat44(V, lightPos, add3(lightPos, vec3( 0, 0, -1)), vec3(0, -1, 0)); // -Z + multiply44x2(PV, P, V); // -Z + + shader_bind(program); shader_mat44("cameraToShadowView", V); + shader_bind(program); shader_mat44("cameraToShadowProjector", PV); +} + +void shadow_create(int RESOLUTION) { + do_blur = 1; + do_debugshadow = 0; + BLUR_SCALE = 0.5; // Amount of blurring [0..1] + SHADOWMAP_WIDTH = RESOLUTION; // 256,512,1024,2048 + lightPos = vec3(-2, 2.0, -2); + lightAimPos = vec3(0.0, 0, -5.0); + + // Create programs + shadowProgram = shader(vs_shadow_vsm, fs_shadow_vsm, "position", "outColor", 0); + blurProgram = shader(vs_shadow_blur, fs_shadow_blur, "position,,texcoord", "outColor", 0); + + // ShadowMap-textures and FBO // @todo: GL_RG32F+GL_RG also GL_CLAMP to remove artifacts + shadowMapTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 2, NULL, TEXTURE_FLOAT).id; + shadowMapTexDepth = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 0, NULL, TEXTURE_DEPTH | TEXTURE_FLOAT).id; + shadowMapFBO = fbo(shadowMapTex, shadowMapTexDepth, 0); + + // Textures and FBO to perform blurring + blurTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 2, NULL, TEXTURE_FLOAT).id; + blurFBO = fbo(blurTex, 0, 0); + +#if VSMCUBE + // Create cubemap + cubeTex = cubemap_create(SHADOWMAP_WIDTH, 0); + cubeDepthTex = cubemap_create(SHADOWMAP_WIDTH, TEXTURE_DEPTH); + framebuffer_cube_create(cubeFBOs, cubeTex, cubeDepthTex); + // Temporary storage + currentSideTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 2, NULL, TEXTURE_FLOAT /*| TEXTURE_EDGE*/ ).id; + currentSideDepthTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 0, NULL, TEXTURE_DEPTH | TEXTURE_FLOAT).id; + toCurrentSideFBO = fbo(currentSideTex, currentSideDepthTex, 0); +#endif +} +void shadow_destroy() { + glDeleteProgram(shadowProgram); + glDeleteProgram(blurProgram); + + glDeleteTextures(1, &blurTex); + glDeleteFramebuffers(1, &blurFBO); + + glDeleteTextures(1, &shadowMapTex); + glDeleteTextures(1, &shadowMapTexDepth); + glDeleteFramebuffers(1, &shadowMapFBO); +} +bool shadow_is_active() { + return shadow_active; +} +void shadow_pv_matrix(mat44 PV) { + mat44 P,V; +// perspective44(P, 45.0f, 1.0f, 2.0f, 100.0f); +perspective44(P, 45*2, window_width() / ((float)window_height()+!window_height()), 1.f, 100.f); + + lookat44(V, lightPos, lightAimPos, vec3(0, 1, 0)); // Point toward object regardless of position + multiply44x2(PV, P, V); +} +void shadow_position(vec3 p) { + lightPos = p; +} +void shadow_target(vec3 p) { + lightAimPos = p; +} +void shadow_begin() { + shadow_active = 1; + + // shadow_state() { + glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); + glEnable(GL_CULL_FACE); glCullFace(GL_BACK); + glFrontFace(GL_CW); + glBlendFunc(1, 0); +#if VSMCUBE + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); +#endif + // } + + glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFBO); + + glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH); + //glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + mat44 PV; shadow_pv_matrix(PV); + shader_bind(shadowProgram);shader_mat44("cameraToShadowProjector", PV); +} +static void draw_fullscreen_quad() { + //delete_mesh(quadMesh); + if(!quadMesh.vao) quadMesh = create_quad(); + + glBindVertexArray(quadMesh.vao); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); +} +static void shadow_blur() { + // remap 0(min)..1(max) -> 2(min)..epsilon(max) + float blur_scale = 1.999 * (1 - BLUR_SCALE) + 0.001; + + glDisable(GL_DEPTH_TEST); + + // Blur shadowMapTex (horizontally) to blurTex + glBindFramebuffer(GL_FRAMEBUFFER, blurFBO); + glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, shadowMapTex); //Input-texture + shader_bind(blurProgram); shader_vec2("ScaleU", vec2(1.0 / (SHADOWMAP_WIDTH*blur_scale), 0)); + shader_int("textureSource",0); +// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + draw_fullscreen_quad(); + + // Blur blurTex vertically and write to shadowMapTex + glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFBO); + glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, blurTex); + shader_bind(blurProgram); shader_vec2("ScaleU", vec2(0, 1.0 / (SHADOWMAP_WIDTH*blur_scale))); + shader_int("textureSource",0); +// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + draw_fullscreen_quad(); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + glEnable(GL_DEPTH_TEST); +} +void shadow_end() { + // Reset + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + + if(do_blur) shadow_blur(); + shadow_active = 0; + + glViewport(0, 0, window_width(), window_height()); +} +void shadow_ui() { + // UI + if( ui_panel("Shadow", 0) ) { + if(ui_toggle("Debug", &do_debugshadow)) {} + if(ui_toggle("Blur shadow", &do_blur)) {} + if(ui_slider("Blur amount", &BLUR_SCALE)) {} + ui_panel_end(); + } + + if(do_debugshadow) { + // Blur and draw to screen + shader_bind(blurProgram); shader_vec2("ScaleU", vec2(0, 0)); // ... but make sure we don't actually blur + glBindTexture(GL_TEXTURE_2D, shadowMapTex); + draw_fullscreen_quad(); + glBindTexture(GL_TEXTURE_2D, 0); + } +} + +#define USER_DRAWCALL(shader) do { \ + model_render(sponza, camera_get_active()->proj, camera_get_active()->view, sponza.pivot, shader); \ +} while(0) + + +static void vsm_cube_draw() +{ + glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH); + + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + shader_bind(shadowProgram); + + // For each side of cubemap + for (int i = 0; i < 6; ++i) { +#if VSMBLUR + // Draw to temp. storage + shader_bind(shadowProgram); + glBindFramebuffer(GL_FRAMEBUFFER, toCurrentSideFBO); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + set_shadow_matrix_uniform(shadowProgram, i); + USER_DRAWCALL(shadowProgram); + + // Blur horizontally to blurTex + glDisable(GL_DEPTH_TEST); + + shader_bind(blurProgram); + shader_vec2("ScaleU", vec2(1.0 / SHADOWMAP_WIDTH, 0)); + + glBindFramebuffer(GL_FRAMEBUFFER, blurFBO); + glBindTexture(GL_TEXTURE_2D, currentSideTex); + glClear(GL_COLOR_BUFFER_BIT); + draw_fullscreen_quad(); + + // Blur vertically to actual cubemap + glBindFramebuffer(GL_FRAMEBUFFER, cubeFBOs[i]); + + glBindTexture(GL_TEXTURE_2D, blurTex); + shader_bind(blurProgram); + shader_vec2("ScaleU", vec2(0, 1.0 / SHADOWMAP_WIDTH)); + + draw_fullscreen_quad(); + + glEnable(GL_DEPTH_TEST); +#else + // Draw directly to cubemap + glBindFramebuffer(GL_FRAMEBUFFER, cubeFBOs[i]); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + set_shadow_matrix_uniform(shadowProgram, i); + USER_DRAWCALL(shadowProgram); +#endif + } + + // Reset state + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); +} + +#undef shadowProgram +#undef blurProgram +#undef quadMesh +#undef shadowMapFBO +#undef shadowMapTex +#undef shadowMapTexDepth +#undef blurFBO +#undef blurTex +#undef do_blur +#undef do_debugshadow +#undef BLUR_SCALE +#undef SHADOWMAP_WIDTH +#undef shadow_active +#undef lightPos +#undef lightAimPos + + + + + +// Geometry (world coordinates) +static bool do_animate = 1; + +static void color_begin(const GLuint program) { + glCullFace(GL_BACK); + +#if 1 // VSMCUBE +glViewport(0, 0, window_width(), window_height()); +glClearColor(0.5f, 0.5f, 0.5f, 1.0f); +glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +#endif + + // Upload uniforms + shader_bind(program); + shader_mat44("view", camera_get_active()->view); +// shader_mat44("proj", camera_get_active()->proj); + shader_vec3("lightPos", shadow.lightPos); + +#if VSMCUBE + set_shadow_matrix_uniform(program, -1); +#else + mat44 PV; shadow_pv_matrix(PV); + shader_mat44("cameraToShadowProjector", PV); +#endif + + glActiveTexture(GL_TEXTURE0+1); +#if VSMCUBE + glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTex); +#else + glBindTexture(GL_TEXTURE_2D, shadow.shadowMapTex); //Input-texture +#endif + shader_int("shadowMap",1); +} +static void color_end() { +#if VSMCUBE + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +#else + glBindTexture(GL_TEXTURE_2D, 0); +#endif +} + + +int main(int argc, char **argv) +{ + window_create(0.75f, 0); + + camera_t cam = camera(); + + // init shadowing 384x384 // 512x512 + shadow_create(argc > 1 ? atoi(argv[1]) : 384); + + sponza = model("sponza.obj", 0); + translation44(sponza.pivot, 0,-1,0); + rotate44(sponza.pivot, -90,1,0,0); + scale44(sponza.pivot, 10,10,10); + + model_t suzanne = model("suzanne.obj", 0); + + // create geometry + GLuint vsm_program = sponza.iqm->program; + #if 1 + const char *tpl[] = { + "{{include-shadowmap}}", fs_0_0_shadowmap_lit, + }; + vsm_program = shader(strlerp(1,tpl,vs_323444143_16_332_model), strlerp(1,tpl,fs_32_4_model), "att_position,att_texcoord,att_normal", "fragColor"); + #endif + + while (window_swap()) + { + // input + if (input(KEY_ESC)) + break; + + // fps camera + bool active = ui_active() ? 0 : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R); + vec3 wasdec = scale3( vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-input(KEY_C),input(KEY_W)-input(KEY_S)), 0.2f); + vec2 mouse = scale2( vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active); + camera_move(&cam, wasdec.x,wasdec.y,wasdec.z); + camera_fps(&cam, mouse.x,mouse.y); + window_cursor( !active ); + +#if 1 + // animate light + if( do_animate ) { + static vec3 lightPos; + do_once { + lightPos = cam.position; + }; + vec3 offs = vec3(sin(window_time()) * 15, 0, cos(window_time()) * 15); + shadow_position(add3(lightPos, offs)); +// shadow_target(vec3(0,0,0)); // good for pointlight + shadow_target(add3(add3(lightPos, offs), vec3(0,0,-1))); + } +#else + shadow_position(cam.position); + shadow_target(add3(cam.position, cam.look)); +#endif + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // render + +#if VSMCUBE + shadow_begin(); + vsm_cube_draw(); + shadow_end(); +#else + shadow_begin(); + model_render(sponza, camera_get_active()->proj, camera_get_active()->view, sponza.pivot, shadow.shadowProgram); //< typo!, but works! + shadow_end(); +#endif + + color_begin(vsm_program); + model_render(sponza, camera_get_active()->proj, camera_get_active()->view, sponza.pivot, vsm_program); // does not work without program + color_end(); + + + // light bulb (suzanne) + { + mat44 M; scaling44(M, 10,10,10); relocate44(M, shadow.lightPos.x, shadow.lightPos.y, shadow.lightPos.z ); + model_render(suzanne, camera_get_active()->proj, camera_get_active()->view, M, 0); + } + + + if( ui_panel("App", 0) ) { + if(ui_toggle("Animate light", &do_animate)) {} + ui_panel_end(); + } + + shadow_ui(); + } +} diff --git a/demos/art/meshes/ShadowsTest.mtl b/demos/art/meshes/ShadowsTest.mtl new file mode 100644 index 0000000..e995d13 --- /dev/null +++ b/demos/art/meshes/ShadowsTest.mtl @@ -0,0 +1,82 @@ +# Blender 4.2.1 LTS MTL File: 'None' +# www.blender.org + +newmtl backWall +Ns 10.000005 +Ka 1.000000 1.000000 1.000000 +Kd 0.725000 0.710000 0.680000 +Ks 0.000000 0.000000 0.000000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 1 + +newmtl ceiling +Ns 10.000005 +Ka 1.000000 1.000000 1.000000 +Kd 0.725000 0.710000 0.680000 +Ks 0.000000 0.000000 0.000000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 1 + +newmtl floor +Ns 10.000005 +Ka 1.000000 1.000000 1.000000 +Kd 0.725000 0.710000 0.680000 +Ks 0.000000 0.000000 0.000000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 1 + +newmtl leftWall +Ns 10.000005 +Ka 1.000000 1.000000 1.000000 +Kd 0.630000 0.065000 0.050000 +Ks 0.000000 0.000000 0.000000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 1 + +newmtl light +Ns 10.000005 +Ka 1.000000 1.000000 1.000000 +Kd 0.780000 0.780000 0.780000 +Ks 0.000000 0.000000 0.000000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 1 + +newmtl rightWall +Ns 10.000005 +Ka 1.000000 1.000000 1.000000 +Kd 0.140000 0.450000 0.091000 +Ks 0.000000 0.000000 0.000000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 1 + +newmtl shortBox +Ns 10.000005 +Ka 1.000000 1.000000 1.000000 +Kd 0.725000 0.710000 0.680000 +Ks 0.000000 0.000000 0.000000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 1 + +newmtl tallBox +Ns 10.000005 +Ka 1.000000 1.000000 1.000000 +Kd 0.725000 0.710000 0.680000 +Ks 0.000000 0.000000 0.000000 +Ke 0.000000 0.000000 0.000000 +Ni 1.000000 +d 1.000000 +illum 1 diff --git a/demos/art/meshes/ShadowsTest.obj b/demos/art/meshes/ShadowsTest.obj new file mode 100644 index 0000000..7e31703 --- /dev/null +++ b/demos/art/meshes/ShadowsTest.obj @@ -0,0 +1,4131 @@ +# Blender 4.2.1 LTS +# www.blender.org +mtllib ShadowsTest.mtl +o CornellBox-Original +v -20.200003 20.199995 -0.000000 +v 19.999998 20.199999 -0.000000 +v 20.000002 -20.399998 0.000000 +v -19.799997 -20.400002 0.000000 +v 2.120000 3.000000 -2.400000 +v 2.800000 0.680000 -2.400000 +v 0.520000 -0.000000 -2.400000 +v -0.200000 2.280000 -2.400000 +v -0.200000 2.280000 -0.000000 +v -0.200000 2.280000 -2.400000 +v 0.520000 -0.000000 -2.400000 +v 0.520000 0.000000 0.000000 +v 2.120000 3.000000 -0.000000 +v 2.120000 3.000000 -2.400000 +v -0.200000 2.280000 -2.400000 +v -0.200000 2.280000 -0.000000 +v 2.800000 0.680000 -0.000000 +v 2.800000 0.680000 -2.400000 +v 2.120000 3.000000 -2.400000 +v 2.120000 3.000000 -0.000000 +v 0.520000 0.000000 0.000000 +v 0.520000 -0.000000 -2.400000 +v 2.800000 0.680000 -2.400000 +v 2.800000 0.680000 -0.000000 +v -2.120000 0.359999 -8.800000 +v 0.160000 -0.360000 -8.800000 +v -0.560000 -2.680001 -8.800000 +v -2.840000 -1.960001 -8.800000 +v -2.120000 0.360000 -0.000000 +v -2.120000 0.359999 -8.800000 +v -2.840000 -1.960001 -8.800000 +v -2.840000 -1.960000 0.000000 +v -2.840000 -1.960000 0.000000 +v -2.840000 -1.960001 -8.800000 +v -0.560000 -2.680001 -8.800000 +v -0.560000 -2.680000 0.000000 +v -0.560000 -2.680000 0.000000 +v -0.560000 -2.680001 -8.800000 +v 0.160000 -0.360000 -8.800000 +v 0.160000 -0.360000 0.000000 +v 0.160000 -0.360000 0.000000 +v 0.160000 -0.360000 -8.800000 +v -2.120000 0.359999 -8.800000 +v -2.120000 0.360000 -0.000000 +v 1.940454 1.700058 -4.305698 +v 2.216353 1.700058 -4.029799 +v 2.365669 1.700058 -3.669319 +v 2.384884 1.700058 -3.474229 +v 2.365669 1.700058 -3.279139 +v 2.216353 1.700058 -2.918658 +v 1.576226 1.738119 -4.455014 +v 1.760214 1.774716 -4.398108 +v 1.929779 1.808445 -4.305698 +v 2.078404 1.838008 -4.181335 +v 2.200377 1.862270 -4.029799 +v 2.291011 1.880298 -3.856912 +v 2.346823 1.891400 -3.669319 +v 2.365669 1.895149 -3.474229 +v 2.346823 1.891400 -3.279139 +v 2.291011 1.880298 -3.091545 +v 2.200377 1.862270 -2.918658 +v 2.078404 1.838008 -2.767122 +v 1.929779 1.808445 -2.642759 +v 1.760214 1.774716 -2.550349 +v 1.576226 1.738119 -2.493444 +v 1.565124 1.774716 -4.455014 +v 1.738437 1.846505 -4.398108 +v 1.898164 1.912666 -4.305698 +v 2.038165 1.970656 -4.181335 +v 2.153061 2.018248 -4.029799 +v 2.238437 2.053612 -3.856912 +v 2.291011 2.075389 -3.669319 +v 2.308763 2.082742 -3.474229 +v 2.291011 2.075389 -3.279139 +v 2.238437 2.053612 -3.091545 +v 2.153061 2.018248 -2.918658 +v 2.038165 1.970656 -2.767122 +v 1.898164 1.912666 -2.642759 +v 1.738437 1.846505 -2.550349 +v 1.565124 1.774716 -2.493444 +v 1.547096 1.808445 -4.455014 +v 1.703074 1.912666 -4.398108 +v 1.846824 2.008717 -4.305698 +v 1.972822 2.092906 -4.181335 +v 2.076226 2.161998 -4.029799 +v 2.153062 2.213338 -3.856912 +v 2.200377 2.244954 -3.669319 +v 2.216353 2.255629 -3.474229 +v 2.200377 2.244954 -3.279139 +v 2.153062 2.213338 -3.091545 +v 2.076226 2.161998 -2.918658 +v 1.972822 2.092906 -2.767122 +v 1.846824 2.008717 -2.642759 +v 1.703074 1.912666 -2.550349 +v 1.547096 1.808445 -2.493444 +v 1.522834 1.838008 -4.455014 +v 1.655482 1.970656 -4.398108 +v 1.777731 2.092906 -4.305698 +v 1.884884 2.200058 -4.181335 +v 1.972822 2.287996 -4.029799 +v 2.038165 2.353339 -3.856912 +v 2.078404 2.393578 -3.669319 +v 2.091990 2.407165 -3.474229 +v 2.078404 2.393578 -3.279139 +v 2.038165 2.353340 -3.091545 +v 1.972822 2.287996 -2.918658 +v 1.884884 2.200058 -2.767122 +v 1.777731 2.092906 -2.642759 +v 1.655482 1.970656 -2.550349 +v 1.522834 1.838008 -2.493444 +v 1.493270 1.862270 -4.455014 +v 1.597491 2.018248 -4.398108 +v 1.693542 2.161998 -4.305698 +v 1.777731 2.287996 -4.181335 +v 1.846823 2.391400 -4.029799 +v 1.898164 2.468236 -3.856912 +v 1.929779 2.515551 -3.669319 +v 1.940454 2.531528 -3.474229 +v 1.929779 2.515552 -3.279139 +v 1.898164 2.468236 -3.091545 +v 1.846823 2.391400 -2.918658 +v 1.777731 2.287996 -2.767122 +v 1.693542 2.161998 -2.642759 +v 1.597491 2.018248 -2.550349 +v 1.493270 1.862270 -2.493444 +v 1.384884 1.700058 -4.474229 +v 1.459542 1.880298 -4.455014 +v 1.531330 2.053612 -4.398108 +v 1.597491 2.213338 -4.305698 +v 1.655482 2.353340 -4.181335 +v 1.703073 2.468236 -4.029799 +v 1.738437 2.553612 -3.856912 +v 1.760214 2.606186 -3.669319 +v 1.767567 2.623938 -3.474229 +v 1.760214 2.606186 -3.279139 +v 1.738437 2.553612 -3.091545 +v 1.703073 2.468236 -2.918658 +v 1.655482 2.353340 -2.767122 +v 1.597491 2.213338 -2.642759 +v 1.531330 2.053612 -2.550349 +v 1.459542 1.880298 -2.493444 +v 1.422944 1.891400 -4.455014 +v 1.459542 2.075389 -4.398108 +v 1.493270 2.244953 -4.305698 +v 1.522834 2.393578 -4.181335 +v 1.547095 2.515551 -4.029799 +v 1.565124 2.606186 -3.856912 +v 1.576225 2.661998 -3.669319 +v 1.579974 2.680843 -3.474229 +v 1.576225 2.661998 -3.279139 +v 1.565124 2.606186 -3.091545 +v 1.547095 2.515551 -2.918658 +v 1.522834 2.393578 -2.767122 +v 1.493270 2.244953 -2.642759 +v 1.459542 2.075389 -2.550349 +v 1.422944 1.891400 -2.493444 +v 1.384884 1.895149 -4.455014 +v 1.384884 2.082742 -4.398108 +v 1.384884 2.255628 -4.305698 +v 1.384884 2.407165 -4.181335 +v 1.384884 2.531528 -4.029799 +v 1.384884 2.623938 -3.856912 +v 1.384884 2.680843 -3.669319 +v 1.384884 2.700058 -3.474229 +v 1.384884 2.680843 -3.279139 +v 1.384884 2.623938 -3.091545 +v 1.384884 2.531528 -2.918658 +v 1.384884 2.407165 -2.767122 +v 1.384884 2.255629 -2.642759 +v 1.384884 2.082742 -2.550349 +v 1.384884 1.895149 -2.493444 +v 1.346824 1.891400 -4.455014 +v 1.310226 2.075389 -4.398108 +v 1.276497 2.244953 -4.305698 +v 1.246934 2.393578 -4.181335 +v 1.222672 2.515551 -4.029799 +v 1.204644 2.606186 -3.856912 +v 1.193542 2.661998 -3.669319 +v 1.189793 2.680843 -3.474229 +v 1.193542 2.661998 -3.279139 +v 1.204644 2.606186 -3.091545 +v 1.222672 2.515551 -2.918658 +v 1.246934 2.393578 -2.767122 +v 1.276497 2.244953 -2.642759 +v 1.310226 2.075389 -2.550349 +v 1.346824 1.891400 -2.493444 +v 1.310226 1.880298 -4.455014 +v 1.238437 2.053612 -4.398108 +v 1.172276 2.213338 -4.305698 +v 1.114286 2.353340 -4.181335 +v 1.066694 2.468236 -4.029799 +v 1.031331 2.553612 -3.856912 +v 1.009554 2.606185 -3.669319 +v 1.002200 2.623937 -3.474229 +v 1.009554 2.606185 -3.279139 +v 1.031331 2.553612 -3.091545 +v 1.066694 2.468236 -2.918658 +v 1.114286 2.353339 -2.767122 +v 1.172276 2.213338 -2.642759 +v 1.238437 2.053612 -2.550349 +v 1.310226 1.880298 -2.493444 +v 1.276498 1.862270 -4.455014 +v 1.172276 2.018248 -4.398108 +v 1.076226 2.161998 -4.305698 +v 0.992036 2.287996 -4.181335 +v 0.922944 2.391400 -4.029799 +v 0.871604 2.468236 -3.856912 +v 0.839989 2.515551 -3.669319 +v 0.829314 2.531527 -3.474229 +v 0.839989 2.515551 -3.279139 +v 0.871604 2.468236 -3.091545 +v 0.922944 2.391400 -2.918658 +v 0.992036 2.287996 -2.767122 +v 1.076226 2.161998 -2.642759 +v 1.172276 2.018248 -2.550349 +v 1.276498 1.862270 -2.493444 +v 1.246934 1.838008 -4.455014 +v 1.114286 1.970656 -4.398108 +v 0.992036 2.092906 -4.305698 +v 0.884884 2.200058 -4.181335 +v 0.796946 2.287996 -4.029799 +v 0.731603 2.353340 -3.856912 +v 0.691364 2.393578 -3.669319 +v 0.677777 2.407165 -3.474229 +v 0.691364 2.393578 -3.279139 +v 0.731603 2.353340 -3.091545 +v 0.796946 2.287996 -2.918658 +v 0.884884 2.200058 -2.767122 +v 0.992036 2.092906 -2.642759 +v 1.114286 1.970656 -2.550349 +v 1.246934 1.838008 -2.493444 +v 1.222672 1.808445 -4.455014 +v 1.066694 1.912666 -4.398108 +v 0.922944 2.008716 -4.305698 +v 0.796946 2.092906 -4.181335 +v 0.693542 2.161998 -4.029799 +v 0.616706 2.213338 -3.856912 +v 0.569391 2.244953 -3.669319 +v 0.553415 2.255628 -3.474229 +v 0.569391 2.244953 -3.279139 +v 0.616706 2.213338 -3.091545 +v 0.693542 2.161998 -2.918658 +v 0.796946 2.092906 -2.767122 +v 0.922944 2.008716 -2.642759 +v 1.066694 1.912666 -2.550349 +v 1.222672 1.808445 -2.493444 +v 1.204644 1.774716 -4.455014 +v 1.031331 1.846505 -4.398108 +v 0.871604 1.912666 -4.305698 +v 0.731602 1.970656 -4.181335 +v 0.616706 2.018248 -4.029799 +v 0.531331 2.053612 -3.856912 +v 0.478757 2.075388 -3.669319 +v 0.461005 2.082741 -3.474229 +v 0.478757 2.075388 -3.279139 +v 0.531331 2.053612 -3.091545 +v 0.616706 2.018248 -2.918658 +v 0.731602 1.970656 -2.767122 +v 0.871604 1.912666 -2.642759 +v 1.031331 1.846505 -2.550349 +v 1.204644 1.774716 -2.493444 +v 1.193542 1.738119 -4.455014 +v 1.009554 1.774716 -4.398108 +v 0.839989 1.808445 -4.305698 +v 0.691364 1.838008 -4.181335 +v 0.569391 1.862270 -4.029799 +v 0.478757 1.880298 -3.856912 +v 0.422944 1.891400 -3.669319 +v 0.404099 1.895148 -3.474229 +v 0.422944 1.891400 -3.279139 +v 0.478757 1.880298 -3.091545 +v 0.569391 1.862270 -2.918658 +v 0.691364 1.838008 -2.767122 +v 0.839989 1.808445 -2.642759 +v 1.009554 1.774716 -2.550349 +v 1.193542 1.738119 -2.493444 +v 1.189794 1.700058 -4.455014 +v 1.002200 1.700058 -4.398108 +v 0.829314 1.700058 -4.305698 +v 0.677777 1.700058 -4.181335 +v 0.553415 1.700058 -4.029799 +v 0.461005 1.700058 -3.856912 +v 0.404099 1.700058 -3.669319 +v 0.384885 1.700058 -3.474229 +v 0.404099 1.700058 -3.279139 +v 0.461005 1.700058 -3.091545 +v 0.553415 1.700058 -2.918658 +v 0.677777 1.700058 -2.767122 +v 0.829314 1.700058 -2.642759 +v 1.002200 1.700058 -2.550349 +v 1.189794 1.700058 -2.493444 +v 1.193542 1.661998 -4.455014 +v 1.009554 1.625400 -4.398108 +v 0.839989 1.591672 -4.305698 +v 0.691364 1.562109 -4.181335 +v 0.569391 1.537847 -4.029799 +v 0.478757 1.519819 -3.856912 +v 0.422944 1.508717 -3.669319 +v 0.404099 1.504968 -3.474229 +v 0.422944 1.508717 -3.279138 +v 0.478757 1.519818 -3.091545 +v 0.569391 1.537847 -2.918658 +v 0.691364 1.562109 -2.767122 +v 0.839989 1.591672 -2.642759 +v 1.009554 1.625400 -2.550349 +v 1.193542 1.661998 -2.493444 +v 1.204644 1.625401 -4.455014 +v 1.031331 1.553612 -4.398108 +v 0.871604 1.487451 -4.305698 +v 0.731603 1.429460 -4.181335 +v 0.616706 1.381869 -4.029799 +v 0.531331 1.346505 -3.856912 +v 0.478757 1.324728 -3.669319 +v 0.461005 1.317375 -3.474229 +v 0.478757 1.324728 -3.279138 +v 0.531331 1.346505 -3.091545 +v 0.616706 1.381869 -2.918658 +v 0.731603 1.429460 -2.767122 +v 0.871604 1.487451 -2.642759 +v 1.031331 1.553612 -2.550349 +v 1.204644 1.625401 -2.493444 +v 1.222672 1.591672 -4.455014 +v 1.066694 1.487451 -4.398108 +v 0.922944 1.391400 -4.305698 +v 0.796946 1.307211 -4.181335 +v 0.693542 1.238119 -4.029799 +v 0.616706 1.186779 -3.856912 +v 0.569391 1.155163 -3.669319 +v 0.553415 1.144488 -3.474229 +v 0.569391 1.155163 -3.279138 +v 0.616706 1.186779 -3.091545 +v 0.693542 1.238119 -2.918658 +v 0.796946 1.307211 -2.767122 +v 0.922944 1.391400 -2.642759 +v 1.066694 1.487451 -2.550349 +v 1.222672 1.591672 -2.493444 +v 1.246934 1.562109 -4.455014 +v 1.114286 1.429460 -4.398108 +v 0.992037 1.307211 -4.305698 +v 0.884884 1.200058 -4.181335 +v 0.796946 1.112121 -4.029799 +v 0.731603 1.046777 -3.856912 +v 0.691364 1.006539 -3.669319 +v 0.677778 0.992952 -3.474229 +v 0.691364 1.006539 -3.279138 +v 0.731603 1.046777 -3.091545 +v 0.796946 1.112121 -2.918658 +v 0.884884 1.200058 -2.767122 +v 0.992037 1.307211 -2.642759 +v 1.114286 1.429460 -2.550349 +v 1.246934 1.562109 -2.493443 +v 1.384884 1.700058 -2.474229 +v 1.276498 1.537847 -4.455014 +v 1.172276 1.381869 -4.398108 +v 1.076226 1.238119 -4.305698 +v 0.992037 1.112121 -4.181335 +v 0.922944 1.008717 -4.029799 +v 0.871604 0.931881 -3.856912 +v 0.839989 0.884565 -3.669319 +v 0.829314 0.868589 -3.474229 +v 0.839989 0.884565 -3.279138 +v 0.871604 0.931881 -3.091545 +v 0.922944 1.008717 -2.918658 +v 0.992037 1.112121 -2.767122 +v 1.076226 1.238119 -2.642759 +v 1.172276 1.381869 -2.550349 +v 1.276498 1.537847 -2.493443 +v 1.310226 1.519819 -4.455014 +v 1.238437 1.346505 -4.398108 +v 1.172277 1.186779 -4.305698 +v 1.114286 1.046777 -4.181335 +v 1.066694 0.931881 -4.029799 +v 1.031331 0.846505 -3.856912 +v 1.009554 0.793931 -3.669319 +v 1.002201 0.776179 -3.474229 +v 1.009554 0.793931 -3.279138 +v 1.031331 0.846505 -3.091545 +v 1.066694 0.931881 -2.918658 +v 1.114286 1.046777 -2.767122 +v 1.172277 1.186779 -2.642759 +v 1.238437 1.346505 -2.550349 +v 1.310226 1.519818 -2.493443 +v 1.346824 1.508717 -4.455014 +v 1.310226 1.324728 -4.398108 +v 1.276498 1.155164 -4.305698 +v 1.246934 1.006539 -4.181335 +v 1.222672 0.884566 -4.029799 +v 1.204644 0.793931 -3.856912 +v 1.193542 0.738119 -3.669319 +v 1.189794 0.719274 -3.474229 +v 1.193542 0.738119 -3.279138 +v 1.204644 0.793931 -3.091545 +v 1.222672 0.884566 -2.918658 +v 1.246934 1.006539 -2.767122 +v 1.276498 1.155164 -2.642759 +v 1.310226 1.324728 -2.550349 +v 1.346824 1.508717 -2.493443 +v 1.384884 1.504968 -4.455014 +v 1.384884 1.317375 -4.398108 +v 1.384884 1.144489 -4.305698 +v 1.384884 0.992952 -4.181335 +v 1.384884 0.868589 -4.029799 +v 1.384884 0.776179 -3.856912 +v 1.384884 0.719273 -3.669319 +v 1.384884 0.700059 -3.474229 +v 1.384884 0.719274 -3.279138 +v 1.384884 0.776179 -3.091545 +v 1.384884 0.868589 -2.918658 +v 1.384884 0.992952 -2.767122 +v 1.384884 1.144488 -2.642759 +v 1.384884 1.317375 -2.550349 +v 1.384884 1.504968 -2.493443 +v 1.422944 1.508717 -4.455014 +v 1.459542 1.324728 -4.398108 +v 1.493270 1.155164 -4.305698 +v 1.522833 1.006539 -4.181335 +v 1.547096 0.884566 -4.029799 +v 1.565124 0.793931 -3.856912 +v 1.576226 0.738119 -3.669319 +v 1.579975 0.719274 -3.474229 +v 1.576226 0.738119 -3.279138 +v 1.565124 0.793931 -3.091545 +v 1.547096 0.884566 -2.918658 +v 1.522833 1.006539 -2.767122 +v 1.493270 1.155164 -2.642759 +v 1.459542 1.324728 -2.550349 +v 1.422944 1.508717 -2.493443 +v 1.459542 1.519819 -4.455014 +v 1.531330 1.346505 -4.398108 +v 1.597491 1.186779 -4.305698 +v 1.655482 1.046777 -4.181335 +v 1.703073 0.931881 -4.029799 +v 1.738437 0.846505 -3.856912 +v 1.760214 0.793931 -3.669319 +v 1.767567 0.776180 -3.474229 +v 1.760214 0.793931 -3.279138 +v 1.738437 0.846505 -3.091545 +v 1.703073 0.931881 -2.918658 +v 1.655482 1.046777 -2.767122 +v 1.597491 1.186779 -2.642759 +v 1.531330 1.346505 -2.550349 +v 1.459542 1.519819 -2.493443 +v 1.493270 1.537847 -4.455014 +v 1.597491 1.381869 -4.398108 +v 1.693542 1.238119 -4.305698 +v 1.777731 1.112121 -4.181335 +v 1.846823 1.008717 -4.029799 +v 1.898164 0.931881 -3.856912 +v 1.929779 0.884566 -3.669319 +v 1.940454 0.868590 -3.474229 +v 1.929779 0.884566 -3.279138 +v 1.898164 0.931881 -3.091545 +v 1.846823 1.008717 -2.918658 +v 1.777731 1.112121 -2.767122 +v 1.693542 1.238119 -2.642759 +v 1.597491 1.381869 -2.550349 +v 1.493270 1.537847 -2.493443 +v 1.522833 1.562109 -4.455014 +v 1.655482 1.429460 -4.398108 +v 1.777731 1.307211 -4.305698 +v 1.884884 1.200059 -4.181335 +v 1.972821 1.112121 -4.029799 +v 2.038165 1.046777 -3.856912 +v 2.078404 1.006539 -3.669319 +v 2.091990 0.992953 -3.474229 +v 2.078404 1.006539 -3.279138 +v 2.038165 1.046777 -3.091545 +v 1.972821 1.112121 -2.918658 +v 1.884884 1.200058 -2.767122 +v 1.777731 1.307211 -2.642759 +v 1.655482 1.429460 -2.550349 +v 1.522833 1.562109 -2.493443 +v 1.547095 1.591672 -4.455014 +v 1.703073 1.487451 -4.398108 +v 1.846823 1.391400 -4.305698 +v 1.972822 1.307211 -4.181335 +v 2.076225 1.238119 -4.029799 +v 2.153061 1.186779 -3.856912 +v 2.200377 1.155164 -3.669319 +v 2.216353 1.144489 -3.474229 +v 2.200377 1.155164 -3.279138 +v 2.153061 1.186779 -3.091545 +v 2.076225 1.238119 -2.918658 +v 1.972822 1.307211 -2.767122 +v 1.846823 1.391400 -2.642759 +v 1.703073 1.487451 -2.550349 +v 1.547095 1.591672 -2.493444 +v 1.565124 1.625401 -4.455014 +v 1.738437 1.553612 -4.398108 +v 1.898163 1.487451 -4.305698 +v 2.038165 1.429460 -4.181335 +v 2.153061 1.381869 -4.029799 +v 2.238437 1.346505 -3.856912 +v 2.291011 1.324728 -3.669319 +v 2.308763 1.317376 -3.474229 +v 2.291011 1.324728 -3.279138 +v 2.238437 1.346505 -3.091545 +v 2.153061 1.381869 -2.918658 +v 2.038165 1.429461 -2.767122 +v 1.898163 1.487451 -2.642759 +v 1.738437 1.553612 -2.550349 +v 1.565124 1.625401 -2.493444 +v 1.576225 1.661998 -4.455014 +v 1.760214 1.625401 -4.398108 +v 1.929778 1.591672 -4.305698 +v 2.078404 1.562109 -4.181335 +v 2.200377 1.537847 -4.029799 +v 2.291011 1.519819 -3.856912 +v 2.346823 1.508717 -3.669319 +v 2.365668 1.504969 -3.474229 +v 2.346823 1.508717 -3.279138 +v 2.291011 1.519818 -3.091545 +v 2.200377 1.537847 -2.918658 +v 2.078404 1.562109 -2.767122 +v 1.929778 1.591672 -2.642759 +v 1.760214 1.625401 -2.550349 +v 1.576225 1.661998 -2.493444 +v 1.579974 1.700058 -4.455014 +v 1.767567 1.700058 -4.398108 +v 2.091990 1.700058 -4.181335 +v 2.308763 1.700058 -3.856912 +v 2.308763 1.700058 -3.091545 +v 2.091990 1.700058 -2.767122 +v 1.940453 1.700059 -2.642759 +v 1.767567 1.700058 -2.550349 +v 1.579974 1.700058 -2.493444 +v -6.042284 1.586531 -4.246895 +v -6.042284 1.586531 1.000000 +v -6.649259 0.515920 1.000000 +v -6.649259 0.515920 -4.246895 +v -6.653658 0.560581 1.000000 +v -6.653658 0.560581 -4.246895 +v -6.666685 0.603526 1.000000 +v -6.666685 0.603526 -4.246895 +v -6.687840 0.643104 1.000000 +v -6.687840 0.643104 -4.246895 +v -6.716310 0.677795 1.000000 +v -6.716310 0.677795 -4.246895 +v -6.751000 0.706264 1.000000 +v -6.751000 0.706264 -4.246895 +v -6.790579 0.727419 1.000000 +v -6.790579 0.727419 -4.246895 +v -6.833524 0.740447 1.000000 +v -6.833524 0.740447 -4.246895 +v -6.878185 0.744845 1.000000 +v -6.878185 0.744845 -4.246895 +v -6.922846 0.740446 1.000000 +v -6.922846 0.740447 -4.246895 +v -6.965791 0.727419 1.000000 +v -6.965791 0.727419 -4.246895 +v -7.005369 0.706264 1.000000 +v -7.005369 0.706264 -4.246895 +v -7.040060 0.677795 1.000000 +v -7.040060 0.677795 -4.246895 +v -7.068529 0.643104 1.000000 +v -7.068529 0.643104 -4.246895 +v -7.089684 0.603526 1.000000 +v -7.089684 0.603526 -4.246895 +v -7.102711 0.560581 1.000000 +v -7.102711 0.560581 -4.246895 +v -7.107110 0.515920 1.000000 +v -7.107110 0.515920 -4.246895 +v -7.102711 0.471259 1.000000 +v -7.102711 0.471259 -4.246895 +v -7.089684 0.428314 1.000000 +v -7.089684 0.428314 -4.246895 +v -7.068529 0.388736 1.000000 +v -7.068529 0.388736 -4.246895 +v -7.040060 0.354045 1.000000 +v -7.040060 0.354045 -4.246895 +v -7.005369 0.325575 1.000000 +v -7.005369 0.325575 -4.246895 +v -6.965791 0.304420 1.000000 +v -6.965791 0.304420 -4.246895 +v -6.922846 0.291393 1.000000 +v -6.922846 0.291393 -4.246895 +v -6.878185 0.286994 1.000000 +v -6.878185 0.286994 -4.246895 +v -6.833524 0.291393 1.000000 +v -6.833524 0.291393 -4.246895 +v -6.790579 0.304420 1.000000 +v -6.790579 0.304420 -4.246895 +v -6.751000 0.325575 1.000000 +v -6.751000 0.325575 -4.246895 +v -6.716310 0.354045 1.000000 +v -6.716310 0.354045 -4.246895 +v -6.687840 0.388736 1.000000 +v -6.687840 0.388736 -4.246895 +v -6.666685 0.428314 1.000000 +v -6.666685 0.428314 -4.246895 +v -6.653658 0.471259 1.000000 +v -6.653658 0.471259 -4.246895 +v -6.046682 1.631192 1.000000 +v -6.046682 1.631192 -4.246895 +v -6.059710 1.674137 1.000000 +v -6.059710 1.674137 -4.246895 +v -6.080864 1.713715 1.000000 +v -6.080864 1.713715 -4.246895 +v -6.109334 1.748405 1.000000 +v -6.109334 1.748405 -4.246895 +v -6.144025 1.776875 1.000000 +v -6.144025 1.776875 -4.246895 +v -6.183603 1.798030 1.000000 +v -6.183603 1.798030 -4.246895 +v -6.226548 1.811057 1.000000 +v -6.226548 1.811057 -4.246895 +v -6.271209 1.815456 1.000000 +v -6.271209 1.815456 -4.246895 +v -6.315870 1.811057 1.000000 +v -6.315870 1.811057 -4.246895 +v -6.358815 1.798030 1.000000 +v -6.358815 1.798030 -4.246895 +v -6.398393 1.776875 1.000000 +v -6.398393 1.776875 -4.246895 +v -6.433084 1.748405 1.000000 +v -6.433084 1.748405 -4.246895 +v -6.461554 1.713715 1.000000 +v -6.461554 1.713715 -4.246895 +v -6.482708 1.674137 1.000000 +v -6.482708 1.674137 -4.246895 +v -6.495736 1.631192 1.000000 +v -6.495736 1.631192 -4.246895 +v -6.500134 1.586531 1.000000 +v -6.500134 1.586531 -4.246895 +v -6.495736 1.541870 1.000000 +v -6.495736 1.541869 -4.246895 +v -6.482708 1.498925 1.000000 +v -6.482708 1.498925 -4.246895 +v -6.461554 1.459347 1.000000 +v -6.461554 1.459346 -4.246895 +v -6.433084 1.424656 1.000000 +v -6.433084 1.424656 -4.246895 +v -6.398393 1.396186 1.000000 +v -6.398393 1.396186 -4.246895 +v -6.358815 1.375031 1.000000 +v -6.358815 1.375031 -4.246895 +v -6.315870 1.362004 1.000000 +v -6.315870 1.362004 -4.246895 +v -6.271209 1.357605 1.000000 +v -6.271209 1.357605 -4.246895 +v -6.226548 1.362004 1.000000 +v -6.226548 1.362004 -4.246895 +v -6.183603 1.375031 1.000000 +v -6.183603 1.375031 -4.246895 +v -6.144025 1.396186 1.000000 +v -6.144025 1.396186 -4.246895 +v -6.109334 1.424656 1.000000 +v -6.109334 1.424656 -4.246895 +v -6.080864 1.459347 1.000000 +v -6.080864 1.459346 -4.246895 +v -6.059710 1.498925 1.000000 +v -6.059710 1.498925 -4.246895 +v -6.046682 1.541870 1.000000 +v -6.046682 1.541869 -4.246895 +v -5.206753 2.407171 -4.246895 +v -5.206753 2.407171 1.000000 +v -5.211152 2.451832 1.000000 +v -5.211152 2.451832 -4.246895 +v -5.224179 2.494777 1.000000 +v -5.224179 2.494777 -4.246895 +v -5.245334 2.534355 1.000000 +v -5.245334 2.534355 -4.246895 +v -5.273804 2.569046 1.000000 +v -5.273804 2.569046 -4.246895 +v -5.308494 2.597516 1.000000 +v -5.308494 2.597516 -4.246895 +v -5.348073 2.618671 1.000000 +v -5.348073 2.618670 -4.246895 +v -5.391017 2.631698 1.000000 +v -5.391017 2.631698 -4.246895 +v -5.435678 2.636096 1.000000 +v -5.435678 2.636096 -4.246895 +v -5.480340 2.631698 1.000000 +v -5.480340 2.631698 -4.246895 +v -5.523284 2.618671 1.000000 +v -5.523284 2.618670 -4.246895 +v -5.562862 2.597516 1.000000 +v -5.562862 2.597516 -4.246895 +v -5.597553 2.569046 1.000000 +v -5.597553 2.569046 -4.246895 +v -5.626023 2.534355 1.000000 +v -5.626023 2.534355 -4.246895 +v -5.647178 2.494777 1.000000 +v -5.647178 2.494777 -4.246895 +v -5.660205 2.451832 1.000000 +v -5.660205 2.451832 -4.246895 +v -5.664604 2.407171 1.000000 +v -5.664604 2.407171 -4.246895 +v -5.660205 2.362510 1.000000 +v -5.660205 2.362510 -4.246895 +v -5.647178 2.319565 1.000000 +v -5.647178 2.319565 -4.246895 +v -5.626023 2.279987 1.000000 +v -5.626023 2.279987 -4.246895 +v -5.597553 2.245296 1.000000 +v -5.597553 2.245296 -4.246895 +v -5.562862 2.216827 1.000000 +v -5.562862 2.216826 -4.246895 +v -5.523284 2.195672 1.000000 +v -5.523284 2.195672 -4.246895 +v -5.480340 2.182644 1.000000 +v -5.480340 2.182644 -4.246895 +v -5.435678 2.178246 1.000000 +v -5.435678 2.178246 -4.246895 +v -5.391017 2.182644 1.000000 +v -5.391017 2.182644 -4.246895 +v -5.348073 2.195672 1.000000 +v -5.348073 2.195672 -4.246895 +v -5.308494 2.216827 1.000000 +v -5.308494 2.216826 -4.246895 +v -5.273804 2.245296 1.000000 +v -5.273804 2.245296 -4.246895 +v -5.245334 2.279987 1.000000 +v -5.245334 2.279987 -4.246895 +v -5.224179 2.319565 1.000000 +v -5.224179 2.319565 -4.246895 +v -5.211152 2.362510 1.000000 +v -5.211152 2.362510 -4.246895 +v -6.283453 1.568205 -4.846380 +v -6.366491 1.443930 -4.714700 +v -6.321685 1.510987 -4.828739 +v -6.352079 1.465500 -4.780540 +v -6.392481 1.465259 -4.714700 +v -6.286795 1.570947 -4.846380 +v -6.374138 1.483602 -4.780540 +v -6.335454 1.522286 -4.828739 +v -6.856569 0.520221 -4.846380 +v -6.709977 0.549378 -4.714700 +v -6.789075 0.533645 -4.828739 +v -6.735418 0.544318 -4.780540 +v -6.706681 0.515920 -4.714700 +v -6.856145 0.515919 -4.846380 +v -6.732621 0.515919 -4.780540 +v -6.787329 0.515919 -4.828739 +v -6.279644 1.606892 -4.846380 +v -6.336841 1.744979 -4.714700 +v -6.305978 1.670469 -4.828739 +v -6.326914 1.721013 -4.780540 +v -6.304668 1.754738 -4.714700 +v -6.275508 1.608146 -4.846380 +v -6.299607 1.729296 -4.780540 +v -6.288934 1.675640 -4.828739 +v -6.857823 0.524354 -4.846380 +v -6.719736 0.581551 -4.714700 +v -6.794245 0.550689 -4.828739 +v -6.743702 0.571624 -4.780540 +v -6.859859 0.528164 -4.846380 +v -6.735585 0.611202 -4.714700 +v -6.802641 0.566396 -4.828739 +v -6.757154 0.596790 -4.780540 +v -6.413809 1.491248 -4.714700 +v -6.289533 1.574284 -4.846380 +v -6.392241 1.505659 -4.780540 +v -6.346752 1.536053 -4.828739 +v -6.862600 0.531503 -4.846380 +v -6.756914 0.637191 -4.714700 +v -6.813940 0.580164 -4.828739 +v -6.775256 0.618848 -4.780540 +v -6.271209 1.758034 -4.714700 +v -6.271210 1.608570 -4.846380 +v -6.271209 1.732093 -4.780540 +v -6.271210 1.677385 -4.828739 +v -6.865940 0.534245 -4.846380 +v -6.782903 0.658519 -4.714700 +v -6.827708 0.591463 -4.828739 +v -6.797315 0.636951 -4.780540 +v -6.869750 0.536281 -4.846380 +v -6.812553 0.674368 -4.714700 +v -6.843416 0.599858 -4.828739 +v -6.822481 0.650402 -4.780540 +v -6.429658 1.520899 -4.714700 +v -6.291572 1.578098 -4.846380 +v -6.405692 1.530826 -4.780540 +v -6.355149 1.551762 -4.828739 +v -6.873886 0.537535 -4.846380 +v -6.844726 0.684128 -4.714700 +v -6.860460 0.605029 -4.828739 +v -6.849787 0.658685 -4.780540 +v -6.237751 1.754738 -4.714700 +v -6.266910 1.608146 -4.846380 +v -6.242812 1.729296 -4.780540 +v -6.253485 1.675640 -4.828739 +v -6.878185 0.537959 -4.846380 +v -6.878185 0.687423 -4.714700 +v -6.878185 0.606775 -4.828739 +v -6.878185 0.661482 -4.780540 +v -6.882484 0.537535 -4.846380 +v -6.911644 0.684128 -4.714700 +v -6.895909 0.605029 -4.828739 +v -6.906583 0.658685 -4.780540 +v -6.439417 1.553072 -4.714700 +v -6.292825 1.582229 -4.846380 +v -6.413976 1.558132 -4.780540 +v -6.360319 1.568804 -4.828739 +v -6.886619 0.536281 -4.846380 +v -6.943816 0.674368 -4.714700 +v -6.912953 0.599859 -4.828739 +v -6.933889 0.650402 -4.780540 +v -6.205578 1.744979 -4.714700 +v -6.262775 1.606892 -4.846380 +v -6.215505 1.721012 -4.780540 +v -6.236441 1.670469 -4.828739 +v -6.890430 0.534244 -4.846380 +v -6.973467 0.658519 -4.714700 +v -6.928662 0.591463 -4.828739 +v -6.959055 0.636951 -4.780540 +v -6.893768 0.531505 -4.846380 +v -6.999456 0.637191 -4.714700 +v -6.942429 0.580164 -4.828739 +v -6.981113 0.618848 -4.780540 +v -6.442713 1.586530 -4.714700 +v -6.293249 1.586530 -4.846380 +v -6.416773 1.586530 -4.780540 +v -6.362065 1.586530 -4.828739 +v -6.896510 0.528163 -4.846380 +v -7.020784 0.611202 -4.714700 +v -6.953728 0.566395 -4.828739 +v -6.999216 0.596790 -4.780540 +v -6.175927 1.729130 -4.714700 +v -6.258965 1.604855 -4.846380 +v -6.190339 1.707561 -4.780540 +v -6.220733 1.662073 -4.828739 +v -6.898546 0.524354 -4.846380 +v -7.036633 0.581551 -4.714700 +v -6.962123 0.550688 -4.828739 +v -7.012667 0.571624 -4.780540 +v -6.899801 0.520219 -4.846380 +v -7.046393 0.549378 -4.714700 +v -6.967294 0.533644 -4.828739 +v -7.020951 0.544317 -4.780540 +v -6.439417 1.619989 -4.714700 +v -6.292825 1.590831 -4.846380 +v -6.413976 1.614928 -4.780540 +v -6.360319 1.604256 -4.828739 +v -6.900224 0.515919 -4.846380 +v -7.049688 0.515920 -4.714700 +v -6.969040 0.515919 -4.828739 +v -7.023747 0.515920 -4.780540 +v -6.149938 1.707801 -4.714700 +v -6.255624 1.602114 -4.846380 +v -6.168281 1.689459 -4.780540 +v -6.206964 1.650774 -4.828739 +v -6.899801 0.511620 -4.846380 +v -7.046393 0.482461 -4.714700 +v -6.967294 0.498194 -4.828739 +v -7.020951 0.487522 -4.780540 +v -6.898546 0.507485 -4.846380 +v -7.036633 0.450288 -4.714700 +v -6.962123 0.481151 -4.828739 +v -7.012667 0.460215 -4.780540 +v -6.429658 1.652162 -4.714700 +v -6.291572 1.594963 -4.846380 +v -6.405692 1.642234 -4.780540 +v -6.355149 1.621298 -4.828739 +v -6.896510 0.503674 -4.846380 +v -7.020784 0.420637 -4.714700 +v -6.953728 0.465443 -4.828739 +v -6.999215 0.435049 -4.780540 +v -6.128609 1.681813 -4.714700 +v -6.252885 1.598776 -4.846380 +v -6.150178 1.667400 -4.780540 +v -6.195667 1.637007 -4.828739 +v -6.893769 0.500335 -4.846380 +v -6.999456 0.394648 -4.714700 +v -6.942429 0.451675 -4.828739 +v -6.981113 0.412991 -4.780540 +v -6.890430 0.497595 -4.846380 +v -6.973467 0.373320 -4.714700 +v -6.928662 0.440376 -4.828739 +v -6.959055 0.394888 -4.780540 +v -6.413809 1.681813 -4.714700 +v -6.289533 1.598776 -4.846380 +v -6.392241 1.667401 -4.780540 +v -6.346752 1.637008 -4.828739 +v -6.886618 0.495557 -4.846380 +v -6.943816 0.357471 -4.714700 +v -6.912953 0.431980 -4.828739 +v -6.933889 0.381437 -4.780540 +v -6.112761 1.652162 -4.714700 +v -6.250847 1.594963 -4.846380 +v -6.136726 1.642234 -4.780540 +v -6.187270 1.621298 -4.828739 +v -6.882484 0.494303 -4.846380 +v -6.911644 0.347711 -4.714700 +v -6.895910 0.426810 -4.828739 +v -6.906583 0.373153 -4.780540 +v -6.878185 0.493880 -4.846380 +v -6.878185 0.344416 -4.714700 +v -6.878185 0.425064 -4.828739 +v -6.878185 0.370357 -4.780540 +v -6.392481 1.707801 -4.714700 +v -6.286795 1.602113 -4.846380 +v -6.374138 1.689458 -4.780540 +v -6.335454 1.650774 -4.828739 +v -6.873885 0.494303 -4.846380 +v -6.844726 0.347711 -4.714700 +v -6.860460 0.426810 -4.828739 +v -6.849787 0.373154 -4.780540 +v -6.103001 1.619989 -4.714700 +v -6.249594 1.590831 -4.846380 +v -6.128443 1.614928 -4.780540 +v -6.182099 1.604256 -4.828739 +v -6.869751 0.495557 -4.846380 +v -6.812553 0.357471 -4.714700 +v -6.843416 0.431980 -4.828739 +v -6.822481 0.381437 -4.780540 +v -6.865940 0.497595 -4.846380 +v -6.782903 0.373320 -4.714700 +v -6.827708 0.440376 -4.828739 +v -6.797315 0.394888 -4.780540 +v -6.366491 1.729130 -4.714700 +v -6.283454 1.604855 -4.846380 +v -6.352080 1.707561 -4.780540 +v -6.321686 1.662073 -4.828739 +v -6.862600 0.500336 -4.846380 +v -6.756914 0.394648 -4.714700 +v -6.813940 0.451675 -4.828739 +v -6.775256 0.412991 -4.780540 +v -6.859859 0.503675 -4.846380 +v -6.735585 0.420637 -4.714700 +v -6.802641 0.465443 -4.828739 +v -6.757154 0.435049 -4.780540 +v -6.099706 1.586530 -4.714700 +v -6.249170 1.586530 -4.846380 +v -6.125646 1.586530 -4.780540 +v -6.180354 1.586530 -4.828739 +v -6.857823 0.507485 -4.846380 +v -6.719736 0.450288 -4.714700 +v -6.794245 0.481150 -4.828739 +v -6.743702 0.460215 -4.780540 +v -6.856569 0.511618 -4.846380 +v -6.709977 0.482461 -4.714700 +v -6.789075 0.498194 -4.828739 +v -6.735418 0.487521 -4.780540 +v -6.279644 1.566168 -4.846380 +v -6.336841 1.428082 -4.714700 +v -6.305978 1.502591 -4.828739 +v -6.326914 1.452048 -4.780540 +v -6.275509 1.564914 -4.846380 +v -6.304668 1.418322 -4.714700 +v -6.288934 1.497421 -4.828739 +v -6.299607 1.443764 -4.780540 +v -6.271210 1.564491 -4.846380 +v -6.271209 1.415027 -4.714700 +v -6.271210 1.495675 -4.828739 +v -6.271209 1.440967 -4.780540 +v -6.266910 1.564914 -4.846380 +v -6.237751 1.418322 -4.714700 +v -6.253485 1.497421 -4.828739 +v -6.242812 1.443764 -4.780540 +v -6.262775 1.566169 -4.846380 +v -6.205578 1.428082 -4.714700 +v -6.236441 1.502591 -4.828739 +v -6.215505 1.452048 -4.780540 +v -6.258965 1.568205 -4.846380 +v -6.175927 1.443930 -4.714700 +v -6.220733 1.510987 -4.828739 +v -6.190339 1.465499 -4.780540 +v -6.255624 1.570946 -4.846380 +v -6.149938 1.465259 -4.714700 +v -6.206964 1.522286 -4.828739 +v -6.168281 1.483602 -4.780540 +v -6.252885 1.574285 -4.846380 +v -6.128609 1.491248 -4.714700 +v -6.195667 1.536053 -4.828739 +v -6.150178 1.505660 -4.780540 +v -6.250847 1.578098 -4.846380 +v -6.112761 1.520899 -4.714700 +v -6.187270 1.551762 -4.828739 +v -6.136726 1.530826 -4.780540 +v -6.249594 1.582229 -4.846380 +v -6.103001 1.553072 -4.714700 +v -6.182099 1.568804 -4.828739 +v -6.128443 1.558132 -4.780540 +v -5.447922 2.388844 -4.846380 +v -5.530961 2.264571 -4.714700 +v -5.486154 2.331627 -4.828739 +v -5.516549 2.286140 -4.780540 +v -5.556950 2.285900 -4.714700 +v -5.451262 2.391587 -4.846380 +v -5.538607 2.304242 -4.780540 +v -5.499923 2.342926 -4.828739 +v -5.444113 2.427532 -4.846380 +v -5.501310 2.565619 -4.714700 +v -5.470448 2.491110 -4.828739 +v -5.491383 2.541653 -4.780540 +v -5.469137 2.575379 -4.714700 +v -5.439979 2.428787 -4.846380 +v -5.464077 2.549937 -4.780540 +v -5.453403 2.496280 -4.828739 +v -5.578278 2.311889 -4.714700 +v -5.454004 2.394927 -4.846380 +v -5.556709 2.326300 -4.780540 +v -5.511222 2.356694 -4.828739 +v -5.435678 2.578674 -4.714700 +v -5.435678 2.429210 -4.846380 +v -5.435678 2.552734 -4.780540 +v -5.435678 2.498026 -4.828739 +v -5.594127 2.341539 -4.714700 +v -5.456040 2.398737 -4.846380 +v -5.570161 2.351466 -4.780540 +v -5.519618 2.372402 -4.828739 +v -5.402220 2.575379 -4.714700 +v -5.431378 2.428787 -4.846380 +v -5.407280 2.549937 -4.780540 +v -5.417953 2.496280 -4.828739 +v -5.603887 2.373712 -4.714700 +v -5.457294 2.402871 -4.846380 +v -5.578444 2.378773 -4.780540 +v -5.524788 2.389446 -4.828739 +v -5.370047 2.565619 -4.714700 +v -5.427244 2.427532 -4.846380 +v -5.379974 2.541653 -4.780540 +v -5.400909 2.491110 -4.828739 +v -5.607182 2.407171 -4.714700 +v -5.457718 2.407171 -4.846380 +v -5.581241 2.407171 -4.780540 +v -5.526534 2.407171 -4.828739 +v -5.340396 2.549771 -4.714700 +v -5.423434 2.425496 -4.846380 +v -5.354808 2.528202 -4.780540 +v -5.385202 2.482714 -4.828739 +v -5.603887 2.440629 -4.714700 +v -5.457294 2.411470 -4.846380 +v -5.578444 2.435569 -4.780540 +v -5.524788 2.424896 -4.828739 +v -5.314407 2.528442 -4.714700 +v -5.420094 2.422755 -4.846380 +v -5.332750 2.510099 -4.780540 +v -5.371434 2.471415 -4.828739 +v -5.594127 2.472802 -4.714700 +v -5.456040 2.415604 -4.846380 +v -5.570161 2.462875 -4.780540 +v -5.519618 2.441939 -4.828739 +v -5.293078 2.502453 -4.714700 +v -5.417353 2.419415 -4.846380 +v -5.314648 2.488041 -4.780540 +v -5.360135 2.457647 -4.828739 +v -5.578278 2.502453 -4.714700 +v -5.454003 2.419416 -4.846380 +v -5.556709 2.488041 -4.780540 +v -5.511221 2.457648 -4.828739 +v -5.277230 2.472802 -4.714700 +v -5.415316 2.415604 -4.846380 +v -5.301196 2.462875 -4.780540 +v -5.351739 2.441939 -4.828739 +v -5.556950 2.528442 -4.714700 +v -5.451262 2.422755 -4.846380 +v -5.538607 2.510099 -4.780540 +v -5.499922 2.471415 -4.828739 +v -5.267470 2.440629 -4.714700 +v -5.414063 2.411472 -4.846380 +v -5.292913 2.435569 -4.780540 +v -5.346570 2.424896 -4.828739 +v -5.530961 2.549771 -4.714700 +v -5.447923 2.425496 -4.846380 +v -5.516549 2.528202 -4.780540 +v -5.486155 2.482714 -4.828739 +v -5.264175 2.407171 -4.714700 +v -5.413639 2.407171 -4.846380 +v -5.290116 2.407171 -4.780540 +v -5.344824 2.407171 -4.828739 +v -5.444113 2.386809 -4.846380 +v -5.501310 2.248722 -4.714700 +v -5.470448 2.323231 -4.828739 +v -5.491383 2.272688 -4.780540 +v -5.439978 2.385555 -4.846380 +v -5.469137 2.238963 -4.714700 +v -5.453403 2.318062 -4.828739 +v -5.464077 2.264405 -4.780540 +v -5.435678 2.385131 -4.846380 +v -5.435678 2.235667 -4.714700 +v -5.435678 2.316316 -4.828739 +v -5.435678 2.261608 -4.780540 +v -5.431379 2.385555 -4.846380 +v -5.402220 2.238963 -4.714700 +v -5.417953 2.318062 -4.828739 +v -5.407280 2.264405 -4.780540 +v -5.427244 2.386809 -4.846380 +v -5.370047 2.248722 -4.714700 +v -5.400909 2.323231 -4.828739 +v -5.379974 2.272688 -4.780540 +v -5.423435 2.388845 -4.846380 +v -5.340396 2.264571 -4.714700 +v -5.385203 2.331627 -4.828739 +v -5.354808 2.286139 -4.780540 +v -5.420094 2.391587 -4.846380 +v -5.314407 2.285899 -4.714700 +v -5.371434 2.342926 -4.828739 +v -5.332750 2.304242 -4.780540 +v -5.417353 2.394927 -4.846380 +v -5.293078 2.311889 -4.714700 +v -5.360135 2.356695 -4.828739 +v -5.314647 2.326301 -4.780540 +v -5.415317 2.398736 -4.846380 +v -5.277230 2.341539 -4.714700 +v -5.351740 2.372402 -4.828739 +v -5.301196 2.351466 -4.780540 +v -5.414063 2.402869 -4.846380 +v -5.267470 2.373712 -4.714700 +v -5.346570 2.389445 -4.828739 +v -5.292913 2.378773 -4.780540 +vn -0.0000 -0.0000 -1.0000 +vn -0.9536 -0.3011 -0.0000 +vn -0.2964 0.9551 -0.0000 +vn 0.9596 0.2813 -0.0000 +vn 0.2858 -0.9583 -0.0000 +vn -0.9551 0.2964 -0.0000 +vn -0.3011 -0.9536 -0.0000 +vn 0.9551 -0.2964 -0.0000 +vn 0.3011 0.9536 -0.0000 +vn 0.9810 -0.0000 0.1939 +vn 1.0000 -0.0000 -0.0000 +vn 0.9808 0.1951 -0.0000 +vn 0.9622 0.1914 0.1939 +vn 0.3879 -0.0000 -0.9217 +vn 0.2010 -0.0000 -0.9796 +vn 0.1971 0.0392 -0.9796 +vn 0.3804 0.0757 -0.9217 +vn 0.9248 -0.0000 0.3805 +vn 0.9070 0.1804 0.3805 +vn 0.5598 -0.0000 -0.8286 +vn 0.5490 0.1092 -0.8286 +vn 0.8333 -0.0000 0.5528 +vn 0.8173 0.1626 0.5528 +vn 0.7101 -0.0000 -0.7041 +vn 0.6965 0.1385 -0.7041 +vn 0.7101 -0.0000 0.7041 +vn 0.6965 0.1385 0.7041 +vn 0.8333 -0.0000 -0.5528 +vn 0.8173 0.1626 -0.5528 +vn 0.5598 -0.0000 0.8286 +vn 0.5490 0.1092 0.8286 +vn 0.9248 -0.0000 -0.3805 +vn 0.9070 0.1804 -0.3805 +vn 0.3879 -0.0000 0.9217 +vn 0.3804 0.0757 0.9217 +vn 0.9810 -0.0000 -0.1939 +vn 0.9622 0.1914 -0.1939 +vn 0.2010 -0.0000 0.9796 +vn 0.1971 0.0392 0.9796 +vn -0.0000 -0.0000 1.0000 +vn 0.9063 0.3754 -0.1939 +vn 0.9239 0.3827 -0.0000 +vn 0.1857 0.0769 -0.9796 +vn 0.1857 0.0769 0.9796 +vn 0.9063 0.3754 0.1939 +vn 0.3584 0.1484 -0.9217 +vn 0.8544 0.3539 0.3805 +vn 0.5172 0.2142 -0.8286 +vn 0.7699 0.3189 0.5528 +vn 0.6561 0.2718 -0.7041 +vn 0.6561 0.2718 0.7041 +vn 0.7699 0.3189 -0.5528 +vn 0.5172 0.2142 0.8286 +vn 0.8544 0.3539 -0.3805 +vn 0.3584 0.1484 0.9217 +vn 0.6929 0.4630 0.5528 +vn 0.5905 0.3945 0.7041 +vn 0.5905 0.3945 -0.7041 +vn 0.6929 0.4630 -0.5528 +vn 0.4654 0.3110 0.8286 +vn 0.7689 0.5138 -0.3805 +vn 0.3225 0.2155 0.9217 +vn 0.8157 0.5450 -0.1939 +vn 0.1671 0.1116 0.9796 +vn 0.8315 0.5556 -0.0000 +vn 0.1671 0.1116 -0.9796 +vn 0.8157 0.5450 0.1939 +vn 0.3225 0.2155 -0.9217 +vn 0.7689 0.5138 0.3805 +vn 0.4654 0.3110 -0.8286 +vn 0.1421 0.1421 -0.9796 +vn 0.1421 0.1421 0.9796 +vn 0.7071 0.7071 -0.0000 +vn 0.6937 0.6937 0.1939 +vn 0.2743 0.2743 -0.9217 +vn 0.6539 0.6539 0.3805 +vn 0.3958 0.3958 -0.8286 +vn 0.5893 0.5893 0.5528 +vn 0.5021 0.5021 -0.7041 +vn 0.5021 0.5021 0.7041 +vn 0.5893 0.5893 -0.5528 +vn 0.3958 0.3958 0.8286 +vn 0.6539 0.6539 -0.3805 +vn 0.2743 0.2743 0.9217 +vn 0.6937 0.6937 -0.1939 +vn 0.3945 0.5905 -0.7041 +vn 0.4630 0.6929 -0.5528 +vn 0.3945 0.5905 0.7041 +vn 0.3110 0.4654 0.8286 +vn 0.5138 0.7689 -0.3805 +vn 0.2155 0.3225 0.9217 +vn 0.5450 0.8157 -0.1939 +vn 0.1117 0.1671 0.9796 +vn 0.5556 0.8315 -0.0000 +vn 0.1117 0.1671 -0.9796 +vn 0.5450 0.8157 0.1939 +vn 0.2155 0.3225 -0.9217 +vn 0.5138 0.7689 0.3805 +vn 0.3110 0.4654 -0.8286 +vn 0.4630 0.6929 0.5528 +vn 0.3827 0.9239 -0.0000 +vn 0.3754 0.9063 0.1939 +vn 0.0769 0.1857 -0.9796 +vn 0.1484 0.3584 -0.9217 +vn 0.3539 0.8544 0.3805 +vn 0.2142 0.5172 -0.8286 +vn 0.3189 0.7699 0.5528 +vn 0.2718 0.6561 -0.7041 +vn 0.2718 0.6561 0.7041 +vn 0.3189 0.7699 -0.5528 +vn 0.2142 0.5172 0.8286 +vn 0.3539 0.8544 -0.3805 +vn 0.1484 0.3584 0.9217 +vn 0.3754 0.9063 -0.1939 +vn 0.0769 0.1857 0.9796 +vn 0.1385 0.6965 0.7041 +vn 0.1092 0.5490 0.8286 +vn 0.1626 0.8173 -0.5528 +vn 0.1804 0.9070 -0.3805 +vn 0.0757 0.3804 0.9217 +vn 0.1914 0.9622 -0.1939 +vn 0.0392 0.1971 0.9796 +vn 0.1951 0.9808 -0.0000 +vn 0.0392 0.1971 -0.9796 +vn 0.1914 0.9622 0.1939 +vn 0.0757 0.3804 -0.9217 +vn 0.1804 0.9070 0.3805 +vn 0.1092 0.5490 -0.8286 +vn 0.1626 0.8173 0.5528 +vn 0.1385 0.6965 -0.7041 +vn -0.0000 0.9810 0.1939 +vn -0.0000 0.9248 0.3805 +vn -0.0000 0.3879 -0.9217 +vn -0.0000 0.5598 -0.8286 +vn -0.0000 0.8333 0.5528 +vn -0.0000 0.7101 -0.7041 +vn -0.0000 0.7101 0.7041 +vn -0.0000 0.8333 -0.5528 +vn -0.0000 0.5598 0.8286 +vn -0.0000 0.9248 -0.3805 +vn -0.0000 0.3879 0.9217 +vn -0.0000 0.9810 -0.1939 +vn -0.0000 0.2010 0.9796 +vn -0.0000 1.0000 -0.0000 +vn -0.0000 0.2010 -0.9796 +vn -0.1092 0.5490 0.8286 +vn -0.0757 0.3804 0.9217 +vn -0.1804 0.9070 -0.3805 +vn -0.1914 0.9622 -0.1939 +vn -0.0392 0.1971 0.9796 +vn -0.1951 0.9808 -0.0000 +vn -0.0392 0.1971 -0.9796 +vn -0.1914 0.9622 0.1939 +vn -0.0757 0.3804 -0.9217 +vn -0.1804 0.9070 0.3805 +vn -0.1092 0.5490 -0.8286 +vn -0.1626 0.8173 0.5528 +vn -0.1385 0.6965 -0.7041 +vn -0.1385 0.6965 0.7041 +vn -0.1626 0.8173 -0.5528 +vn -0.1484 0.3584 -0.9217 +vn -0.2142 0.5172 -0.8286 +vn -0.3539 0.8544 0.3805 +vn -0.3189 0.7699 0.5528 +vn -0.2718 0.6561 -0.7041 +vn -0.2718 0.6561 0.7041 +vn -0.3189 0.7699 -0.5528 +vn -0.2142 0.5172 0.8286 +vn -0.3539 0.8544 -0.3805 +vn -0.1484 0.3584 0.9217 +vn -0.3754 0.9063 -0.1939 +vn -0.0769 0.1857 0.9796 +vn -0.3827 0.9239 -0.0000 +vn -0.0769 0.1857 -0.9796 +vn -0.3754 0.9063 0.1939 +vn -0.5138 0.7689 -0.3805 +vn -0.5450 0.8157 -0.1939 +vn -0.2155 0.3225 0.9217 +vn -0.1117 0.1671 0.9796 +vn -0.5556 0.8315 -0.0000 +vn -0.1117 0.1671 -0.9796 +vn -0.5450 0.8157 0.1939 +vn -0.2155 0.3225 -0.9217 +vn -0.5138 0.7689 0.3805 +vn -0.3110 0.4654 -0.8286 +vn -0.4630 0.6929 0.5528 +vn -0.3945 0.5905 -0.7041 +vn -0.3945 0.5905 0.7041 +vn -0.4630 0.6929 -0.5528 +vn -0.3110 0.4654 0.8286 +vn -0.6539 0.6539 0.3805 +vn -0.5893 0.5893 0.5528 +vn -0.3958 0.3958 -0.8286 +vn -0.5021 0.5021 -0.7041 +vn -0.5021 0.5021 0.7041 +vn -0.5893 0.5893 -0.5528 +vn -0.3958 0.3958 0.8286 +vn -0.6539 0.6539 -0.3805 +vn -0.2743 0.2743 0.9217 +vn -0.6937 0.6937 -0.1939 +vn -0.1421 0.1421 0.9796 +vn -0.7071 0.7071 -0.0000 +vn -0.1421 0.1421 -0.9796 +vn -0.6937 0.6937 0.1939 +vn -0.2743 0.2743 -0.9217 +vn -0.3225 0.2155 0.9217 +vn -0.1671 0.1117 0.9796 +vn -0.8157 0.5450 -0.1939 +vn -0.8315 0.5556 -0.0000 +vn -0.1671 0.1116 -0.9796 +vn -0.8157 0.5450 0.1939 +vn -0.3225 0.2155 -0.9217 +vn -0.7689 0.5138 0.3805 +vn -0.4654 0.3110 -0.8286 +vn -0.6929 0.4630 0.5528 +vn -0.5905 0.3945 -0.7041 +vn -0.5905 0.3945 0.7041 +vn -0.6929 0.4630 -0.5528 +vn -0.4654 0.3110 0.8286 +vn -0.7689 0.5138 -0.3805 +vn -0.5172 0.2142 -0.8286 +vn -0.6561 0.2718 -0.7041 +vn -0.7699 0.3189 0.5528 +vn -0.6561 0.2718 0.7041 +vn -0.7699 0.3189 -0.5528 +vn -0.5172 0.2142 0.8286 +vn -0.8544 0.3539 -0.3805 +vn -0.3584 0.1484 0.9217 +vn -0.9063 0.3754 -0.1939 +vn -0.1857 0.0769 0.9796 +vn -0.9239 0.3827 -0.0000 +vn -0.1857 0.0769 -0.9796 +vn -0.9063 0.3754 0.1939 +vn -0.3584 0.1484 -0.9217 +vn -0.8544 0.3539 0.3805 +vn -0.9622 0.1914 -0.1939 +vn -0.9808 0.1951 -0.0000 +vn -0.1971 0.0392 -0.9796 +vn -0.1971 0.0392 0.9796 +vn -0.9622 0.1914 0.1939 +vn -0.3804 0.0757 -0.9217 +vn -0.9070 0.1804 0.3805 +vn -0.5490 0.1092 -0.8286 +vn -0.8173 0.1626 0.5528 +vn -0.6965 0.1385 -0.7041 +vn -0.6965 0.1385 0.7041 +vn -0.8173 0.1626 -0.5528 +vn -0.5490 0.1092 0.8286 +vn -0.9070 0.1804 -0.3805 +vn -0.3804 0.0757 0.9217 +vn -0.8333 -0.0000 0.5528 +vn -0.7101 -0.0000 0.7041 +vn -0.7101 -0.0000 -0.7041 +vn -0.8333 -0.0000 -0.5528 +vn -0.5598 -0.0000 0.8286 +vn -0.9248 -0.0000 -0.3805 +vn -0.3879 -0.0000 0.9217 +vn -0.9810 -0.0000 -0.1939 +vn -0.2010 -0.0000 0.9796 +vn -1.0000 -0.0000 -0.0000 +vn -0.2010 -0.0000 -0.9796 +vn -0.9810 -0.0000 0.1939 +vn -0.3879 -0.0000 -0.9217 +vn -0.9248 -0.0000 0.3805 +vn -0.5598 -0.0000 -0.8286 +vn -0.1971 -0.0392 0.9796 +vn -0.9808 -0.1951 -0.0000 +vn -0.9622 -0.1914 0.1939 +vn -0.1971 -0.0392 -0.9796 +vn -0.3804 -0.0757 -0.9217 +vn -0.9070 -0.1804 0.3805 +vn -0.5490 -0.1092 -0.8286 +vn -0.8173 -0.1626 0.5528 +vn -0.6965 -0.1385 -0.7041 +vn -0.6965 -0.1385 0.7041 +vn -0.8173 -0.1626 -0.5528 +vn -0.5490 -0.1092 0.8286 +vn -0.9070 -0.1804 -0.3805 +vn -0.3804 -0.0757 0.9217 +vn -0.9622 -0.1914 -0.1939 +vn -0.6561 -0.2718 0.7041 +vn -0.5172 -0.2142 0.8286 +vn -0.7699 -0.3189 -0.5528 +vn -0.8544 -0.3539 -0.3805 +vn -0.3584 -0.1484 0.9217 +vn -0.9063 -0.3754 -0.1939 +vn -0.1857 -0.0769 0.9796 +vn -0.9239 -0.3827 -0.0000 +vn -0.1857 -0.0769 -0.9796 +vn -0.9063 -0.3754 0.1939 +vn -0.3584 -0.1484 -0.9217 +vn -0.8544 -0.3539 0.3805 +vn -0.5172 -0.2142 -0.8286 +vn -0.7699 -0.3189 0.5528 +vn -0.6561 -0.2718 -0.7041 +vn -0.1671 -0.1117 -0.9796 +vn -0.3225 -0.2155 -0.9217 +vn -0.8157 -0.5450 0.1939 +vn -0.7689 -0.5138 0.3805 +vn -0.4654 -0.3110 -0.8286 +vn -0.6929 -0.4630 0.5528 +vn -0.5905 -0.3945 -0.7041 +vn -0.5905 -0.3945 0.7041 +vn -0.6929 -0.4630 -0.5528 +vn -0.4654 -0.3110 0.8286 +vn -0.7689 -0.5138 -0.3805 +vn -0.3225 -0.2155 0.9217 +vn -0.8157 -0.5450 -0.1939 +vn -0.1671 -0.1117 0.9796 +vn -0.8315 -0.5556 -0.0000 +vn -0.5893 -0.5893 -0.5528 +vn -0.6539 -0.6539 -0.3805 +vn -0.3958 -0.3958 0.8286 +vn -0.2743 -0.2743 0.9217 +vn -0.6937 -0.6937 -0.1939 +vn -0.1421 -0.1421 0.9796 +vn -0.7071 -0.7071 -0.0000 +vn -0.1421 -0.1421 -0.9796 +vn -0.6937 -0.6937 0.1939 +vn -0.2743 -0.2743 -0.9217 +vn -0.6539 -0.6539 0.3805 +vn -0.3958 -0.3958 -0.8286 +vn -0.5893 -0.5893 0.5528 +vn -0.5021 -0.5021 -0.7041 +vn -0.5021 -0.5021 0.7041 +vn -0.5450 -0.8157 0.1939 +vn -0.5138 -0.7689 0.3805 +vn -0.2155 -0.3225 -0.9217 +vn -0.3110 -0.4654 -0.8286 +vn -0.4630 -0.6929 0.5528 +vn -0.3945 -0.5905 -0.7041 +vn -0.3945 -0.5905 0.7041 +vn -0.4630 -0.6929 -0.5528 +vn -0.3110 -0.4654 0.8286 +vn -0.5138 -0.7689 -0.3805 +vn -0.2155 -0.3225 0.9217 +vn -0.5450 -0.8157 -0.1939 +vn -0.1117 -0.1671 0.9796 +vn -0.5556 -0.8315 -0.0000 +vn -0.1117 -0.1671 -0.9796 +vn -0.2142 -0.5172 0.8286 +vn -0.1484 -0.3584 0.9217 +vn -0.3539 -0.8544 -0.3805 +vn -0.3754 -0.9063 -0.1939 +vn -0.0769 -0.1857 0.9796 +vn -0.3827 -0.9239 -0.0000 +vn -0.0769 -0.1857 -0.9796 +vn -0.3754 -0.9063 0.1939 +vn -0.1484 -0.3584 -0.9217 +vn -0.3539 -0.8544 0.3805 +vn -0.2142 -0.5172 -0.8286 +vn -0.3189 -0.7699 0.5528 +vn -0.2718 -0.6561 -0.7041 +vn -0.2718 -0.6561 0.7041 +vn -0.3189 -0.7699 -0.5528 +vn -0.0757 -0.3804 -0.9217 +vn -0.1092 -0.5490 -0.8286 +vn -0.1804 -0.9070 0.3805 +vn -0.1626 -0.8173 0.5528 +vn -0.1385 -0.6965 -0.7041 +vn -0.1385 -0.6965 0.7041 +vn -0.1626 -0.8173 -0.5528 +vn -0.1092 -0.5490 0.8286 +vn -0.1804 -0.9070 -0.3805 +vn -0.0757 -0.3804 0.9217 +vn -0.1914 -0.9622 -0.1939 +vn -0.0392 -0.1971 0.9796 +vn -0.1951 -0.9808 -0.0000 +vn -0.0392 -0.1971 -0.9796 +vn -0.1914 -0.9622 0.1939 +vn -0.0000 -0.9248 -0.3805 +vn -0.0000 -0.9810 -0.1939 +vn -0.0000 -0.3879 0.9217 +vn -0.0000 -0.2010 0.9796 +vn -0.0000 -1.0000 -0.0000 +vn -0.0000 -0.2010 -0.9796 +vn -0.0000 -0.9810 0.1939 +vn -0.0000 -0.3879 -0.9217 +vn -0.0000 -0.9248 0.3805 +vn -0.0000 -0.5598 -0.8286 +vn -0.0000 -0.8333 0.5528 +vn -0.0000 -0.7101 -0.7041 +vn -0.0000 -0.7101 0.7041 +vn -0.0000 -0.8333 -0.5528 +vn -0.0000 -0.5598 0.8286 +vn 0.1804 -0.9070 0.3805 +vn 0.1626 -0.8173 0.5528 +vn 0.1092 -0.5490 -0.8286 +vn 0.1385 -0.6965 -0.7041 +vn 0.1385 -0.6965 0.7041 +vn 0.1626 -0.8173 -0.5528 +vn 0.1092 -0.5490 0.8286 +vn 0.1804 -0.9070 -0.3805 +vn 0.0757 -0.3804 0.9217 +vn 0.1914 -0.9622 -0.1939 +vn 0.0392 -0.1971 0.9796 +vn 0.1951 -0.9808 -0.0000 +vn 0.0392 -0.1971 -0.9796 +vn 0.1914 -0.9622 0.1939 +vn 0.0757 -0.3804 -0.9217 +vn 0.1484 -0.3584 0.9217 +vn 0.0769 -0.1857 0.9796 +vn 0.3754 -0.9063 -0.1939 +vn 0.3827 -0.9239 -0.0000 +vn 0.0769 -0.1857 -0.9796 +vn 0.3754 -0.9063 0.1939 +vn 0.1484 -0.3584 -0.9217 +vn 0.3539 -0.8544 0.3805 +vn 0.2142 -0.5172 -0.8286 +vn 0.3189 -0.7699 0.5528 +vn 0.2718 -0.6561 -0.7041 +vn 0.2718 -0.6561 0.7041 +vn 0.3189 -0.7699 -0.5528 +vn 0.2142 -0.5172 0.8286 +vn 0.3539 -0.8544 -0.3805 +vn 0.4630 -0.6929 0.5528 +vn 0.3945 -0.5905 0.7041 +vn 0.3945 -0.5905 -0.7041 +vn 0.4630 -0.6929 -0.5528 +vn 0.3110 -0.4654 0.8286 +vn 0.5138 -0.7689 -0.3805 +vn 0.2155 -0.3225 0.9217 +vn 0.5450 -0.8157 -0.1939 +vn 0.1117 -0.1671 0.9796 +vn 0.5556 -0.8315 -0.0000 +vn 0.1117 -0.1671 -0.9796 +vn 0.5450 -0.8157 0.1939 +vn 0.2155 -0.3225 -0.9217 +vn 0.5138 -0.7689 0.3805 +vn 0.3110 -0.4654 -0.8286 +vn 0.1421 -0.1421 -0.9796 +vn 0.1421 -0.1421 0.9796 +vn 0.7071 -0.7071 -0.0000 +vn 0.6937 -0.6937 0.1939 +vn 0.2743 -0.2743 -0.9217 +vn 0.6539 -0.6539 0.3805 +vn 0.3958 -0.3958 -0.8286 +vn 0.5893 -0.5893 0.5528 +vn 0.5021 -0.5021 -0.7041 +vn 0.5021 -0.5021 0.7041 +vn 0.5893 -0.5893 -0.5528 +vn 0.3958 -0.3958 0.8286 +vn 0.6539 -0.6539 -0.3805 +vn 0.2743 -0.2743 0.9217 +vn 0.6937 -0.6937 -0.1939 +vn 0.5905 -0.3945 -0.7041 +vn 0.6929 -0.4630 -0.5528 +vn 0.5905 -0.3945 0.7041 +vn 0.4654 -0.3110 0.8286 +vn 0.7689 -0.5138 -0.3805 +vn 0.3225 -0.2155 0.9217 +vn 0.8157 -0.5450 -0.1939 +vn 0.1671 -0.1117 0.9796 +vn 0.8315 -0.5556 -0.0000 +vn 0.1671 -0.1117 -0.9796 +vn 0.8157 -0.5450 0.1939 +vn 0.3225 -0.2155 -0.9217 +vn 0.7689 -0.5138 0.3805 +vn 0.4654 -0.3110 -0.8286 +vn 0.6929 -0.4630 0.5528 +vn 0.9239 -0.3827 -0.0000 +vn 0.9063 -0.3754 0.1939 +vn 0.1857 -0.0769 -0.9796 +vn 0.3584 -0.1484 -0.9217 +vn 0.8544 -0.3539 0.3805 +vn 0.5172 -0.2142 -0.8286 +vn 0.7699 -0.3189 0.5528 +vn 0.6561 -0.2718 -0.7041 +vn 0.6561 -0.2718 0.7041 +vn 0.7699 -0.3189 -0.5528 +vn 0.5172 -0.2142 0.8286 +vn 0.8544 -0.3539 -0.3805 +vn 0.3584 -0.1484 0.9217 +vn 0.9063 -0.3754 -0.1939 +vn 0.1857 -0.0769 0.9796 +vn 0.6965 -0.1385 0.7041 +vn 0.5490 -0.1092 0.8286 +vn 0.8173 -0.1626 -0.5528 +vn 0.9070 -0.1804 -0.3805 +vn 0.3804 -0.0757 0.9217 +vn 0.9622 -0.1914 -0.1939 +vn 0.1971 -0.0392 0.9796 +vn 0.9808 -0.1951 -0.0000 +vn 0.1971 -0.0392 -0.9796 +vn 0.9622 -0.1914 0.1939 +vn 0.3804 -0.0757 -0.9217 +vn 0.9070 -0.1804 0.3805 +vn 0.5490 -0.1092 -0.8286 +vn 0.8173 -0.1626 0.5528 +vn 0.6965 -0.1385 -0.7041 +vn 0.6052 0.4044 0.6857 +vn 0.8299 0.5545 -0.0608 +vn 0.7058 0.7058 -0.0608 +vn 0.5147 0.5147 0.6857 +vn 0.9222 0.3820 -0.0608 +vn 0.8959 0.3711 -0.2443 +vn 0.8063 0.5387 -0.2443 +vn 0.7279 -0.0000 0.6857 +vn 0.9981 -0.0000 -0.0608 +vn 0.9790 0.1947 -0.0608 +vn 0.7139 0.1420 0.6857 +vn 0.6725 0.2785 0.6857 +vn 0.4044 0.6052 0.6857 +vn 0.2785 0.6725 0.6857 +vn 0.1420 0.7139 0.6857 +vn -0.0000 0.7279 0.6857 +vn -0.1420 0.7139 0.6857 +vn -0.2785 0.6725 0.6857 +vn -0.4044 0.6052 0.6857 +vn -0.5147 0.5147 0.6857 +vn -0.6052 0.4044 0.6857 +vn -0.6725 0.2785 0.6857 +vn -0.7139 0.1420 0.6857 +vn -0.7279 -0.0000 0.6857 +vn -0.7139 -0.1420 0.6857 +vn -0.6725 -0.2785 0.6857 +vn -0.6052 -0.4044 0.6857 +vn -0.5147 -0.5147 0.6857 +vn -0.4044 -0.6052 0.6857 +vn -0.2785 -0.6725 0.6857 +vn -0.1420 -0.7139 0.6857 +vn -0.0000 -0.7279 0.6857 +vn 0.1420 -0.7139 0.6857 +vn 0.2785 -0.6725 0.6857 +vn 0.4044 -0.6052 0.6857 +vn 0.5147 -0.5147 0.6857 +vn 0.6052 -0.4044 0.6857 +vn 0.6725 -0.2785 0.6857 +vn 0.7139 -0.1420 0.6857 +vn 0.8299 -0.5545 -0.0608 +vn 0.9222 -0.3820 -0.0608 +vn 0.5545 0.8299 -0.0608 +vn 0.3820 0.9222 -0.0608 +vn 0.7058 -0.7058 -0.0608 +vn 0.1947 0.9790 -0.0608 +vn 0.5545 -0.8299 -0.0608 +vn -0.0000 0.9982 -0.0608 +vn 0.3820 -0.9222 -0.0608 +vn -0.1947 0.9790 -0.0608 +vn 0.1947 -0.9790 -0.0608 +vn -0.3820 0.9222 -0.0608 +vn -0.0000 -0.9982 -0.0608 +vn -0.5545 0.8299 -0.0608 +vn -0.1947 -0.9790 -0.0608 +vn -0.0000 0.9981 -0.0608 +vn -0.7058 0.7058 -0.0608 +vn -0.3820 -0.9222 -0.0608 +vn -0.8299 0.5545 -0.0608 +vn -0.5545 -0.8299 -0.0608 +vn -0.9222 0.3820 -0.0608 +vn -0.7058 -0.7058 -0.0608 +vn -0.9790 0.1947 -0.0608 +vn -0.8299 -0.5545 -0.0608 +vn -0.9982 -0.0000 -0.0608 +vn -0.9222 -0.3820 -0.0608 +vn -0.9790 -0.1947 -0.0608 +vn 0.9697 -0.0000 -0.2443 +vn 0.9511 0.1892 -0.2443 +vn 0.9790 -0.1947 -0.0608 +vn 0.1892 0.9511 -0.2443 +vn -0.0000 0.9697 -0.2443 +vn -0.5387 -0.8063 -0.2443 +vn -0.3711 -0.8959 -0.2443 +vn -0.0000 -0.9697 -0.2443 +vn 0.1892 -0.9511 -0.2443 +vn 0.1303 0.0259 -0.9911 +vn 0.1328 -0.0000 -0.9911 +vn 0.1303 -0.0259 -0.9911 +vn 0.1227 -0.0508 -0.9911 +vn 0.1104 -0.0738 -0.9911 +vn 0.0939 -0.0939 -0.9911 +vn 0.0738 -0.1105 -0.9911 +vn 0.0508 -0.1227 -0.9911 +vn 0.0259 -0.1303 -0.9911 +vn -0.0000 -0.1328 -0.9911 +vn -0.0259 -0.1303 -0.9911 +vn -0.0508 -0.1227 -0.9911 +vn -0.0738 -0.1104 -0.9911 +vn -0.0939 -0.0939 -0.9911 +vn -0.1104 -0.0738 -0.9911 +vn -0.1227 -0.0509 -0.9911 +vn -0.1303 -0.0259 -0.9911 +vn -0.1328 -0.0000 -0.9911 +vn -0.1303 0.0259 -0.9911 +vn -0.1227 0.0508 -0.9911 +vn -0.1104 0.0738 -0.9911 +vn -0.0939 0.0939 -0.9911 +vn -0.0738 0.1104 -0.9911 +vn -0.0508 0.1227 -0.9911 +vn -0.0259 0.1303 -0.9911 +vn -0.0000 0.1328 -0.9911 +vn 0.0259 0.1303 -0.9911 +vn 0.0508 0.1227 -0.9911 +vn 0.0738 0.1104 -0.9911 +vn 0.0939 0.0939 -0.9911 +vn 0.1104 0.0738 -0.9911 +vn 0.1227 0.0508 -0.9911 +vn 0.8959 -0.3711 -0.2443 +vn 0.9511 -0.1892 -0.2443 +vn -0.1892 0.9511 -0.2443 +vn -0.3711 0.8959 -0.2443 +vn 0.3711 0.8959 -0.2443 +vn -0.8959 0.3711 -0.2443 +vn -0.9511 0.1892 -0.2443 +vn -0.6857 0.6857 -0.2443 +vn -0.8063 0.5387 -0.2443 +vn -0.8063 -0.5387 -0.2443 +vn -0.6857 -0.6857 -0.2443 +vn 0.5387 0.8063 -0.2443 +vn 0.3711 -0.8959 -0.2443 +vn 0.5387 -0.8063 -0.2443 +vn 0.6857 -0.6857 -0.2443 +vn 0.0738 -0.1104 -0.9911 +vn -0.1227 -0.0508 -0.9911 +vn -0.9697 -0.0000 -0.2443 +vn -0.9511 -0.1892 -0.2443 +vn -0.1892 -0.9511 -0.2443 +vn 0.6857 0.6857 -0.2443 +vn -0.5387 0.8063 -0.2443 +vn -0.8959 -0.3711 -0.2443 +vn 0.8063 -0.5387 -0.2443 +vn -0.5821 -0.5821 -0.5677 +vn -0.4574 -0.6845 -0.5677 +vn -0.3386 -0.3386 -0.8779 +vn -0.2660 -0.3982 -0.8779 +vn 0.8233 -0.0000 -0.5677 +vn 0.8074 0.1606 -0.5677 +vn 0.4788 -0.0000 -0.8779 +vn 0.4697 0.0934 -0.8779 +vn -0.1606 0.8074 -0.5677 +vn -0.3150 0.7606 -0.5677 +vn -0.0934 0.4697 -0.8779 +vn -0.1832 0.4424 -0.8779 +vn 0.7606 0.3150 -0.5677 +vn 0.4424 0.1833 -0.8779 +vn 0.6845 0.4574 -0.5677 +vn 0.3981 0.2660 -0.8779 +vn -0.6845 -0.4574 -0.5677 +vn -0.3982 -0.2660 -0.8779 +vn 0.5821 0.5821 -0.5677 +vn 0.3386 0.3386 -0.8779 +vn -0.0000 0.8232 -0.5677 +vn -0.0000 0.4789 -0.8779 +vn 0.4574 0.6845 -0.5677 +vn 0.2660 0.3982 -0.8779 +vn 0.3150 0.7606 -0.5677 +vn 0.1832 0.4424 -0.8779 +vn -0.7606 -0.3150 -0.5677 +vn -0.4424 -0.1833 -0.8779 +vn 0.1606 0.8074 -0.5677 +vn 0.0934 0.4697 -0.8779 +vn -0.0000 0.8233 -0.5677 +vn -0.8074 -0.1606 -0.5677 +vn -0.4697 -0.0934 -0.8779 +vn -0.4574 0.6845 -0.5677 +vn -0.2660 0.3982 -0.8779 +vn -0.5821 0.5821 -0.5677 +vn -0.3386 0.3386 -0.8779 +vn -0.8233 -0.0000 -0.5677 +vn -0.4788 -0.0000 -0.8779 +vn -0.6845 0.4574 -0.5677 +vn -0.3982 0.2660 -0.8779 +vn -0.7606 0.3150 -0.5677 +vn -0.4424 0.1832 -0.8779 +vn -0.8074 0.1606 -0.5677 +vn -0.4697 0.0934 -0.8779 +vn -0.8232 -0.0000 -0.5677 +vn -0.4789 -0.0000 -0.8779 +vn -0.4424 -0.1832 -0.8779 +vn -0.4424 0.1833 -0.8779 +vn -0.2660 -0.3981 -0.8779 +vn -0.3150 -0.7606 -0.5677 +vn -0.1832 -0.4424 -0.8779 +vn 0.7606 0.3151 -0.5677 +vn -0.1606 -0.8074 -0.5677 +vn -0.0934 -0.4697 -0.8779 +vn -0.0000 -0.8233 -0.5677 +vn -0.0000 -0.4789 -0.8779 +vn 0.1606 -0.8074 -0.5677 +vn 0.0934 -0.4696 -0.8779 +vn 0.3150 -0.7606 -0.5677 +vn 0.1833 -0.4424 -0.8779 +vn 0.4574 -0.6845 -0.5677 +vn 0.2660 -0.3982 -0.8779 +vn 0.5821 -0.5821 -0.5677 +vn 0.3386 -0.3386 -0.8779 +vn 0.6845 -0.4574 -0.5677 +vn 0.3981 -0.2660 -0.8779 +vn 0.7606 -0.3150 -0.5677 +vn 0.4424 -0.1832 -0.8779 +vn 0.8074 -0.1606 -0.5677 +vn 0.4696 -0.0934 -0.8779 +vn -0.1833 -0.4424 -0.8779 +vn -0.0934 -0.4696 -0.8779 +vn 0.0934 -0.4697 -0.8779 +vn 0.1832 -0.4424 -0.8779 +vn 0.4424 -0.1833 -0.8779 +vn 0.4697 -0.0934 -0.8779 +vn 0.0934 0.4696 -0.8779 +vn 0.2660 0.3981 -0.8779 +vn -0.3981 0.2660 -0.8779 +vn 0.4424 0.1832 -0.8779 +vn -0.2660 0.3981 -0.8779 +vn 0.8232 -0.0000 -0.5677 +vn 0.4789 -0.0000 -0.8779 +vn -0.0000 -0.8232 -0.5677 +vn 0.3982 -0.2660 -0.8779 +vt 0.000000 0.000000 +vt 0.750000 0.437500 +vt 0.750000 0.500000 +vt 0.718750 0.500000 +vt 0.718750 0.437500 +vt 0.750000 0.875000 +vt 0.750000 0.937500 +vt 0.718750 0.937500 +vt 0.718750 0.875000 +vt 0.750000 0.375000 +vt 0.718750 0.375000 +vt 0.750000 0.812500 +vt 0.718750 0.812500 +vt 0.750000 0.312500 +vt 0.718750 0.312500 +vt 0.750000 0.750000 +vt 0.718750 0.750000 +vt 0.750000 0.250000 +vt 0.718750 0.250000 +vt 0.750000 0.687500 +vt 0.718750 0.687500 +vt 0.750000 0.187500 +vt 0.718750 0.187500 +vt 0.750000 0.625000 +vt 0.718750 0.625000 +vt 0.750000 0.125000 +vt 0.718750 0.125000 +vt 0.750000 0.562500 +vt 0.718750 0.562500 +vt 0.750000 0.062500 +vt 0.718750 0.062500 +vt 0.734375 1.000000 +vt 0.734375 0.000000 +vt 0.687500 0.562500 +vt 0.687500 0.500000 +vt 0.703125 1.000000 +vt 0.687500 0.937500 +vt 0.703125 0.000000 +vt 0.687500 0.062500 +vt 0.687500 0.437500 +vt 0.687500 0.875000 +vt 0.687500 0.375000 +vt 0.687500 0.812500 +vt 0.687500 0.312500 +vt 0.687500 0.750000 +vt 0.687500 0.250000 +vt 0.687500 0.687500 +vt 0.687500 0.187500 +vt 0.687500 0.625000 +vt 0.687500 0.125000 +vt 0.656250 0.312500 +vt 0.656250 0.250000 +vt 0.656250 0.750000 +vt 0.656250 0.687500 +vt 0.656250 0.187500 +vt 0.656250 0.625000 +vt 0.656250 0.125000 +vt 0.656250 0.562500 +vt 0.656250 0.062500 +vt 0.656250 0.500000 +vt 0.671875 1.000000 +vt 0.656250 0.937500 +vt 0.671875 0.000000 +vt 0.656250 0.437500 +vt 0.656250 0.875000 +vt 0.656250 0.375000 +vt 0.656250 0.812500 +vt 0.640625 1.000000 +vt 0.625000 0.937500 +vt 0.640625 0.000000 +vt 0.625000 0.062500 +vt 0.625000 0.500000 +vt 0.625000 0.437500 +vt 0.625000 0.875000 +vt 0.625000 0.375000 +vt 0.625000 0.812500 +vt 0.625000 0.312500 +vt 0.625000 0.750000 +vt 0.625000 0.250000 +vt 0.625000 0.687500 +vt 0.625000 0.187500 +vt 0.625000 0.625000 +vt 0.625000 0.125000 +vt 0.625000 0.562500 +vt 0.593750 0.750000 +vt 0.593750 0.687500 +vt 0.593750 0.250000 +vt 0.593750 0.187500 +vt 0.593750 0.625000 +vt 0.593750 0.125000 +vt 0.593750 0.562500 +vt 0.593750 0.062500 +vt 0.593750 0.500000 +vt 0.609375 1.000000 +vt 0.593750 0.937500 +vt 0.609375 0.000000 +vt 0.593750 0.437500 +vt 0.593750 0.875000 +vt 0.593750 0.375000 +vt 0.593750 0.812500 +vt 0.593750 0.312500 +vt 0.562500 0.500000 +vt 0.562500 0.437500 +vt 0.562500 0.937500 +vt 0.562500 0.875000 +vt 0.562500 0.375000 +vt 0.562500 0.812500 +vt 0.562500 0.312500 +vt 0.562500 0.750000 +vt 0.562500 0.250000 +vt 0.562500 0.687500 +vt 0.562500 0.187500 +vt 0.562500 0.625000 +vt 0.562500 0.125000 +vt 0.562500 0.562500 +vt 0.562500 0.062500 +vt 0.578125 1.000000 +vt 0.578125 0.000000 +vt 0.531250 0.250000 +vt 0.531250 0.187500 +vt 0.531250 0.687500 +vt 0.531250 0.625000 +vt 0.531250 0.125000 +vt 0.531250 0.562500 +vt 0.531250 0.062500 +vt 0.531250 0.500000 +vt 0.546875 1.000000 +vt 0.531250 0.937500 +vt 0.546875 0.000000 +vt 0.531250 0.437500 +vt 0.531250 0.875000 +vt 0.531250 0.375000 +vt 0.531250 0.812500 +vt 0.531250 0.312500 +vt 0.531250 0.750000 +vt 0.500000 0.437500 +vt 0.500000 0.375000 +vt 0.500000 0.875000 +vt 0.500000 0.812500 +vt 0.500000 0.312500 +vt 0.500000 0.750000 +vt 0.500000 0.250000 +vt 0.500000 0.687500 +vt 0.500000 0.187500 +vt 0.500000 0.625000 +vt 0.500000 0.125000 +vt 0.500000 0.562500 +vt 0.500000 0.062500 +vt 0.500000 0.500000 +vt 0.515625 1.000000 +vt 0.500000 0.937500 +vt 0.515625 0.000000 +vt 0.468750 0.187500 +vt 0.468750 0.125000 +vt 0.468750 0.625000 +vt 0.468750 0.562500 +vt 0.468750 0.062500 +vt 0.468750 0.500000 +vt 0.484375 1.000000 +vt 0.468750 0.937500 +vt 0.484375 0.000000 +vt 0.468750 0.437500 +vt 0.468750 0.875000 +vt 0.468750 0.375000 +vt 0.468750 0.812500 +vt 0.468750 0.312500 +vt 0.468750 0.750000 +vt 0.468750 0.250000 +vt 0.468750 0.687500 +vt 0.437500 0.875000 +vt 0.437500 0.812500 +vt 0.437500 0.375000 +vt 0.437500 0.312500 +vt 0.437500 0.750000 +vt 0.437500 0.250000 +vt 0.437500 0.687500 +vt 0.437500 0.187500 +vt 0.437500 0.625000 +vt 0.437500 0.125000 +vt 0.437500 0.562500 +vt 0.437500 0.062500 +vt 0.437500 0.500000 +vt 0.453125 1.000000 +vt 0.437500 0.937500 +vt 0.453125 0.000000 +vt 0.437500 0.437500 +vt 0.406250 0.625000 +vt 0.406250 0.562500 +vt 0.406250 0.125000 +vt 0.406250 0.062500 +vt 0.406250 0.500000 +vt 0.421875 1.000000 +vt 0.406250 0.937500 +vt 0.421875 0.000000 +vt 0.406250 0.437500 +vt 0.406250 0.875000 +vt 0.406250 0.375000 +vt 0.406250 0.812500 +vt 0.406250 0.312500 +vt 0.406250 0.750000 +vt 0.406250 0.250000 +vt 0.406250 0.687500 +vt 0.406250 0.187500 +vt 0.375000 0.375000 +vt 0.375000 0.312500 +vt 0.375000 0.812500 +vt 0.375000 0.750000 +vt 0.375000 0.250000 +vt 0.375000 0.687500 +vt 0.375000 0.187500 +vt 0.375000 0.625000 +vt 0.375000 0.125000 +vt 0.375000 0.562500 +vt 0.375000 0.062500 +vt 0.375000 0.500000 +vt 0.390625 1.000000 +vt 0.375000 0.937500 +vt 0.390625 0.000000 +vt 0.375000 0.437500 +vt 0.375000 0.875000 +vt 0.343750 0.125000 +vt 0.343750 0.062500 +vt 0.343750 0.562500 +vt 0.343750 0.500000 +vt 0.359375 1.000000 +vt 0.343750 0.937500 +vt 0.359375 0.000000 +vt 0.343750 0.437500 +vt 0.343750 0.875000 +vt 0.343750 0.375000 +vt 0.343750 0.812500 +vt 0.343750 0.312500 +vt 0.343750 0.750000 +vt 0.343750 0.250000 +vt 0.343750 0.687500 +vt 0.343750 0.187500 +vt 0.343750 0.625000 +vt 0.312500 0.812500 +vt 0.312500 0.750000 +vt 0.312500 0.312500 +vt 0.312500 0.250000 +vt 0.312500 0.687500 +vt 0.312500 0.187500 +vt 0.312500 0.625000 +vt 0.312500 0.125000 +vt 0.312500 0.562500 +vt 0.312500 0.062500 +vt 0.312500 0.500000 +vt 0.328125 1.000000 +vt 0.312500 0.937500 +vt 0.328125 0.000000 +vt 0.312500 0.437500 +vt 0.312500 0.875000 +vt 0.312500 0.375000 +vt 0.281250 0.562500 +vt 0.281250 0.500000 +vt 0.296875 1.000000 +vt 0.281250 0.937500 +vt 0.296875 0.000000 +vt 0.281250 0.062500 +vt 0.281250 0.437500 +vt 0.281250 0.875000 +vt 0.281250 0.375000 +vt 0.281250 0.812500 +vt 0.281250 0.312500 +vt 0.281250 0.750000 +vt 0.281250 0.250000 +vt 0.281250 0.687500 +vt 0.281250 0.187500 +vt 0.281250 0.625000 +vt 0.281250 0.125000 +vt 0.250000 0.312500 +vt 0.250000 0.250000 +vt 0.250000 0.750000 +vt 0.250000 0.687500 +vt 0.250000 0.187500 +vt 0.250000 0.625000 +vt 0.250000 0.125000 +vt 0.250000 0.562500 +vt 0.250000 0.062500 +vt 0.250000 0.500000 +vt 0.265625 1.000000 +vt 0.250000 0.937500 +vt 0.265625 0.000000 +vt 0.250000 0.437500 +vt 0.250000 0.875000 +vt 0.250000 0.375000 +vt 0.250000 0.812500 +vt 0.234375 0.000000 +vt 0.218750 0.062500 +vt 0.218750 0.500000 +vt 0.218750 0.437500 +vt 0.218750 0.937500 +vt 0.218750 0.875000 +vt 0.218750 0.375000 +vt 0.218750 0.812500 +vt 0.218750 0.312500 +vt 0.218750 0.750000 +vt 0.218750 0.250000 +vt 0.218750 0.687500 +vt 0.218750 0.187500 +vt 0.218750 0.625000 +vt 0.218750 0.125000 +vt 0.218750 0.562500 +vt 0.234375 1.000000 +vt 0.187500 0.250000 +vt 0.187500 0.187500 +vt 0.187500 0.687500 +vt 0.187500 0.625000 +vt 0.187500 0.125000 +vt 0.187500 0.562500 +vt 0.187500 0.062500 +vt 0.187500 0.500000 +vt 0.203125 1.000000 +vt 0.187500 0.937500 +vt 0.203125 0.000000 +vt 0.187500 0.437500 +vt 0.187500 0.875000 +vt 0.187500 0.375000 +vt 0.187500 0.812500 +vt 0.187500 0.312500 +vt 0.187500 0.750000 +vt 0.156250 0.937500 +vt 0.156250 0.875000 +vt 0.156250 0.437500 +vt 0.156250 0.375000 +vt 0.156250 0.812500 +vt 0.156250 0.312500 +vt 0.156250 0.750000 +vt 0.156250 0.250000 +vt 0.156250 0.687500 +vt 0.156250 0.187500 +vt 0.156250 0.625000 +vt 0.156250 0.125000 +vt 0.156250 0.562500 +vt 0.156250 0.062500 +vt 0.156250 0.500000 +vt 0.171875 1.000000 +vt 0.171875 0.000000 +vt 0.125000 0.687500 +vt 0.125000 0.625000 +vt 0.125000 0.187500 +vt 0.125000 0.125000 +vt 0.125000 0.562500 +vt 0.125000 0.062500 +vt 0.125000 0.500000 +vt 0.140625 1.000000 +vt 0.125000 0.937500 +vt 0.140625 0.000000 +vt 0.125000 0.437500 +vt 0.125000 0.875000 +vt 0.125000 0.375000 +vt 0.125000 0.812500 +vt 0.125000 0.312500 +vt 0.125000 0.750000 +vt 0.125000 0.250000 +vt 0.093750 0.437500 +vt 0.093750 0.375000 +vt 0.093750 0.875000 +vt 0.093750 0.812500 +vt 0.093750 0.312500 +vt 0.093750 0.750000 +vt 0.093750 0.250000 +vt 0.093750 0.687500 +vt 0.093750 0.187500 +vt 0.093750 0.625000 +vt 0.093750 0.125000 +vt 0.093750 0.562500 +vt 0.093750 0.062500 +vt 0.093750 0.500000 +vt 0.109375 1.000000 +vt 0.093750 0.937500 +vt 0.109375 0.000000 +vt 0.062500 0.187500 +vt 0.062500 0.125000 +vt 0.062500 0.625000 +vt 0.062500 0.562500 +vt 0.062500 0.062500 +vt 0.062500 0.500000 +vt 0.078125 1.000000 +vt 0.062500 0.937500 +vt 0.078125 0.000000 +vt 0.062500 0.437500 +vt 0.062500 0.875000 +vt 0.062500 0.375000 +vt 0.062500 0.812500 +vt 0.062500 0.312500 +vt 0.062500 0.750000 +vt 0.062500 0.250000 +vt 0.062500 0.687500 +vt 0.031250 0.875000 +vt 0.031250 0.812500 +vt 0.031250 0.375000 +vt 0.031250 0.312500 +vt 0.031250 0.750000 +vt 0.031250 0.250000 +vt 0.031250 0.687500 +vt 0.031250 0.187500 +vt 0.031250 0.625000 +vt 0.031250 0.125000 +vt 0.031250 0.562500 +vt 0.031250 0.062500 +vt 0.031250 0.500000 +vt 0.046875 1.000000 +vt 0.031250 0.937500 +vt 0.046875 0.000000 +vt 0.031250 0.437500 +vt 0.000000 0.625000 +vt 0.000000 0.562500 +vt 0.000000 0.125000 +vt 0.000000 0.062500 +vt 0.000000 0.500000 +vt 0.015625 1.000000 +vt 0.000000 0.937500 +vt 0.015625 0.000000 +vt 0.000000 0.437500 +vt 0.000000 0.875000 +vt 0.000000 0.375000 +vt 0.000000 0.812500 +vt 0.000000 0.312500 +vt 0.000000 0.750000 +vt 0.000000 0.250000 +vt 0.000000 0.687500 +vt 0.000000 0.187500 +vt 1.000000 0.312500 +vt 1.000000 0.375000 +vt 0.968750 0.375000 +vt 0.968750 0.312500 +vt 1.000000 0.750000 +vt 1.000000 0.812500 +vt 0.968750 0.812500 +vt 0.968750 0.750000 +vt 1.000000 0.250000 +vt 0.968750 0.250000 +vt 1.000000 0.687500 +vt 0.968750 0.687500 +vt 1.000000 0.187500 +vt 0.968750 0.187500 +vt 1.000000 0.625000 +vt 0.968750 0.625000 +vt 1.000000 0.125000 +vt 0.968750 0.125000 +vt 1.000000 0.562500 +vt 0.968750 0.562500 +vt 1.000000 0.062500 +vt 0.968750 0.062500 +vt 1.000000 0.500000 +vt 0.968750 0.500000 +vt 1.000000 0.937500 +vt 0.984375 1.000000 +vt 0.968750 0.937500 +vt 0.984375 0.000000 +vt 1.000000 0.437500 +vt 0.968750 0.437500 +vt 1.000000 0.875000 +vt 0.968750 0.875000 +vt 0.937500 0.125000 +vt 0.937500 0.062500 +vt 0.937500 0.562500 +vt 0.937500 0.500000 +vt 0.953125 1.000000 +vt 0.937500 0.937500 +vt 0.953125 0.000000 +vt 0.937500 0.437500 +vt 0.937500 0.875000 +vt 0.937500 0.375000 +vt 0.937500 0.812500 +vt 0.937500 0.312500 +vt 0.937500 0.750000 +vt 0.937500 0.250000 +vt 0.937500 0.687500 +vt 0.937500 0.187500 +vt 0.937500 0.625000 +vt 0.906250 0.312500 +vt 0.906250 0.250000 +vt 0.906250 0.750000 +vt 0.906250 0.687500 +vt 0.906250 0.187500 +vt 0.906250 0.625000 +vt 0.906250 0.125000 +vt 0.906250 0.562500 +vt 0.906250 0.062500 +vt 0.906250 0.500000 +vt 0.921875 1.000000 +vt 0.906250 0.937500 +vt 0.921875 0.000000 +vt 0.906250 0.437500 +vt 0.906250 0.875000 +vt 0.906250 0.375000 +vt 0.906250 0.812500 +vt 0.890625 1.000000 +vt 0.875000 0.937500 +vt 0.890625 0.000000 +vt 0.875000 0.062500 +vt 0.875000 0.500000 +vt 0.875000 0.437500 +vt 0.875000 0.875000 +vt 0.875000 0.375000 +vt 0.875000 0.812500 +vt 0.875000 0.312500 +vt 0.875000 0.750000 +vt 0.875000 0.250000 +vt 0.875000 0.687500 +vt 0.875000 0.187500 +vt 0.875000 0.625000 +vt 0.875000 0.125000 +vt 0.875000 0.562500 +vt 0.843750 0.750000 +vt 0.843750 0.687500 +vt 0.843750 0.250000 +vt 0.843750 0.187500 +vt 0.843750 0.625000 +vt 0.843750 0.125000 +vt 0.843750 0.562500 +vt 0.843750 0.062500 +vt 0.843750 0.500000 +vt 0.859375 1.000000 +vt 0.843750 0.937500 +vt 0.859375 0.000000 +vt 0.843750 0.437500 +vt 0.843750 0.875000 +vt 0.843750 0.375000 +vt 0.843750 0.812500 +vt 0.843750 0.312500 +vt 0.812500 0.500000 +vt 0.812500 0.437500 +vt 0.812500 0.937500 +vt 0.812500 0.875000 +vt 0.812500 0.375000 +vt 0.812500 0.812500 +vt 0.812500 0.312500 +vt 0.812500 0.750000 +vt 0.812500 0.250000 +vt 0.812500 0.687500 +vt 0.812500 0.187500 +vt 0.812500 0.625000 +vt 0.812500 0.125000 +vt 0.812500 0.562500 +vt 0.812500 0.062500 +vt 0.828125 1.000000 +vt 0.828125 0.000000 +vt 0.781250 0.250000 +vt 0.781250 0.187500 +vt 0.781250 0.687500 +vt 0.781250 0.625000 +vt 0.781250 0.125000 +vt 0.781250 0.562500 +vt 0.781250 0.062500 +vt 0.781250 0.500000 +vt 0.796875 1.000000 +vt 0.781250 0.937500 +vt 0.796875 0.000000 +vt 0.781250 0.437500 +vt 0.781250 0.875000 +vt 0.781250 0.375000 +vt 0.781250 0.812500 +vt 0.781250 0.312500 +vt 0.781250 0.750000 +vt 0.765625 1.000000 +vt 0.765625 0.000000 +vt 0.906250 0.500000 +vt 0.906250 1.000000 +vt 0.875000 1.000000 +vt 0.875000 0.500000 +vt 0.937500 1.000000 +vt 1.000000 1.000000 +vt 0.968750 1.000000 +vt 0.968750 0.500000 +vt 0.750000 0.490000 +vt 0.796822 0.485388 +vt 0.841844 0.471731 +vt 0.883337 0.449553 +vt 0.919706 0.419706 +vt 0.949553 0.383337 +vt 0.971731 0.341844 +vt 0.985388 0.296822 +vt 0.990000 0.250000 +vt 0.985388 0.203178 +vt 0.971731 0.158156 +vt 0.949553 0.116663 +vt 0.919706 0.080294 +vt 0.883337 0.050447 +vt 0.841844 0.028269 +vt 0.796822 0.014612 +vt 0.750000 0.010000 +vt 0.703178 0.014612 +vt 0.658156 0.028269 +vt 0.616663 0.050447 +vt 0.580294 0.080294 +vt 0.550447 0.116663 +vt 0.528269 0.158156 +vt 0.514612 0.203178 +vt 0.510000 0.250000 +vt 0.514612 0.296822 +vt 0.528269 0.341844 +vt 0.550447 0.383337 +vt 0.580294 0.419706 +vt 0.616663 0.449553 +vt 0.658156 0.471731 +vt 0.703178 0.485388 +vt 0.093750 0.500000 +vt 0.093750 1.000000 +vt 0.062500 1.000000 +vt 0.062500 0.500000 +vt 0.937500 0.500000 +vt 0.843750 0.500000 +vt 0.843750 1.000000 +vt 0.812500 1.000000 +vt 0.812500 0.500000 +vt 0.125000 0.500000 +vt 0.125000 1.000000 +vt 0.781250 1.000000 +vt 0.781250 0.500000 +vt 0.156250 0.500000 +vt 0.156250 1.000000 +vt 0.750000 1.000000 +vt 0.187500 0.500000 +vt 0.187500 1.000000 +vt 0.718750 1.000000 +vt 0.218750 0.500000 +vt 0.218750 1.000000 +vt 0.687500 1.000000 +vt 0.250000 0.500000 +vt 0.250000 1.000000 +vt 0.656250 1.000000 +vt 0.281250 0.500000 +vt 0.281250 1.000000 +vt 0.625000 1.000000 +vt 0.312500 0.500000 +vt 0.312500 1.000000 +vt 0.593750 1.000000 +vt 0.343750 0.500000 +vt 0.343750 1.000000 +vt 0.562500 1.000000 +vt 0.375000 0.500000 +vt 0.375000 1.000000 +vt 0.531250 1.000000 +vt 0.406250 0.500000 +vt 0.406250 1.000000 +vt 0.500000 1.000000 +vt 0.500000 0.500000 +vt 0.437500 0.500000 +vt 0.437500 1.000000 +vt 0.468750 1.000000 +vt 0.468750 0.500000 +vt 0.031250 0.500000 +vt 0.031250 1.000000 +vt 0.000000 1.000000 +vt 0.937500 1.000000 +vt 0.256645 0.283396 +vt 0.250000 0.284051 +vt 0.243355 0.283396 +vt 0.236972 0.281460 +vt 0.231081 0.278311 +vt 0.225923 0.274079 +vt 0.221687 0.268917 +vt 0.218541 0.263031 +vt 0.216603 0.256643 +vt 0.215949 0.249999 +vt 0.216603 0.243356 +vt 0.218541 0.236969 +vt 0.221687 0.231083 +vt 0.225924 0.225921 +vt 0.231079 0.221690 +vt 0.236972 0.218540 +vt 0.243355 0.216604 +vt 0.250000 0.215949 +vt 0.256645 0.216604 +vt 0.263028 0.218540 +vt 0.268921 0.221690 +vt 0.274076 0.225921 +vt 0.278312 0.231081 +vt 0.281459 0.236968 +vt 0.283397 0.243358 +vt 0.284051 0.249999 +vt 0.283397 0.256642 +vt 0.281459 0.263031 +vt 0.278313 0.268917 +vt 0.274077 0.274079 +vt 0.268919 0.278311 +vt 0.263028 0.281460 +vt 0.256645 0.283396 +vt 0.250000 0.284051 +vt 0.243355 0.283396 +vt 0.236968 0.281459 +vt 0.231083 0.278313 +vt 0.225923 0.274079 +vt 0.221688 0.268918 +vt 0.218541 0.263029 +vt 0.216603 0.256643 +vt 0.215949 0.250000 +vt 0.216603 0.243357 +vt 0.218541 0.236970 +vt 0.221688 0.231081 +vt 0.225923 0.225922 +vt 0.231081 0.221688 +vt 0.236969 0.218542 +vt 0.243357 0.216603 +vt 0.250000 0.215949 +vt 0.256643 0.216603 +vt 0.263031 0.218542 +vt 0.268916 0.221687 +vt 0.274079 0.225924 +vt 0.278312 0.231081 +vt 0.281459 0.236969 +vt 0.283397 0.243358 +vt 0.284051 0.250000 +vt 0.283397 0.256642 +vt 0.281459 0.263031 +vt 0.278312 0.268918 +vt 0.274077 0.274079 +vt 0.268917 0.278313 +vt 0.263031 0.281459 +vt 0.256645 0.283396 +vt 0.250000 0.284051 +vt 0.243355 0.283396 +vt 0.236969 0.281459 +vt 0.231084 0.278313 +vt 0.225923 0.274078 +vt 0.221686 0.268916 +vt 0.218541 0.263032 +vt 0.216603 0.256643 +vt 0.215949 0.250000 +vt 0.216603 0.243357 +vt 0.218541 0.236968 +vt 0.221686 0.231084 +vt 0.225922 0.225923 +vt 0.231083 0.221687 +vt 0.236970 0.218541 +vt 0.243357 0.216603 +vt 0.250000 0.215949 +vt 0.256643 0.216603 +vt 0.263029 0.218541 +vt 0.268919 0.221689 +vt 0.274078 0.225923 +vt 0.278312 0.231082 +vt 0.281459 0.236969 +vt 0.283396 0.243356 +vt 0.284051 0.250000 +vt 0.283396 0.256644 +vt 0.281459 0.263031 +vt 0.278312 0.268918 +vt 0.274078 0.274077 +vt 0.268918 0.278313 +vt 0.263030 0.281460 +vt 0.218750 1.000000 +vt 0.093750 1.000000 +vt 0.656250 1.000000 +vt 0.875000 1.000000 +vt 0.687500 1.000000 +vt 0.781251 1.000000 +vt 0.750000 1.000000 +vt 0.437500 1.000000 +vt 0.373318 1.000000 +vt 0.345431 1.000000 +vt 0.368514 1.000000 +vt 0.350236 1.000000 +vt 0.056642 0.109115 +vt 0.074100 0.087843 +vt 0.998318 1.000000 +vt 0.970431 1.000000 +vt 0.993513 1.000000 +vt 0.975235 1.000000 +vt 0.287105 0.486345 +vt 0.259719 0.489043 +vt 0.717068 1.000000 +vt 0.689181 1.000000 +vt 0.712264 1.000000 +vt 0.693986 1.000000 +vt 0.474566 0.167500 +vt 0.482554 0.193834 +vt 0.967068 1.000000 +vt 0.939181 1.000000 +vt 0.962263 1.000000 +vt 0.943986 1.000000 +vt 0.332499 0.474566 +vt 0.306167 0.482554 +vt 0.935819 1.000000 +vt 0.907932 1.000000 +vt 0.931014 1.000000 +vt 0.912737 1.000000 +vt 0.374724 0.454156 +vt 0.350456 0.467128 +vt 0.404568 1.000000 +vt 0.376682 1.000000 +vt 0.399764 1.000000 +vt 0.381487 1.000000 +vt 0.087845 0.074098 +vt 0.109114 0.056643 +vt 0.904568 1.000000 +vt 0.876682 1.000000 +vt 0.899763 1.000000 +vt 0.881486 1.000000 +vt 0.412157 0.425900 +vt 0.390886 0.443357 +vt 0.748318 1.000000 +vt 0.720431 1.000000 +vt 0.743513 1.000000 +vt 0.725236 1.000000 +vt 0.486346 0.212897 +vt 0.489043 0.240281 +vt 0.873320 1.000000 +vt 0.845431 1.000000 +vt 0.868515 1.000000 +vt 0.850236 1.000000 +vt 0.443357 0.390886 +vt 0.425900 0.412158 +vt 0.842068 1.000000 +vt 0.814182 1.000000 +vt 0.837264 1.000000 +vt 0.818986 1.000000 +vt 0.467128 0.350456 +vt 0.454156 0.374725 +vt 0.435819 1.000000 +vt 0.407931 1.000000 +vt 0.431015 1.000000 +vt 0.412735 1.000000 +vt 0.125273 0.045845 +vt 0.149544 0.032872 +vt 0.810818 1.000000 +vt 0.782931 1.000000 +vt 0.806013 1.000000 +vt 0.787735 1.000000 +vt 0.482554 0.306166 +vt 0.474566 0.332500 +vt 0.779568 1.000000 +vt 0.751682 1.000000 +vt 0.774763 1.000000 +vt 0.756486 1.000000 +vt 0.489043 0.259717 +vt 0.486346 0.287103 +vt 0.751682 1.000000 +vt 0.774764 1.000000 +vt 0.756487 1.000000 +vt 0.489043 0.259718 +vt 0.486346 0.287103 +vt 0.748318 1.000000 +vt 0.720431 1.000000 +vt 0.743514 1.000000 +vt 0.725236 1.000000 +vt 0.486346 0.212897 +vt 0.489043 0.240282 +vt 0.467068 1.000000 +vt 0.439182 1.000000 +vt 0.462263 1.000000 +vt 0.443987 1.000000 +vt 0.167502 0.025434 +vt 0.193833 0.017446 +vt 0.717068 1.000000 +vt 0.689182 1.000000 +vt 0.712264 1.000000 +vt 0.693986 1.000000 +vt 0.474566 0.167501 +vt 0.482554 0.193834 +vt 0.810819 1.000000 +vt 0.782932 1.000000 +vt 0.806014 1.000000 +vt 0.787737 1.000000 +vt 0.482554 0.306167 +vt 0.474566 0.332500 +vt 0.685819 1.000000 +vt 0.657931 1.000000 +vt 0.681014 1.000000 +vt 0.662736 1.000000 +vt 0.454156 0.125275 +vt 0.467128 0.149544 +vt 0.654568 1.000000 +vt 0.626682 1.000000 +vt 0.649762 1.000000 +vt 0.631487 1.000000 +vt 0.425901 0.087844 +vt 0.443357 0.109113 +vt 0.498318 1.000000 +vt 0.470431 1.000000 +vt 0.493513 1.000000 +vt 0.475235 1.000000 +vt 0.212895 0.013655 +vt 0.240281 0.010957 +vt 0.623318 1.000000 +vt 0.595431 1.000000 +vt 0.618515 1.000000 +vt 0.600236 1.000000 +vt 0.390885 0.056642 +vt 0.412158 0.074100 +vt 0.842068 1.000000 +vt 0.814181 1.000000 +vt 0.837263 1.000000 +vt 0.467128 0.350456 +vt 0.454156 0.374724 +vt 0.592068 1.000000 +vt 0.564181 1.000000 +vt 0.587263 1.000000 +vt 0.568986 1.000000 +vt 0.350456 0.032872 +vt 0.374723 0.045843 +vt 0.560818 1.000000 +vt 0.532932 1.000000 +vt 0.556015 1.000000 +vt 0.537737 1.000000 +vt 0.306168 0.017447 +vt 0.332500 0.025435 +vt 0.529569 1.000000 +vt 0.501682 1.000000 +vt 0.524765 1.000000 +vt 0.506487 1.000000 +vt 0.259719 0.010957 +vt 0.287105 0.013655 +vt 0.529568 1.000000 +vt 0.524763 1.000000 +vt 0.506486 1.000000 +vt 0.259717 0.010957 +vt 0.287103 0.013654 +vt 0.873319 1.000000 +vt 0.845432 1.000000 +vt 0.868514 1.000000 +vt 0.850236 1.000000 +vt 0.443358 0.390885 +vt 0.425900 0.412158 +vt 0.498319 1.000000 +vt 0.470432 1.000000 +vt 0.493514 1.000000 +vt 0.475237 1.000000 +vt 0.212897 0.013654 +vt 0.240283 0.010957 +vt 0.467068 1.000000 +vt 0.439182 1.000000 +vt 0.462263 1.000000 +vt 0.443985 1.000000 +vt 0.167500 0.025435 +vt 0.193832 0.017447 +vt 0.560818 1.000000 +vt 0.532932 1.000000 +vt 0.556013 1.000000 +vt 0.537737 1.000000 +vt 0.306167 0.017446 +vt 0.332497 0.025434 +vt 0.435818 1.000000 +vt 0.431014 1.000000 +vt 0.412737 1.000000 +vt 0.125276 0.045844 +vt 0.149544 0.032872 +vt 0.876682 1.000000 +vt 0.899763 1.000000 +vt 0.881487 1.000000 +vt 0.412156 0.425901 +vt 0.390887 0.443357 +vt 0.404569 1.000000 +vt 0.376682 1.000000 +vt 0.399763 1.000000 +vt 0.381486 1.000000 +vt 0.087843 0.074099 +vt 0.109114 0.056643 +vt 0.373318 1.000000 +vt 0.345432 1.000000 +vt 0.368514 1.000000 +vt 0.350237 1.000000 +vt 0.056643 0.109113 +vt 0.074100 0.087843 +vt 0.592068 1.000000 +vt 0.564181 1.000000 +vt 0.587265 1.000000 +vt 0.568986 1.000000 +vt 0.350455 0.032872 +vt 0.374727 0.045845 +vt 0.342068 1.000000 +vt 0.314181 1.000000 +vt 0.337264 1.000000 +vt 0.318986 1.000000 +vt 0.032872 0.149544 +vt 0.045844 0.125275 +vt 0.935819 1.000000 +vt 0.907932 1.000000 +vt 0.931015 1.000000 +vt 0.912735 1.000000 +vt 0.374726 0.454155 +vt 0.350455 0.467128 +vt 0.310819 1.000000 +vt 0.282932 1.000000 +vt 0.306014 1.000000 +vt 0.287737 1.000000 +vt 0.017446 0.193833 +vt 0.025434 0.167501 +vt 0.279568 1.000000 +vt 0.251682 1.000000 +vt 0.274764 1.000000 +vt 0.256486 1.000000 +vt 0.010957 0.240282 +vt 0.013654 0.212897 +vt 0.595432 1.000000 +vt 0.618512 1.000000 +vt 0.600237 1.000000 +vt 0.390886 0.056643 +vt 0.412155 0.074098 +vt 0.248319 1.000000 +vt 0.220432 1.000000 +vt 0.243514 1.000000 +vt 0.225237 1.000000 +vt 0.013654 0.287103 +vt 0.010957 0.259718 +vt 0.967069 1.000000 +vt 0.939182 1.000000 +vt 0.943988 1.000000 +vt 0.332497 0.474566 +vt 0.306167 0.482554 +vt 0.217068 1.000000 +vt 0.189181 1.000000 +vt 0.212263 1.000000 +vt 0.193986 1.000000 +vt 0.025434 0.332499 +vt 0.017446 0.306167 +vt 0.185819 1.000000 +vt 0.157932 1.000000 +vt 0.181014 1.000000 +vt 0.162736 1.000000 +vt 0.045844 0.374725 +vt 0.032872 0.350456 +vt 0.654568 1.000000 +vt 0.626682 1.000000 +vt 0.649763 1.000000 +vt 0.631486 1.000000 +vt 0.425900 0.087843 +vt 0.443357 0.109114 +vt 0.154569 1.000000 +vt 0.126681 1.000000 +vt 0.149763 1.000000 +vt 0.131486 1.000000 +vt 0.074100 0.412158 +vt 0.056643 0.390886 +vt 0.123318 1.000000 +vt 0.095431 1.000000 +vt 0.118514 1.000000 +vt 0.100237 1.000000 +vt 0.109114 0.443357 +vt 0.087843 0.425900 +vt 0.998318 1.000000 +vt 0.970431 1.000000 +vt 0.993513 1.000000 +vt 0.975235 1.000000 +vt 0.287105 0.486345 +vt 0.259719 0.489043 +vt 0.092068 1.000000 +vt 0.064182 1.000000 +vt 0.087263 1.000000 +vt 0.068986 1.000000 +vt 0.149544 0.467128 +vt 0.125276 0.454157 +vt 0.685818 1.000000 +vt 0.657931 1.000000 +vt 0.681014 1.000000 +vt 0.662735 1.000000 +vt 0.454156 0.125275 +vt 0.467128 0.149544 +vt 0.060819 1.000000 +vt 0.032932 1.000000 +vt 0.056014 1.000000 +vt 0.037737 1.000000 +vt 0.193833 0.482554 +vt 0.167501 0.474566 +vt 0.029569 1.000000 +vt 0.001682 1.000000 +vt 0.024765 1.000000 +vt 0.006487 1.000000 +vt 0.240281 0.489043 +vt 0.212895 0.486345 +vt 0.342068 1.000000 +vt 0.314181 1.000000 +vt 0.337264 1.000000 +vt 0.318987 1.000000 +vt 0.032873 0.149543 +vt 0.045844 0.125275 +vt 0.310818 1.000000 +vt 0.282932 1.000000 +vt 0.306014 1.000000 +vt 0.287736 1.000000 +vt 0.017446 0.193834 +vt 0.025434 0.167501 +vt 0.279569 1.000000 +vt 0.251682 1.000000 +vt 0.274764 1.000000 +vt 0.256487 1.000000 +vt 0.010957 0.240281 +vt 0.013654 0.212896 +vt 0.248318 1.000000 +vt 0.220431 1.000000 +vt 0.243514 1.000000 +vt 0.225236 1.000000 +vt 0.013654 0.287104 +vt 0.010957 0.259718 +vt 0.217069 1.000000 +vt 0.189182 1.000000 +vt 0.212264 1.000000 +vt 0.025434 0.332499 +vt 0.017446 0.306166 +vt 0.185818 1.000000 +vt 0.157932 1.000000 +vt 0.181014 1.000000 +vt 0.162737 1.000000 +vt 0.045844 0.374724 +vt 0.032872 0.350456 +vt 0.154569 1.000000 +vt 0.126681 1.000000 +vt 0.149764 1.000000 +vt 0.131485 1.000000 +vt 0.074100 0.412158 +vt 0.056642 0.390885 +vt 0.123318 1.000000 +vt 0.095431 1.000000 +vt 0.118513 1.000000 +vt 0.100237 1.000000 +vt 0.109113 0.443357 +vt 0.087844 0.425901 +vt 0.092068 1.000000 +vt 0.064181 1.000000 +vt 0.087265 1.000000 +vt 0.068986 1.000000 +vt 0.149544 0.467128 +vt 0.125274 0.454155 +vt 0.060818 1.000000 +vt 0.032932 1.000000 +vt 0.056013 1.000000 +vt 0.193833 0.482554 +vt 0.167502 0.474566 +vt 0.029569 1.000000 +vt 0.001682 1.000000 +vt 0.024765 1.000000 +vt 0.006487 1.000000 +vt 0.240281 0.489043 +vt 0.212895 0.486345 +vt 0.373319 1.000000 +vt 0.345432 1.000000 +vt 0.368514 1.000000 +vt 0.350236 1.000000 +vt 0.056642 0.109115 +vt 0.074100 0.087843 +vt 0.717068 1.000000 +vt 0.689181 1.000000 +vt 0.712264 1.000000 +vt 0.693986 1.000000 +vt 0.474565 0.167500 +vt 0.482554 0.193833 +vt 0.376681 1.000000 +vt 0.399764 1.000000 +vt 0.087843 0.074099 +vt 0.109115 0.056642 +vt 0.748319 1.000000 +vt 0.720431 1.000000 +vt 0.743514 1.000000 +vt 0.725237 1.000000 +vt 0.486346 0.212897 +vt 0.489043 0.240282 +vt 0.435818 1.000000 +vt 0.431014 1.000000 +vt 0.412737 1.000000 +vt 0.125276 0.045843 +vt 0.149544 0.032872 +vt 0.779568 1.000000 +vt 0.751682 1.000000 +vt 0.774764 1.000000 +vt 0.756486 1.000000 +vt 0.489043 0.259718 +vt 0.439182 1.000000 +vt 0.462263 1.000000 +vt 0.443986 1.000000 +vt 0.167500 0.025434 +vt 0.193832 0.017447 +vt 0.810819 1.000000 +vt 0.782932 1.000000 +vt 0.806014 1.000000 +vt 0.482554 0.306167 +vt 0.474565 0.332500 +vt 0.498318 1.000000 +vt 0.493514 1.000000 +vt 0.475237 1.000000 +vt 0.212898 0.013654 +vt 0.240282 0.010957 +vt 0.842069 1.000000 +vt 0.814181 1.000000 +vt 0.818986 1.000000 +vt 0.529568 1.000000 +vt 0.524763 1.000000 +vt 0.506485 1.000000 +vt 0.259717 0.010957 +vt 0.287103 0.013654 +vt 0.873318 1.000000 +vt 0.845432 1.000000 +vt 0.868514 1.000000 +vt 0.850236 1.000000 +vt 0.443358 0.390885 +vt 0.425901 0.412157 +vt 0.532932 1.000000 +vt 0.556014 1.000000 +vt 0.306168 0.017447 +vt 0.332500 0.025434 +vt 0.904568 1.000000 +vt 0.876682 1.000000 +vt 0.899763 1.000000 +vt 0.881486 1.000000 +vt 0.412158 0.425900 +vt 0.390886 0.443357 +vt 0.592068 1.000000 +vt 0.564181 1.000000 +vt 0.587264 1.000000 +vt 0.568985 1.000000 +vt 0.350455 0.032871 +vt 0.374725 0.045844 +vt 0.935818 1.000000 +vt 0.907932 1.000000 +vt 0.931015 1.000000 +vt 0.912737 1.000000 +vt 0.374724 0.454157 +vt 0.350455 0.467128 +vt 0.623318 1.000000 +vt 0.595432 1.000000 +vt 0.618514 1.000000 +vt 0.600237 1.000000 +vt 0.390886 0.056643 +vt 0.412157 0.074100 +vt 0.967068 1.000000 +vt 0.939182 1.000000 +vt 0.962263 1.000000 +vt 0.943987 1.000000 +vt 0.332498 0.474566 +vt 0.306168 0.482553 +vt 0.654568 1.000000 +vt 0.626681 1.000000 +vt 0.649764 1.000000 +vt 0.631486 1.000000 +vt 0.425901 0.087844 +vt 0.443358 0.109115 +vt 0.970432 1.000000 +vt 0.993513 1.000000 +vt 0.975235 1.000000 +vt 0.287105 0.486345 +vt 0.259719 0.489043 +vt 0.685818 1.000000 +vt 0.657931 1.000000 +vt 0.681014 1.000000 +vt 0.662737 1.000000 +vt 0.454156 0.125275 +vt 0.467128 0.149544 +vt 0.342068 1.000000 +vt 0.314182 1.000000 +vt 0.337263 1.000000 +vt 0.032872 0.149543 +vt 0.045843 0.125277 +vt 0.310818 1.000000 +vt 0.282932 1.000000 +vt 0.306013 1.000000 +vt 0.287736 1.000000 +vt 0.017446 0.193834 +vt 0.025434 0.167500 +vt 0.279569 1.000000 +vt 0.251682 1.000000 +vt 0.274764 1.000000 +vt 0.256486 1.000000 +vt 0.010957 0.240281 +vt 0.013654 0.212896 +vt 0.248318 1.000000 +vt 0.220431 1.000000 +vt 0.243513 1.000000 +vt 0.225236 1.000000 +vt 0.013654 0.287104 +vt 0.010957 0.259719 +vt 0.217068 1.000000 +vt 0.189181 1.000000 +vt 0.212264 1.000000 +vt 0.193986 1.000000 +vt 0.025434 0.332500 +vt 0.017446 0.306166 +vt 0.185818 1.000000 +vt 0.157932 1.000000 +vt 0.181013 1.000000 +vt 0.162737 1.000000 +vt 0.045843 0.374723 +vt 0.032873 0.350457 +vt 0.154568 1.000000 +vt 0.126682 1.000000 +vt 0.149764 1.000000 +vt 0.074100 0.412158 +vt 0.056642 0.390885 +vt 0.123318 1.000000 +vt 0.095432 1.000000 +vt 0.118514 1.000000 +vt 0.100237 1.000000 +vt 0.109114 0.443357 +vt 0.087843 0.425900 +vt 0.092068 1.000000 +vt 0.064182 1.000000 +vt 0.087263 1.000000 +vt 0.068986 1.000000 +vt 0.149544 0.467128 +vt 0.125276 0.454157 +vt 0.060818 1.000000 +vt 0.032932 1.000000 +vt 0.056014 1.000000 +vt 0.037737 1.000000 +vt 0.193832 0.482553 +vt 0.167501 0.474566 +vt 0.029569 1.000000 +vt 0.001682 1.000000 +vt 0.024765 1.000000 +vt 0.006487 1.000000 +vt 0.240281 0.489043 +s 0 +usemtl floor +f 1/1/1 2/1/1 3/1/1 4/1/1 +s 1 +f 49/2/10 48/3/11 58/4/12 59/5/13 +f 519/6/14 518/7/15 51/8/16 52/9/17 +f 522/10/18 49/2/10 59/5/13 60/11/19 +f 45/12/20 519/6/14 52/9/17 53/13/21 +f 50/14/22 522/10/18 60/11/19 61/15/23 +f 520/16/24 45/12/20 53/13/21 54/17/25 +f 523/18/26 50/14/22 61/15/23 62/19/27 +f 46/20/28 520/16/24 54/17/25 55/21/29 +f 524/22/30 523/18/26 62/19/27 63/23/31 +f 521/24/32 46/20/28 55/21/29 56/25/33 +f 525/26/34 524/22/30 63/23/31 64/27/35 +f 47/28/36 521/24/32 56/25/33 57/29/37 +f 526/30/38 525/26/34 64/27/35 65/31/39 +f 48/3/11 47/28/36 57/29/37 58/4/12 +f 518/7/15 126/32/1 51/8/16 +f 352/33/40 526/30/38 65/31/39 +f 58/4/12 57/29/37 72/34/41 73/35/42 +f 51/8/16 126/36/1 66/37/43 +f 352/38/40 65/31/39 80/39/44 +f 59/5/13 58/4/12 73/35/42 74/40/45 +f 52/9/17 51/8/16 66/37/43 67/41/46 +f 60/11/19 59/5/13 74/40/45 75/42/47 +f 53/13/21 52/9/17 67/41/46 68/43/48 +f 61/15/23 60/11/19 75/42/47 76/44/49 +f 54/17/25 53/13/21 68/43/48 69/45/50 +f 62/19/27 61/15/23 76/44/49 77/46/51 +f 55/21/29 54/17/25 69/45/50 70/47/52 +f 63/23/31 62/19/27 77/46/51 78/48/53 +f 56/25/33 55/21/29 70/47/52 71/49/54 +f 64/27/35 63/23/31 78/48/53 79/50/55 +f 57/29/37 56/25/33 71/49/54 72/34/41 +f 65/31/39 64/27/35 79/50/55 80/39/44 +f 77/46/51 76/44/49 91/51/56 92/52/57 +f 70/47/52 69/45/50 84/53/58 85/54/59 +f 78/48/53 77/46/51 92/52/57 93/55/60 +f 71/49/54 70/47/52 85/54/59 86/56/61 +f 79/50/55 78/48/53 93/55/60 94/57/62 +f 72/34/41 71/49/54 86/56/61 87/58/63 +f 80/39/44 79/50/55 94/57/62 95/59/64 +f 73/35/42 72/34/41 87/58/63 88/60/65 +f 66/37/43 126/61/1 81/62/66 +f 352/63/40 80/39/44 95/59/64 +f 74/40/45 73/35/42 88/60/65 89/64/67 +f 67/41/46 66/37/43 81/62/66 82/65/68 +f 75/42/47 74/40/45 89/64/67 90/66/69 +f 68/43/48 67/41/46 82/65/68 83/67/70 +f 76/44/49 75/42/47 90/66/69 91/51/56 +f 69/45/50 68/43/48 83/67/70 84/53/58 +f 81/62/66 126/68/1 96/69/71 +f 352/70/40 95/59/64 110/71/72 +f 89/64/67 88/60/65 103/72/73 104/73/74 +f 82/65/68 81/62/66 96/69/71 97/74/75 +f 90/66/69 89/64/67 104/73/74 105/75/76 +f 83/67/70 82/65/68 97/74/75 98/76/77 +f 91/51/56 90/66/69 105/75/76 106/77/78 +f 84/53/58 83/67/70 98/76/77 99/78/79 +f 92/52/57 91/51/56 106/77/78 107/79/80 +f 85/54/59 84/53/58 99/78/79 100/80/81 +f 93/55/60 92/52/57 107/79/80 108/81/82 +f 86/56/61 85/54/59 100/80/81 101/82/83 +f 94/57/62 93/55/60 108/81/82 109/83/84 +f 87/58/63 86/56/61 101/82/83 102/84/85 +f 95/59/64 94/57/62 109/83/84 110/71/72 +f 88/60/65 87/58/63 102/84/85 103/72/73 +f 100/80/81 99/78/79 114/85/86 115/86/87 +f 108/81/82 107/79/80 122/87/88 123/88/89 +f 101/82/83 100/80/81 115/86/87 116/89/90 +f 109/83/84 108/81/82 123/88/89 124/90/91 +f 102/84/85 101/82/83 116/89/90 117/91/92 +f 110/71/72 109/83/84 124/90/91 125/92/93 +f 103/72/73 102/84/85 117/91/92 118/93/94 +f 96/69/71 126/94/1 111/95/95 +f 352/96/40 110/71/72 125/92/93 +f 104/73/74 103/72/73 118/93/94 119/97/96 +f 97/74/75 96/69/71 111/95/95 112/98/97 +f 105/75/76 104/73/74 119/97/96 120/99/98 +f 98/76/77 97/74/75 112/98/97 113/100/99 +f 106/77/78 105/75/76 120/99/98 121/101/100 +f 99/78/79 98/76/77 113/100/99 114/85/86 +f 107/79/80 106/77/78 121/101/100 122/87/88 +f 119/97/96 118/93/94 134/102/101 135/103/102 +f 112/98/97 111/95/95 127/104/103 128/105/104 +f 120/99/98 119/97/96 135/103/102 136/106/105 +f 113/100/99 112/98/97 128/105/104 129/107/106 +f 121/101/100 120/99/98 136/106/105 137/108/107 +f 114/85/86 113/100/99 129/107/106 130/109/108 +f 122/87/88 121/101/100 137/108/107 138/110/109 +f 115/86/87 114/85/86 130/109/108 131/111/110 +f 123/88/89 122/87/88 138/110/109 139/112/111 +f 116/89/90 115/86/87 131/111/110 132/113/112 +f 124/90/91 123/88/89 139/112/111 140/114/113 +f 117/91/92 116/89/90 132/113/112 133/115/114 +f 125/92/93 124/90/91 140/114/113 141/116/115 +f 118/93/94 117/91/92 133/115/114 134/102/101 +f 111/95/95 126/117/1 127/104/103 +f 352/118/40 125/92/93 141/116/115 +f 139/112/111 138/110/109 153/119/116 154/120/117 +f 132/113/112 131/111/110 146/121/118 147/122/119 +f 140/114/113 139/112/111 154/120/117 155/123/120 +f 133/115/114 132/113/112 147/122/119 148/124/121 +f 141/116/115 140/114/113 155/123/120 156/125/122 +f 134/102/101 133/115/114 148/124/121 149/126/123 +f 127/104/103 126/127/1 142/128/124 +f 352/129/40 141/116/115 156/125/122 +f 135/103/102 134/102/101 149/126/123 150/130/125 +f 128/105/104 127/104/103 142/128/124 143/131/126 +f 136/106/105 135/103/102 150/130/125 151/132/127 +f 129/107/106 128/105/104 143/131/126 144/133/128 +f 137/108/107 136/106/105 151/132/127 152/134/129 +f 130/109/108 129/107/106 144/133/128 145/135/130 +f 138/110/109 137/108/107 152/134/129 153/119/116 +f 131/111/110 130/109/108 145/135/130 146/121/118 +f 151/132/127 150/130/125 165/136/131 166/137/132 +f 144/133/128 143/131/126 158/138/133 159/139/134 +f 152/134/129 151/132/127 166/137/132 167/140/135 +f 145/135/130 144/133/128 159/139/134 160/141/136 +f 153/119/116 152/134/129 167/140/135 168/142/137 +f 146/121/118 145/135/130 160/141/136 161/143/138 +f 154/120/117 153/119/116 168/142/137 169/144/139 +f 147/122/119 146/121/118 161/143/138 162/145/140 +f 155/123/120 154/120/117 169/144/139 170/146/141 +f 148/124/121 147/122/119 162/145/140 163/147/142 +f 156/125/122 155/123/120 170/146/141 171/148/143 +f 149/126/123 148/124/121 163/147/142 164/149/144 +f 142/128/124 126/150/1 157/151/145 +f 352/152/40 156/125/122 171/148/143 +f 150/130/125 149/126/123 164/149/144 165/136/131 +f 143/131/126 142/128/124 157/151/145 158/138/133 +f 170/146/141 169/144/139 184/153/146 185/154/147 +f 163/147/142 162/145/140 177/155/148 178/156/149 +f 171/148/143 170/146/141 185/154/147 186/157/150 +f 164/149/144 163/147/142 178/156/149 179/158/151 +f 157/151/145 126/159/1 172/160/152 +f 352/161/40 171/148/143 186/157/150 +f 165/136/131 164/149/144 179/158/151 180/162/153 +f 158/138/133 157/151/145 172/160/152 173/163/154 +f 166/137/132 165/136/131 180/162/153 181/164/155 +f 159/139/134 158/138/133 173/163/154 174/165/156 +f 167/140/135 166/137/132 181/164/155 182/166/157 +f 160/141/136 159/139/134 174/165/156 175/167/158 +f 168/142/137 167/140/135 182/166/157 183/168/159 +f 161/143/138 160/141/136 175/167/158 176/169/160 +f 169/144/139 168/142/137 183/168/159 184/153/146 +f 162/145/140 161/143/138 176/169/160 177/155/148 +f 174/165/156 173/163/154 188/170/161 189/171/162 +f 182/166/157 181/164/155 196/172/163 197/173/164 +f 175/167/158 174/165/156 189/171/162 190/174/165 +f 183/168/159 182/166/157 197/173/164 198/175/166 +f 176/169/160 175/167/158 190/174/165 191/176/167 +f 184/153/146 183/168/159 198/175/166 199/177/168 +f 177/155/148 176/169/160 191/176/167 192/178/169 +f 185/154/147 184/153/146 199/177/168 200/179/170 +f 178/156/149 177/155/148 192/178/169 193/180/171 +f 186/157/150 185/154/147 200/179/170 201/181/172 +f 179/158/151 178/156/149 193/180/171 194/182/173 +f 172/160/152 126/183/1 187/184/174 +f 352/185/40 186/157/150 201/181/172 +f 180/162/153 179/158/151 194/182/173 195/186/175 +f 173/163/154 172/160/152 187/184/174 188/170/161 +f 181/164/155 180/162/153 195/186/175 196/172/163 +f 193/180/171 192/178/169 207/187/176 208/188/177 +f 201/181/172 200/179/170 215/189/178 216/190/179 +f 194/182/173 193/180/171 208/188/177 209/191/180 +f 187/184/174 126/192/1 202/193/181 +f 352/194/40 201/181/172 216/190/179 +f 195/186/175 194/182/173 209/191/180 210/195/182 +f 188/170/161 187/184/174 202/193/181 203/196/183 +f 196/172/163 195/186/175 210/195/182 211/197/184 +f 189/171/162 188/170/161 203/196/183 204/198/185 +f 197/173/164 196/172/163 211/197/184 212/199/186 +f 190/174/165 189/171/162 204/198/185 205/200/187 +f 198/175/166 197/173/164 212/199/186 213/201/188 +f 191/176/167 190/174/165 205/200/187 206/202/189 +f 199/177/168 198/175/166 213/201/188 214/203/190 +f 192/178/169 191/176/167 206/202/189 207/187/176 +f 200/179/170 199/177/168 214/203/190 215/189/178 +f 212/199/186 211/197/184 226/204/191 227/205/192 +f 205/200/187 204/198/185 219/206/193 220/207/194 +f 213/201/188 212/199/186 227/205/192 228/208/195 +f 206/202/189 205/200/187 220/207/194 221/209/196 +f 214/203/190 213/201/188 228/208/195 229/210/197 +f 207/187/176 206/202/189 221/209/196 222/211/198 +f 215/189/178 214/203/190 229/210/197 230/212/199 +f 208/188/177 207/187/176 222/211/198 223/213/200 +f 216/190/179 215/189/178 230/212/199 231/214/201 +f 209/191/180 208/188/177 223/213/200 224/215/202 +f 202/193/181 126/216/1 217/217/203 +f 352/218/40 216/190/179 231/214/201 +f 210/195/182 209/191/180 224/215/202 225/219/204 +f 203/196/183 202/193/181 217/217/203 218/220/205 +f 211/197/184 210/195/182 225/219/204 226/204/191 +f 204/198/185 203/196/183 218/220/205 219/206/193 +f 231/214/201 230/212/199 245/221/206 246/222/207 +f 224/215/202 223/213/200 238/223/208 239/224/209 +f 217/217/203 126/225/1 232/226/210 +f 352/227/40 231/214/201 246/222/207 +f 225/219/204 224/215/202 239/224/209 240/228/211 +f 218/220/205 217/217/203 232/226/210 233/229/212 +f 226/204/191 225/219/204 240/228/211 241/230/213 +f 219/206/193 218/220/205 233/229/212 234/231/214 +f 227/205/192 226/204/191 241/230/213 242/232/215 +f 220/207/194 219/206/193 234/231/214 235/233/216 +f 228/208/195 227/205/192 242/232/215 243/234/217 +f 221/209/196 220/207/194 235/233/216 236/235/218 +f 229/210/197 228/208/195 243/234/217 244/236/219 +f 222/211/198 221/209/196 236/235/218 237/237/220 +f 230/212/199 229/210/197 244/236/219 245/221/206 +f 223/213/200 222/211/198 237/237/220 238/223/208 +f 235/233/216 234/231/214 249/238/221 250/239/222 +f 243/234/217 242/232/215 257/240/223 258/241/224 +f 236/235/218 235/233/216 250/239/222 251/242/225 +f 244/236/219 243/234/217 258/241/224 259/243/226 +f 237/237/220 236/235/218 251/242/225 252/244/227 +f 245/221/206 244/236/219 259/243/226 260/245/228 +f 238/223/208 237/237/220 252/244/227 253/246/229 +f 246/222/207 245/221/206 260/245/228 261/247/230 +f 239/224/209 238/223/208 253/246/229 254/248/231 +f 232/226/210 126/249/1 247/250/232 +f 352/251/40 246/222/207 261/247/230 +f 240/228/211 239/224/209 254/248/231 255/252/233 +f 233/229/212 232/226/210 247/250/232 248/253/234 +f 241/230/213 240/228/211 255/252/233 256/254/235 +f 234/231/214 233/229/212 248/253/234 249/238/221 +f 242/232/215 241/230/213 256/254/235 257/240/223 +f 254/248/231 253/246/229 268/255/236 269/256/237 +f 247/250/232 126/257/1 262/258/238 +f 352/259/40 261/247/230 276/260/239 +f 255/252/233 254/248/231 269/256/237 270/261/240 +f 248/253/234 247/250/232 262/258/238 263/262/241 +f 256/254/235 255/252/233 270/261/240 271/263/242 +f 249/238/221 248/253/234 263/262/241 264/264/243 +f 257/240/223 256/254/235 271/263/242 272/265/244 +f 250/239/222 249/238/221 264/264/243 265/266/245 +f 258/241/224 257/240/223 272/265/244 273/267/246 +f 251/242/225 250/239/222 265/266/245 266/268/247 +f 259/243/226 258/241/224 273/267/246 274/269/248 +f 252/244/227 251/242/225 266/268/247 267/270/249 +f 260/245/228 259/243/226 274/269/248 275/271/250 +f 253/246/229 252/244/227 267/270/249 268/255/236 +f 261/247/230 260/245/228 275/271/250 276/260/239 +f 273/267/246 272/265/244 287/272/251 288/273/252 +f 266/268/247 265/266/245 280/274/253 281/275/254 +f 274/269/248 273/267/246 288/273/252 289/276/255 +f 267/270/249 266/268/247 281/275/254 282/277/256 +f 275/271/250 274/269/248 289/276/255 290/278/257 +f 268/255/236 267/270/249 282/277/256 283/279/258 +f 276/260/239 275/271/250 290/278/257 291/280/259 +f 269/256/237 268/255/236 283/279/258 284/281/260 +f 262/258/238 126/282/1 277/283/261 +f 352/284/40 276/260/239 291/280/259 +f 270/261/240 269/256/237 284/281/260 285/285/262 +f 263/262/241 262/258/238 277/283/261 278/286/263 +f 271/263/242 270/261/240 285/285/262 286/287/264 +f 264/264/243 263/262/241 278/286/263 279/288/265 +f 272/265/244 271/263/242 286/287/264 287/272/251 +f 265/266/245 264/264/243 279/288/265 280/274/253 +f 352/289/40 291/280/259 306/290/266 +f 285/285/262 284/281/260 299/291/267 300/292/268 +f 278/286/263 277/283/261 292/293/269 293/294/270 +f 286/287/264 285/285/262 300/292/268 301/295/271 +f 279/288/265 278/286/263 293/294/270 294/296/272 +f 287/272/251 286/287/264 301/295/271 302/297/273 +f 280/274/253 279/288/265 294/296/272 295/298/274 +f 288/273/252 287/272/251 302/297/273 303/299/275 +f 281/275/254 280/274/253 295/298/274 296/300/276 +f 289/276/255 288/273/252 303/299/275 304/301/277 +f 282/277/256 281/275/254 296/300/276 297/302/278 +f 290/278/257 289/276/255 304/301/277 305/303/279 +f 283/279/258 282/277/256 297/302/278 298/304/280 +f 291/280/259 290/278/257 305/303/279 306/290/266 +f 284/281/260 283/279/258 298/304/280 299/291/267 +f 277/283/261 126/305/1 292/293/269 +f 304/301/277 303/299/275 318/306/281 319/307/282 +f 297/302/278 296/300/276 311/308/283 312/309/284 +f 305/303/279 304/301/277 319/307/282 320/310/285 +f 298/304/280 297/302/278 312/309/284 313/311/286 +f 306/290/266 305/303/279 320/310/285 321/312/287 +f 299/291/267 298/304/280 313/311/286 314/313/288 +f 292/293/269 126/314/1 307/315/289 +f 352/316/40 306/290/266 321/312/287 +f 300/292/268 299/291/267 314/313/288 315/317/290 +f 293/294/270 292/293/269 307/315/289 308/318/291 +f 301/295/271 300/292/268 315/317/290 316/319/292 +f 294/296/272 293/294/270 308/318/291 309/320/293 +f 302/297/273 301/295/271 316/319/292 317/321/294 +f 295/298/274 294/296/272 309/320/293 310/322/295 +f 303/299/275 302/297/273 317/321/294 318/306/281 +f 296/300/276 295/298/274 310/322/295 311/308/283 +f 308/318/291 307/315/289 322/323/296 323/324/297 +f 316/319/292 315/317/290 330/325/298 331/326/299 +f 309/320/293 308/318/291 323/324/297 324/327/300 +f 317/321/294 316/319/292 331/326/299 332/328/301 +f 310/322/295 309/320/293 324/327/300 325/329/302 +f 318/306/281 317/321/294 332/328/301 333/330/303 +f 311/308/283 310/322/295 325/329/302 326/331/304 +f 319/307/282 318/306/281 333/330/303 334/332/305 +f 312/309/284 311/308/283 326/331/304 327/333/306 +f 320/310/285 319/307/282 334/332/305 335/334/307 +f 313/311/286 312/309/284 327/333/306 328/335/308 +f 321/312/287 320/310/285 335/334/307 336/336/309 +f 314/313/288 313/311/286 328/335/308 329/337/310 +f 307/315/289 126/338/1 322/323/296 +f 352/339/40 321/312/287 336/336/309 +f 315/317/290 314/313/288 329/337/310 330/325/298 +f 327/333/306 326/331/304 341/340/311 342/341/312 +f 335/334/307 334/332/305 349/342/313 350/343/314 +f 328/335/308 327/333/306 342/341/312 343/344/315 +f 336/336/309 335/334/307 350/343/314 351/345/316 +f 329/337/310 328/335/308 343/344/315 344/346/317 +f 322/323/296 126/347/1 337/348/318 +f 352/349/40 336/336/309 351/345/316 +f 330/325/298 329/337/310 344/346/317 345/350/319 +f 323/324/297 322/323/296 337/348/318 338/351/320 +f 331/326/299 330/325/298 345/350/319 346/352/321 +f 324/327/300 323/324/297 338/351/320 339/353/322 +f 332/328/301 331/326/299 346/352/321 347/354/323 +f 325/329/302 324/327/300 339/353/322 340/355/324 +f 333/330/303 332/328/301 347/354/323 348/356/325 +f 326/331/304 325/329/302 340/355/324 341/340/311 +f 334/332/305 333/330/303 348/356/325 349/342/313 +f 346/352/321 345/350/319 361/357/326 362/358/327 +f 339/353/322 338/351/320 354/359/328 355/360/329 +f 347/354/323 346/352/321 362/358/327 363/361/330 +f 340/355/324 339/353/322 355/360/329 356/362/331 +f 348/356/325 347/354/323 363/361/330 364/363/332 +f 341/340/311 340/355/324 356/362/331 357/364/333 +f 349/342/313 348/356/325 364/363/332 365/365/334 +f 342/341/312 341/340/311 357/364/333 358/366/335 +f 350/343/314 349/342/313 365/365/334 366/367/336 +f 343/344/315 342/341/312 358/366/335 359/368/337 +f 351/345/316 350/343/314 366/367/336 367/369/338 +f 344/346/317 343/344/315 359/368/337 360/370/339 +f 337/348/318 126/371/1 353/372/340 +f 352/373/40 351/345/316 367/369/338 +f 345/350/319 344/346/317 360/370/339 361/357/326 +f 338/351/320 337/348/318 353/372/340 354/359/328 +f 366/367/336 365/365/334 380/374/341 381/375/342 +f 359/368/337 358/366/335 373/376/343 374/377/344 +f 367/369/338 366/367/336 381/375/342 382/378/345 +f 360/370/339 359/368/337 374/377/344 375/379/346 +f 353/372/340 126/380/1 368/381/347 +f 352/382/40 367/369/338 382/378/345 +f 361/357/326 360/370/339 375/379/346 376/383/348 +f 354/359/328 353/372/340 368/381/347 369/384/349 +f 362/358/327 361/357/326 376/383/348 377/385/350 +f 355/360/329 354/359/328 369/384/349 370/386/351 +f 363/361/330 362/358/327 377/385/350 378/387/352 +f 356/362/331 355/360/329 370/386/351 371/388/353 +f 364/363/332 363/361/330 378/387/352 379/389/354 +f 357/364/333 356/362/331 371/388/353 372/390/355 +f 365/365/334 364/363/332 379/389/354 380/374/341 +f 358/366/335 357/364/333 372/390/355 373/376/343 +f 370/386/351 369/384/349 384/391/356 385/392/357 +f 378/387/352 377/385/350 392/393/358 393/394/359 +f 371/388/353 370/386/351 385/392/357 386/395/360 +f 379/389/354 378/387/352 393/394/359 394/396/361 +f 372/390/355 371/388/353 386/395/360 387/397/362 +f 380/374/341 379/389/354 394/396/361 395/398/363 +f 373/376/343 372/390/355 387/397/362 388/399/364 +f 381/375/342 380/374/341 395/398/363 396/400/365 +f 374/377/344 373/376/343 388/399/364 389/401/366 +f 382/378/345 381/375/342 396/400/365 397/402/367 +f 375/379/346 374/377/344 389/401/366 390/403/368 +f 368/381/347 126/404/1 383/405/369 +f 352/406/40 382/378/345 397/402/367 +f 376/383/348 375/379/346 390/403/368 391/407/370 +f 369/384/349 368/381/347 383/405/369 384/391/356 +f 377/385/350 376/383/348 391/407/370 392/393/358 +f 389/401/366 388/399/364 403/408/371 404/409/372 +f 397/402/367 396/400/365 411/410/373 412/411/374 +f 390/403/368 389/401/366 404/409/372 405/412/375 +f 383/405/369 126/413/1 398/414/376 +f 352/415/40 397/402/367 412/411/374 +f 391/407/370 390/403/368 405/412/375 406/416/377 +f 384/391/356 383/405/369 398/414/376 399/417/378 +f 392/393/358 391/407/370 406/416/377 407/418/379 +f 385/392/357 384/391/356 399/417/378 400/419/380 +f 393/394/359 392/393/358 407/418/379 408/420/381 +f 386/395/360 385/392/357 400/419/380 401/421/382 +f 394/396/361 393/394/359 408/420/381 409/422/383 +f 387/397/362 386/395/360 401/421/382 402/423/384 +f 395/398/363 394/396/361 409/422/383 410/424/385 +f 388/399/364 387/397/362 402/423/384 403/408/371 +f 396/400/365 395/398/363 410/424/385 411/410/373 +f 408/425/381 407/426/379 422/427/386 423/428/387 +f 401/429/382 400/430/380 415/431/388 416/432/389 +f 409/433/383 408/425/381 423/428/387 424/434/390 +f 402/435/384 401/429/382 416/432/389 417/436/391 +f 410/437/385 409/433/383 424/434/390 425/438/392 +f 403/439/371 402/435/384 417/436/391 418/440/393 +f 411/441/373 410/437/385 425/438/392 426/442/394 +f 404/443/372 403/439/371 418/440/393 419/444/395 +f 412/445/374 411/441/373 426/442/394 427/446/396 +f 405/447/375 404/443/372 419/444/395 420/448/397 +f 398/449/376 126/450/1 413/451/398 +f 352/452/40 412/445/374 427/446/396 +f 406/453/377 405/447/375 420/448/397 421/454/399 +f 399/455/378 398/449/376 413/451/398 414/456/400 +f 407/426/379 406/453/377 421/454/399 422/427/386 +f 400/430/380 399/455/378 414/456/400 415/431/388 +f 427/446/396 426/442/394 441/457/401 442/458/402 +f 420/448/397 419/444/395 434/459/403 435/460/404 +f 413/451/398 126/461/1 428/462/405 +f 352/463/40 427/446/396 442/458/402 +f 421/454/399 420/448/397 435/460/404 436/464/406 +f 414/456/400 413/451/398 428/462/405 429/465/407 +f 422/427/386 421/454/399 436/464/406 437/466/408 +f 415/431/388 414/456/400 429/465/407 430/467/409 +f 423/428/387 422/427/386 437/466/408 438/468/410 +f 416/432/389 415/431/388 430/467/409 431/469/411 +f 424/434/390 423/428/387 438/468/410 439/470/412 +f 417/436/391 416/432/389 431/469/411 432/471/413 +f 425/438/392 424/434/390 439/470/412 440/472/414 +f 418/440/393 417/436/391 432/471/413 433/473/415 +f 426/442/394 425/438/392 440/472/414 441/457/401 +f 419/444/395 418/440/393 433/473/415 434/459/403 +f 439/470/412 438/468/410 453/474/416 454/475/417 +f 432/471/413 431/469/411 446/476/418 447/477/419 +f 440/472/414 439/470/412 454/475/417 455/478/420 +f 433/473/415 432/471/413 447/477/419 448/479/421 +f 441/457/401 440/472/414 455/478/420 456/480/422 +f 434/459/403 433/473/415 448/479/421 449/481/423 +f 442/458/402 441/457/401 456/480/422 457/482/424 +f 435/460/404 434/459/403 449/481/423 450/483/425 +f 428/462/405 126/484/1 443/485/426 +f 352/486/40 442/458/402 457/482/424 +f 436/464/406 435/460/404 450/483/425 451/487/427 +f 429/465/407 428/462/405 443/485/426 444/488/428 +f 437/466/408 436/464/406 451/487/427 452/489/429 +f 430/467/409 429/465/407 444/488/428 445/490/430 +f 438/468/410 437/466/408 452/489/429 453/474/416 +f 431/469/411 430/467/409 445/490/430 446/476/418 +f 443/485/426 126/491/1 458/492/431 +f 352/493/40 457/482/424 472/494/432 +f 451/487/427 450/483/425 465/495/433 466/496/434 +f 444/488/428 443/485/426 458/492/431 459/497/435 +f 452/489/429 451/487/427 466/496/434 467/498/436 +f 445/490/430 444/488/428 459/497/435 460/499/437 +f 453/474/416 452/489/429 467/498/436 468/500/438 +f 446/476/418 445/490/430 460/499/437 461/501/439 +f 454/475/417 453/474/416 468/500/438 469/502/440 +f 447/477/419 446/476/418 461/501/439 462/503/441 +f 455/478/420 454/475/417 469/502/440 470/504/442 +f 448/479/421 447/477/419 462/503/441 463/505/443 +f 456/480/422 455/478/420 470/504/442 471/506/444 +f 449/481/423 448/479/421 463/505/443 464/507/445 +f 457/482/424 456/480/422 471/506/444 472/494/432 +f 450/483/425 449/481/423 464/507/445 465/495/433 +f 462/503/441 461/501/439 476/508/446 477/509/447 +f 470/504/442 469/502/440 484/510/448 485/511/449 +f 463/505/443 462/503/441 477/509/447 478/512/450 +f 471/506/444 470/504/442 485/511/449 486/513/451 +f 464/507/445 463/505/443 478/512/450 479/514/452 +f 472/494/432 471/506/444 486/513/451 487/515/453 +f 465/495/433 464/507/445 479/514/452 480/516/454 +f 458/492/431 126/517/1 473/518/455 +f 352/519/40 472/494/432 487/515/453 +f 466/496/434 465/495/433 480/516/454 481/520/456 +f 459/497/435 458/492/431 473/518/455 474/521/457 +f 467/498/436 466/496/434 481/520/456 482/522/458 +f 460/499/437 459/497/435 474/521/457 475/523/459 +f 468/500/438 467/498/436 482/522/458 483/524/460 +f 461/501/439 460/499/437 475/523/459 476/508/446 +f 469/502/440 468/500/438 483/524/460 484/510/448 +f 481/520/456 480/516/454 495/525/461 496/526/462 +f 474/521/457 473/518/455 488/527/463 489/528/464 +f 482/522/458 481/520/456 496/526/462 497/529/465 +f 475/523/459 474/521/457 489/528/464 490/530/466 +f 483/524/460 482/522/458 497/529/465 498/531/467 +f 476/508/446 475/523/459 490/530/466 491/532/468 +f 484/510/448 483/524/460 498/531/467 499/533/469 +f 477/509/447 476/508/446 491/532/468 492/534/470 +f 485/511/449 484/510/448 499/533/469 500/535/471 +f 478/512/450 477/509/447 492/534/470 493/536/472 +f 486/513/451 485/511/449 500/535/471 501/537/473 +f 479/514/452 478/512/450 493/536/472 494/538/474 +f 487/515/453 486/513/451 501/537/473 502/539/475 +f 480/516/454 479/514/452 494/538/474 495/525/461 +f 473/518/455 126/540/1 488/527/463 +f 352/541/40 487/515/453 502/539/475 +f 500/535/471 499/533/469 514/542/476 515/543/477 +f 493/536/472 492/534/470 507/544/478 508/545/479 +f 501/537/473 500/535/471 515/543/477 516/546/480 +f 494/538/474 493/536/472 508/545/479 509/547/481 +f 502/539/475 501/537/473 516/546/480 517/548/482 +f 495/525/461 494/538/474 509/547/481 510/549/483 +f 488/527/463 126/550/1 503/551/484 +f 352/552/40 502/539/475 517/548/482 +f 496/526/462 495/525/461 510/549/483 511/553/485 +f 489/528/464 488/527/463 503/551/484 504/554/486 +f 497/529/465 496/526/462 511/553/485 512/555/487 +f 490/530/466 489/528/464 504/554/486 505/556/488 +f 498/531/467 497/529/465 512/555/487 513/557/489 +f 491/532/468 490/530/466 505/556/488 506/558/490 +f 499/533/469 498/531/467 513/557/489 514/542/476 +f 492/534/470 491/532/468 506/558/490 507/544/478 +f 504/554/486 503/551/484 518/7/15 519/6/14 +f 512/555/487 511/553/485 49/2/10 522/10/18 +f 505/556/488 504/554/486 519/6/14 45/12/20 +f 513/557/489 512/555/487 522/10/18 50/14/22 +f 506/558/490 505/556/488 45/12/20 520/16/24 +f 514/542/476 513/557/489 50/14/22 523/18/26 +f 507/544/478 506/558/490 520/16/24 46/20/28 +f 515/543/477 514/542/476 523/18/26 524/22/30 +f 508/545/479 507/544/478 46/20/28 521/24/32 +f 516/546/480 515/543/477 524/22/30 525/26/34 +f 509/547/481 508/545/479 521/24/32 47/28/36 +f 517/548/482 516/546/480 525/26/34 526/30/38 +f 510/549/483 509/547/481 47/28/36 48/3/11 +f 503/551/484 126/559/1 518/7/15 +f 352/560/40 517/548/482 526/30/38 +f 511/553/485 510/549/483 48/3/11 49/2/10 +f 661/561/491 662/562/492 664/563/493 663/564/494 +f 662/562/492 660/565/495 1043/565/496 1035/562/497 +f 529/447/498 530/566/499 532/567/500 531/568/501 +f 656/569/498 657/570/501 659/571/502 661/572/491 663/573/494 665/574/503 667/575/504 669/576/505 671/577/506 673/578/507 675/579/508 677/580/509 679/581/510 681/582/511 683/583/512 685/584/513 687/585/514 689/586/515 691/587/516 693/588/517 695/589/518 697/590/519 699/591/520 701/592/521 703/593/522 705/594/523 707/595/524 709/596/525 711/597/526 713/598/527 715/599/528 717/600/529 +f 649/601/527 650/602/530 652/603/531 651/604/528 +f 531/568/501 532/567/500 534/565/495 533/605/502 +f 665/606/503 666/607/532 668/608/533 667/609/504 +f 647/610/526 648/611/534 650/602/530 649/601/527 +f 533/605/502 534/565/495 536/562/492 535/561/491 +f 667/609/504 668/608/533 670/612/535 669/613/505 +f 645/614/525 646/615/536 648/611/534 647/610/526 +f 535/561/491 536/562/492 538/563/493 537/564/494 +f 669/613/505 670/612/535 672/616/537 671/3/506 +f 643/617/524 644/618/538 646/615/536 645/614/525 +f 537/564/494 538/563/493 540/607/532 539/606/503 +f 671/3/506 672/616/537 674/619/539 673/4/507 +f 641/620/523 642/621/540 644/618/538 643/617/524 +f 539/606/503 540/607/532 542/608/533 541/609/504 +f 673/4/507 674/619/539 676/622/541 675/35/508 +f 639/623/522 640/624/542 642/621/540 641/620/523 +f 541/609/504 542/608/533 544/612/535 543/613/505 +f 675/35/508 676/622/541 678/625/543 677/60/509 +f 637/626/521 638/627/544 640/624/542 639/623/522 +f 543/613/505 544/612/535 546/616/545 545/3/506 +f 677/60/509 678/625/543 680/628/546 679/72/510 +f 635/629/520 636/630/547 638/627/544 637/626/521 +f 545/3/506 546/616/545 548/619/539 547/4/507 +f 679/72/510 680/628/546 682/631/548 681/93/511 +f 633/632/519 634/633/549 636/630/547 635/629/520 +f 547/4/507 548/619/539 550/622/541 549/35/508 +f 681/93/511 682/631/548 684/634/550 683/102/512 +f 631/635/518 632/636/551 634/633/549 633/632/519 +f 549/35/508 550/622/541 552/625/543 551/60/509 +f 683/102/512 684/634/550 686/637/552 685/126/513 +f 629/638/517 630/639/553 632/636/551 631/635/518 +f 551/60/509 552/625/543 554/628/546 553/72/510 +f 685/126/513 686/637/552 688/640/554 687/641/514 +f 627/642/516 628/643/555 630/639/553 629/638/517 +f 553/72/510 554/628/546 556/631/548 555/93/511 +f 687/641/514 688/640/554 690/644/556 689/645/515 +f 625/645/515 626/644/556 628/643/555 627/642/516 +f 555/93/511 556/631/548 558/634/550 557/102/512 +f 689/645/515 690/644/556 692/643/555 691/642/516 +f 623/641/514 624/640/554 626/644/556 625/645/515 +f 557/102/512 558/634/550 560/637/552 559/126/513 +f 691/642/516 692/643/555 694/639/553 693/638/517 +f 621/126/513 622/637/552 624/640/554 623/641/514 +f 559/126/513 560/637/552 562/640/554 561/641/514 +f 693/638/517 694/639/553 696/636/551 695/635/518 +f 619/102/512 620/634/550 622/637/552 621/126/513 +f 561/641/514 562/640/554 564/644/556 563/645/515 +f 695/635/518 696/636/551 698/633/549 697/632/519 +f 617/93/511 618/631/548 620/634/550 619/102/512 +f 563/645/515 564/644/556 566/643/555 565/642/516 +f 697/632/519 698/633/549 700/630/547 699/629/520 +f 615/72/510 616/628/546 618/631/548 617/93/511 +f 565/642/516 566/643/555 568/639/553 567/638/517 +f 699/629/520 700/630/547 702/627/544 701/626/521 +f 613/60/509 614/625/543 616/628/546 615/72/510 +f 567/638/517 568/639/553 570/636/551 569/635/518 +f 701/626/521 702/627/544 704/624/542 703/623/522 +f 611/35/508 612/622/541 614/625/543 613/60/509 +f 569/635/518 570/636/551 572/633/549 571/632/519 +f 703/623/522 704/624/542 706/621/540 705/620/523 +f 609/4/507 610/619/539 612/622/541 611/35/508 +f 571/632/519 572/633/549 574/630/547 573/629/520 +f 705/620/523 706/621/540 708/618/538 707/617/524 +f 607/3/506 608/616/545 610/619/539 609/4/507 +f 573/629/520 574/630/547 576/627/544 575/626/521 +f 707/617/524 708/618/538 710/615/536 709/614/525 +f 605/613/505 606/612/535 608/616/545 607/3/506 +f 575/626/521 576/627/544 578/624/542 577/623/522 +f 709/614/525 710/615/536 712/611/534 711/610/526 +f 603/609/504 604/608/533 606/612/535 605/613/505 +f 577/623/522 578/624/542 580/621/540 579/620/523 +f 711/610/526 712/611/534 714/602/530 713/601/527 +f 601/606/503 602/607/532 604/608/533 603/609/504 +f 579/620/523 580/621/540 582/618/538 581/617/524 +f 713/601/527 714/602/530 716/603/531 715/604/528 +f 599/564/494 600/563/493 602/607/532 601/606/503 +f 581/617/524 582/618/538 584/615/536 583/614/525 +f 594/567/500 527/566/499 923/566/557 899/567/558 +f 597/561/491 598/562/492 600/563/493 599/564/494 +f 583/614/525 584/615/536 586/611/534 585/610/526 +f 528/569/498 593/570/501 595/571/502 597/572/491 599/573/494 601/574/503 603/575/504 605/576/505 607/577/506 609/578/507 611/579/508 613/580/509 615/581/510 617/582/511 619/583/512 621/584/513 623/585/514 625/586/515 627/587/516 629/588/517 631/589/518 633/590/519 635/591/520 637/592/521 639/593/522 641/594/523 643/595/524 645/596/525 647/597/526 649/598/527 651/599/528 653/600/529 +f 595/605/502 596/565/495 598/562/492 597/561/491 +f 585/610/526 586/611/534 588/602/530 587/601/527 +f 653/646/529 654/647/559 527/648/499 528/412/498 +f 593/568/501 594/567/500 596/565/495 595/605/502 +f 587/601/527 588/602/530 590/603/531 589/604/528 +f 608/616/545 606/612/535 779/612/560 759/616/561 +f 528/447/498 527/566/499 594/567/500 593/568/501 +f 589/604/528 590/603/531 592/647/559 591/646/529 +f 663/564/494 664/563/493 666/607/532 665/606/503 +f 651/604/528 652/603/531 654/647/559 653/646/529 +f 591/646/529 592/647/559 530/648/499 529/412/498 +f 529/569/498 531/570/501 533/571/502 535/572/491 537/573/494 539/574/503 541/575/504 543/576/505 545/577/506 547/578/507 549/579/508 551/580/509 553/581/510 555/582/511 557/583/512 559/584/513 561/585/514 563/586/515 565/587/516 567/588/517 569/589/518 571/590/519 573/591/520 575/592/521 577/593/522 579/594/523 581/595/524 583/596/525 585/597/526 587/598/527 589/599/528 591/600/529 +f 659/605/502 660/565/495 662/562/492 661/561/491 +f 717/646/529 718/647/559 655/648/499 656/412/498 +f 657/568/501 658/567/500 660/565/495 659/605/502 +f 656/447/498 655/566/499 658/567/500 657/568/501 +f 715/604/528 716/603/531 718/647/559 717/646/529 +f 636/630/547 634/633/549 720/633/562 936/630/563 +f 700/630/547 698/633/549 976/633/562 1064/630/563 +f 534/565/495 532/567/500 728/567/558 744/649/496 +f 706/621/540 704/624/542 1072/624/564 1076/621/565 +f 900/650/566 924/651/567 971/652/568 967/653/569 963/654/570 959/655/571 955/656/572 951/657/573 947/658/574 943/659/575 939/660/576 935/661/577 719/662/578 724/663/579 752/664/580 772/665/581 792/666/582 812/667/583 832/668/584 852/669/585 872/670/586 892/671/587 912/672/588 735/673/589 740/674/590 760/675/591 780/676/592 800/677/593 820/678/594 840/679/595 860/680/596 880/681/597 +f 574/630/547 572/633/549 868/633/562 876/630/563 +f 654/647/559 652/603/531 968/603/598 972/647/599 +f 612/622/541 610/619/539 739/619/600 736/622/601 +f 670/612/535 668/608/533 1011/608/602 1003/612/560 +f 622/637/552 620/634/550 851/634/603 831/637/604 +f 548/619/539 546/616/545 784/616/561 788/619/600 +f 682/631/548 680/628/546 1047/628/605 1039/631/606 +f 570/636/551 568/639/553 856/639/607 864/636/608 +f 604/608/533 602/607/532 819/607/609 799/608/602 +f 632/636/551 630/639/553 751/639/607 723/636/608 +f 708/618/538 706/621/540 1076/621/565 1080/618/610 +f 698/633/549 696/636/551 979/636/608 976/633/562 +f 544/612/535 542/608/533 768/608/602 776/612/560 +f 586/611/534 584/615/536 908/615/611 916/611/612 +f 727/682/566 732/683/567 931/684/568 927/685/569 919/686/570 915/687/571 907/688/613 903/689/573 895/690/574 887/691/575 883/692/576 875/693/577 867/694/578 863/695/579 855/696/580 847/697/614 843/698/582 835/699/583 827/700/584 823/701/585 815/702/586 807/703/587 803/704/588 795/705/589 787/706/590 783/707/591 775/708/592 767/709/593 763/710/594 755/711/595 747/712/596 743/713/597 +f 690/644/556 688/640/554 1015/640/615 1007/644/616 +f 660/565/495 658/567/500 1051/567/558 1043/565/496 +f 618/631/548 616/628/546 891/628/605 871/631/606 +f 560/637/552 558/634/550 824/634/603 828/637/604 +f 640/624/542 638/627/544 940/627/617 944/624/564 +f 540/607/532 538/563/493 756/563/618 764/607/609 +f 710/615/536 708/618/538 1080/618/610 1084/615/611 +f 582/618/538 580/621/540 896/621/565 904/618/610 +f 600/563/493 598/562/492 859/562/497 839/563/618 +f 592/647/559 590/603/531 928/603/598 932/647/599 +f 668/608/533 666/607/532 1019/607/609 1011/608/602 +f 556/631/548 554/628/546 808/628/605 816/631/606 +f 680/628/546 678/625/543 1055/625/619 1047/628/605 +f 1052/714/566 1060/715/567 1099/716/568 1095/717/569 1091/718/570 1087/719/571 1083/720/613 1079/721/573 1075/722/574 1071/723/575 1067/724/576 1063/725/577 975/726/578 980/727/579 992/728/580 1000/729/614 1008/730/582 1016/731/583 1024/732/584 1032/733/585 1040/734/586 1048/735/587 1056/736/588 983/737/589 988/738/590 996/739/591 1004/740/592 1012/741/593 1020/742/594 1028/743/595 1036/744/596 1044/745/597 +f 642/621/540 640/624/542 944/624/564 948/746/565 +f 628/643/555 626/644/556 791/644/616 771/643/620 +f 712/611/534 710/615/536 1084/615/611 1088/611/612 +f 614/625/543 612/622/541 736/622/601 911/625/619 +f 588/602/530 586/611/534 916/611/612 920/747/621 +f 572/633/549 570/636/551 864/636/608 868/633/562 +f 552/625/543 550/622/541 796/622/601 804/748/619 +f 530/648/499 592/647/559 932/647/599 731/648/557 +f 596/565/495 594/567/500 899/567/558 879/649/496 +f 688/640/554 686/637/552 1023/637/604 1015/640/615 +f 658/567/500 655/566/499 1059/566/557 1051/567/558 +f 568/639/553 566/643/555 848/643/620 856/639/607 +f 644/618/538 642/621/540 948/621/565 952/618/610 +f 714/602/530 712/611/534 1088/611/612 1092/602/621 +f 678/625/543 676/622/541 984/622/601 1055/748/619 +f 624/640/554 622/637/552 831/637/604 811/640/615 +f 542/608/533 540/607/532 764/607/609 768/608/602 +f 666/607/532 664/563/493 1027/563/618 1019/607/609 +f 564/644/556 562/640/554 836/640/615 844/644/616 +f 606/612/535 604/608/533 799/608/602 779/612/560 +f 590/603/531 588/602/530 920/602/621 928/603/598 +f 646/615/536 644/618/538 952/618/610 956/615/611 +f 716/603/531 714/602/530 1092/602/621 1096/603/598 +f 538/563/493 536/562/492 748/562/497 756/749/618 +f 580/621/540 578/624/542 888/624/564 896/621/565 +f 676/622/541 674/619/539 987/619/600 984/750/601 +f 655/648/499 718/647/559 1100/647/599 1059/648/557 +f 686/637/552 684/634/550 1031/634/603 1023/637/604 +f 620/634/550 618/631/548 871/631/606 851/634/603 +f 554/628/546 552/625/543 804/625/619 808/628/605 +f 532/567/500 530/566/499 731/566/557 728/567/558 +f 674/619/539 672/616/537 995/616/561 987/619/600 +f 576/627/544 574/630/547 876/630/563 884/627/617 +f 602/607/532 600/563/493 839/563/618 819/607/609 +f 648/611/534 646/615/536 956/615/611 960/611/612 +f 718/647/559 716/603/531 1096/603/598 1100/647/599 +f 584/615/536 582/618/538 904/618/610 908/615/611 +f 694/639/553 692/643/555 999/643/620 991/639/607 +f 550/622/541 548/619/539 788/619/600 796/622/601 +f 527/648/499 654/647/559 972/647/599 923/648/557 +f 664/563/493 662/562/492 1035/562/497 1027/749/618 +f 630/639/553 628/643/555 771/643/620 751/639/607 +f 696/636/551 694/639/553 991/639/607 979/636/608 +f 616/628/546 614/625/543 911/625/619 891/628/605 +f 566/643/555 564/644/556 844/644/616 848/643/620 +f 650/602/530 648/611/534 960/611/612 964/747/621 +f 546/616/545 544/612/535 776/751/560 784/752/561 +f 610/619/539 608/616/545 759/616/561 739/619/600 +f 598/562/492 596/565/495 879/565/496 859/562/497 +f 672/616/537 670/612/535 1003/612/560 995/616/561 +f 684/634/550 682/631/548 1039/631/606 1031/634/603 +f 562/640/554 560/637/552 828/637/604 836/640/615 +f 704/624/542 702/627/544 1068/627/617 1072/624/564 +f 652/603/531 650/602/530 964/602/621 968/603/598 +f 626/644/556 624/640/554 811/640/615 791/644/616 +f 702/627/544 700/630/547 1064/630/563 1068/627/617 +f 638/627/544 636/630/547 936/630/563 940/627/617 +f 536/562/492 534/565/495 744/565/496 748/562/497 +f 578/624/542 576/627/544 884/627/617 888/624/564 +f 692/643/555 690/644/556 1007/644/616 999/753/620 +f 558/634/550 556/631/548 816/631/606 824/634/603 +f 720/633/562 723/636/608 725/754/622 722/755/623 +f 722/755/623 725/754/622 726/756/624 721/757/625 +f 721/758/625 726/759/624 724/663/579 719/662/578 +f 728/567/558 731/566/557 733/760/626 730/761/627 +f 730/761/627 733/760/626 734/762/628 729/763/629 +f 729/764/629 734/765/628 732/683/567 727/682/566 +f 736/622/601 739/619/600 741/766/630 738/767/631 +f 738/767/631 741/766/630 742/768/632 737/769/633 +f 737/770/633 742/771/632 740/674/590 735/673/589 +f 744/649/496 728/567/558 730/772/627 746/773/634 +f 746/773/634 730/772/627 729/774/629 745/775/635 +f 745/776/635 729/777/629 727/682/566 743/713/597 +f 748/562/497 744/565/496 746/778/634 750/779/636 +f 750/779/636 746/778/634 745/780/635 749/781/637 +f 749/782/637 745/783/635 743/713/597 747/712/596 +f 723/636/608 751/639/607 753/784/638 725/785/622 +f 725/785/622 753/784/638 754/786/639 726/787/624 +f 726/788/624 754/789/639 752/664/580 724/663/579 +f 756/749/618 748/562/497 750/790/636 758/791/640 +f 758/791/640 750/790/636 749/792/637 757/793/641 +f 757/794/641 749/795/637 747/712/596 755/711/595 +f 739/619/600 759/616/561 761/796/642 741/797/630 +f 741/797/630 761/796/642 762/798/643 742/799/632 +f 742/800/632 762/801/643 760/675/591 740/674/590 +f 764/607/609 756/563/618 758/802/640 766/803/644 +f 766/803/644 758/802/640 757/804/641 765/805/645 +f 765/806/645 757/807/641 755/711/595 763/710/594 +f 768/608/602 764/607/609 766/808/644 770/809/646 +f 770/809/646 766/808/644 765/810/645 769/811/647 +f 769/812/647 765/813/645 763/710/594 767/709/593 +f 751/639/607 771/643/620 773/814/648 753/815/638 +f 753/815/638 773/814/648 774/816/649 754/817/639 +f 754/818/639 774/819/649 772/665/581 752/664/580 +f 776/612/560 768/608/602 770/820/646 778/821/650 +f 778/821/650 770/820/646 769/822/647 777/823/651 +f 777/824/651 769/825/647 767/709/593 775/708/592 +f 759/616/561 779/612/560 781/826/650 761/827/642 +f 761/827/642 781/826/650 782/828/651 762/829/643 +f 762/830/643 782/831/651 780/676/592 760/675/591 +f 784/752/561 776/751/560 778/826/650 786/832/652 +f 786/832/652 778/826/650 777/833/651 785/834/643 +f 785/835/643 777/836/651 775/708/592 783/707/591 +f 788/619/600 784/616/561 786/837/652 790/838/630 +f 790/838/630 786/837/652 785/839/643 789/840/632 +f 789/841/632 785/842/643 783/707/591 787/706/590 +f 771/643/620 791/644/616 793/843/653 773/844/648 +f 773/844/648 793/843/653 794/845/654 774/846/649 +f 774/847/649 794/848/654 792/666/582 772/665/581 +f 796/622/601 788/619/600 790/849/630 798/850/631 +f 798/850/631 790/849/630 789/851/632 797/852/633 +f 797/853/633 789/854/632 787/706/590 795/705/589 +f 779/612/560 799/608/602 801/855/646 781/856/650 +f 781/856/650 801/855/646 802/857/647 782/858/651 +f 782/859/651 802/860/647 800/677/593 780/676/592 +f 804/748/619 796/622/601 798/861/631 806/862/655 +f 806/862/655 798/861/631 797/863/633 805/864/656 +f 805/865/656 797/866/633 795/705/589 803/704/588 +f 808/628/605 804/625/619 806/867/655 810/868/657 +f 810/868/657 806/867/655 805/869/656 809/870/658 +f 809/871/658 805/872/656 803/704/588 807/703/587 +f 791/644/616 811/640/615 813/873/659 793/874/653 +f 793/874/653 813/873/659 814/875/660 794/876/654 +f 794/877/654 814/878/660 812/667/583 792/666/582 +f 816/631/606 808/628/605 810/879/657 818/880/661 +f 818/880/661 810/879/657 809/881/658 817/882/662 +f 817/883/662 809/884/658 807/703/587 815/702/586 +f 799/608/602 819/607/609 821/885/644 801/886/646 +f 801/886/646 821/885/644 822/887/645 802/811/647 +f 802/888/647 822/889/645 820/678/594 800/677/593 +f 824/634/603 816/631/606 818/890/661 826/891/663 +f 826/891/663 818/890/661 817/892/662 825/893/664 +f 825/894/664 817/895/662 815/702/586 823/701/585 +f 828/637/604 824/634/603 826/896/663 830/897/665 +f 830/897/665 826/896/663 825/898/664 829/899/666 +f 829/900/666 825/901/664 823/701/585 827/700/584 +f 811/640/615 831/637/604 833/902/665 813/903/659 +f 813/903/659 833/902/665 834/904/666 814/905/660 +f 814/906/660 834/907/666 832/668/584 812/667/583 +f 836/640/615 828/637/604 830/908/665 838/903/667 +f 838/903/667 830/908/665 829/909/666 837/910/668 +f 837/911/668 829/912/666 827/700/584 835/699/583 +f 819/607/609 839/563/618 841/913/640 821/914/644 +f 821/914/644 841/913/640 842/915/641 822/916/645 +f 822/917/645 842/918/641 840/679/595 820/678/594 +f 844/644/616 836/640/615 838/919/667 846/920/653 +f 846/920/653 838/919/667 837/921/668 845/922/654 +f 845/923/654 837/924/668 835/699/583 843/698/582 +f 848/643/620 844/644/616 846/925/653 850/926/648 +f 850/926/648 846/925/653 845/927/654 849/928/669 +f 849/929/669 845/930/654 843/698/582 847/697/614 +f 831/637/604 851/634/603 853/931/663 833/932/665 +f 833/932/665 853/931/663 854/933/670 834/934/666 +f 834/935/666 854/936/670 852/669/585 832/668/584 +f 856/639/607 848/643/620 850/937/648 858/815/638 +f 858/815/638 850/937/648 849/938/669 857/939/639 +f 857/940/639 849/941/669 847/697/614 855/696/580 +f 839/563/618 859/562/497 861/790/636 841/942/640 +f 841/942/640 861/790/636 862/943/637 842/944/641 +f 842/945/641 862/946/637 860/680/596 840/679/595 +f 864/636/608 856/639/607 858/947/638 866/948/622 +f 866/948/622 858/947/638 857/949/639 865/950/624 +f 865/951/624 857/952/639 855/696/580 863/695/579 +f 868/633/562 864/636/608 866/953/622 870/954/623 +f 870/954/623 866/953/622 865/955/624 869/956/671 +f 869/957/671 865/958/624 863/695/579 867/694/578 +f 851/634/603 871/631/606 873/959/661 853/960/663 +f 853/960/663 873/959/661 874/961/662 854/962/670 +f 854/963/670 874/964/662 872/670/586 852/669/585 +f 876/630/563 868/633/562 870/965/623 878/966/672 +f 878/966/672 870/965/623 869/967/671 877/968/673 +f 877/969/673 869/970/671 867/694/578 875/693/577 +f 859/562/497 879/565/496 881/971/674 861/972/636 +f 861/972/636 881/971/674 882/973/635 862/974/637 +f 862/975/637 882/976/635 880/681/597 860/680/596 +f 884/627/617 876/630/563 878/977/672 886/978/675 +f 886/978/675 878/977/672 877/979/673 885/980/676 +f 885/981/676 877/982/673 875/693/577 883/692/576 +f 888/624/564 884/627/617 886/983/675 890/984/677 +f 890/984/677 886/983/675 885/985/676 889/986/678 +f 889/987/678 885/988/676 883/692/576 887/691/575 +f 871/631/606 891/628/605 893/879/657 873/989/661 +f 873/989/661 893/879/657 894/990/658 874/991/662 +f 874/992/662 894/993/658 892/671/587 872/670/586 +f 896/621/565 888/624/564 890/994/677 898/995/679 +f 898/995/679 890/994/677 889/996/678 897/997/680 +f 897/998/680 889/999/678 887/691/575 895/690/574 +f 879/649/496 899/567/558 901/1000/627 881/1001/674 +f 881/1001/674 901/1000/627 902/774/629 882/1002/635 +f 882/1003/635 902/1004/629 900/650/566 880/681/597 +f 904/618/610 896/621/565 898/1005/679 906/1006/681 +f 906/1006/681 898/1005/679 897/1007/680 905/1008/682 +f 905/1009/682 897/1010/680 895/690/574 903/689/573 +f 908/615/611 904/618/610 906/1011/681 910/1012/683 +f 910/1012/683 906/1011/681 905/1013/682 909/1014/684 +f 909/1015/684 905/1016/682 903/689/573 907/688/613 +f 891/628/605 911/625/619 913/1017/655 893/1018/657 +f 893/1018/657 913/1017/655 914/1019/656 894/1020/658 +f 894/1021/658 914/1022/656 912/672/588 892/671/587 +f 916/611/612 908/615/611 910/1023/683 918/1024/685 +f 918/1024/685 910/1023/683 909/1025/684 917/1026/686 +f 917/1027/686 909/1028/684 907/688/613 915/687/571 +f 920/747/621 916/611/612 918/1029/685 922/1030/687 +f 922/1030/687 918/1029/685 917/1031/686 921/1032/688 +f 921/1033/688 917/1034/686 915/687/571 919/686/570 +f 899/567/558 923/566/557 925/1035/626 901/1036/627 +f 901/1036/627 925/1035/626 926/1037/628 902/1038/629 +f 902/1039/629 926/1040/628 924/651/567 900/650/566 +f 928/603/598 920/602/621 922/1041/687 930/1042/689 +f 930/1042/689 922/1041/687 921/1043/688 929/1044/690 +f 929/1045/690 921/1046/688 919/686/570 927/685/569 +f 911/625/619 736/622/601 738/1047/631 913/1048/655 +f 913/1048/655 738/1047/631 737/1049/633 914/1050/656 +f 914/1051/656 737/1052/633 735/673/589 912/672/588 +f 932/647/599 928/603/598 930/1053/689 934/1054/691 +f 934/1054/691 930/1053/689 929/1055/690 933/1056/692 +f 933/1057/692 929/1058/690 927/685/569 931/684/568 +f 731/648/557 932/647/599 934/1059/691 733/1060/626 +f 733/1060/626 934/1059/691 933/1061/692 734/1062/628 +f 734/1063/628 933/1064/692 931/684/568 732/683/567 +f 936/630/563 720/633/562 722/1065/623 938/1066/672 +f 938/1066/672 722/1065/623 721/1067/625 937/1068/693 +f 937/1069/693 721/1070/625 719/662/578 935/661/577 +f 940/627/617 936/630/563 938/1071/672 942/1072/675 +f 942/1072/675 938/1071/672 937/1073/693 941/1074/694 +f 941/1075/694 937/1076/693 935/661/577 939/660/576 +f 944/624/564 940/627/617 942/1077/675 946/1078/677 +f 946/1078/677 942/1077/675 941/1079/694 945/1080/678 +f 945/1081/678 941/1082/694 939/660/576 943/659/575 +f 948/746/565 944/624/564 946/1083/677 950/1084/679 +f 950/1084/679 946/1083/677 945/1085/678 949/1086/695 +f 949/1087/695 945/1088/678 943/659/575 947/658/574 +f 952/618/610 948/621/565 950/1089/679 954/1090/681 +f 954/1090/681 950/1089/679 949/1091/695 953/1008/696 +f 953/1092/696 949/1093/695 947/658/574 951/657/573 +f 956/615/611 952/618/610 954/1094/681 958/1095/683 +f 958/1095/683 954/1094/681 953/1096/696 957/1097/684 +f 957/1098/684 953/1099/696 951/657/573 955/656/572 +f 960/611/612 956/615/611 958/1100/683 962/1101/685 +f 962/1101/685 958/1100/683 957/1102/684 961/1103/686 +f 961/1104/686 957/1105/684 955/656/572 959/655/571 +f 964/747/621 960/611/612 962/1106/685 966/1107/687 +f 966/1107/687 962/1106/685 961/1108/686 965/1109/688 +f 965/1110/688 961/1111/686 959/655/571 963/654/570 +f 968/603/598 964/602/621 966/1112/687 970/1113/689 +f 970/1113/689 966/1112/687 965/1114/688 969/1115/697 +f 969/1116/697 965/1117/688 963/654/570 967/653/569 +f 972/647/599 968/603/598 970/1118/689 974/1119/691 +f 974/1119/691 970/1118/689 969/1120/697 973/1056/698 +f 973/1121/698 969/1122/697 967/653/569 971/652/568 +f 923/648/557 972/647/599 974/1123/691 925/1124/626 +f 925/1124/626 974/1123/691 973/1125/698 926/1126/628 +f 926/1127/628 973/1128/698 971/652/568 924/651/567 +f 976/633/562 979/636/608 981/1129/622 978/1130/623 +f 978/1130/623 981/1129/622 982/1131/624 977/1132/625 +f 977/1133/625 982/1134/624 980/727/579 975/726/578 +f 984/750/601 987/619/600 989/1135/630 986/1136/631 +f 986/1136/631 989/1135/630 990/1137/632 985/1138/633 +f 985/1139/633 990/1140/632 988/738/590 983/737/589 +f 979/636/608 991/639/607 993/947/638 981/1141/622 +f 981/1141/622 993/947/638 994/1142/639 982/950/624 +f 982/1143/624 994/1144/639 992/728/580 980/727/579 +f 987/619/600 995/616/561 997/1145/642 989/1146/630 +f 989/1146/630 997/1145/642 998/1147/643 990/1148/632 +f 990/1149/632 998/1150/643 996/739/591 988/738/590 +f 991/639/607 999/643/620 1001/1151/648 993/815/638 +f 993/815/638 1001/1151/648 1002/1152/669 994/1153/639 +f 994/1154/639 1002/1155/669 1000/729/614 992/728/580 +f 995/616/561 1003/612/560 1005/1156/650 997/1157/642 +f 997/1157/642 1005/1156/650 1006/1158/699 998/1159/643 +f 998/1160/643 1006/836/699 1004/740/592 996/739/591 +f 999/753/620 1007/644/616 1009/843/653 1001/1161/648 +f 1001/1161/648 1009/843/653 1010/1162/654 1002/1163/669 +f 1002/1164/669 1010/1165/654 1008/730/582 1000/729/614 +f 1003/612/560 1011/608/602 1013/1166/646 1005/1167/650 +f 1005/1167/650 1013/1166/646 1014/1168/647 1006/858/699 +f 1006/1169/699 1014/1170/647 1012/741/593 1004/740/592 +f 1007/644/616 1015/640/615 1017/1171/667 1009/874/653 +f 1009/874/653 1017/1171/667 1018/1172/668 1010/1173/654 +f 1010/1174/654 1018/1175/668 1016/731/583 1008/730/582 +f 1011/608/602 1019/607/609 1021/1176/644 1013/1177/646 +f 1013/1177/646 1021/1176/644 1022/810/700 1014/1178/647 +f 1014/888/647 1022/813/700 1020/742/594 1012/741/593 +f 1015/640/615 1023/637/604 1025/1179/665 1017/903/667 +f 1017/903/667 1025/1179/665 1026/1180/666 1018/1181/668 +f 1018/1182/668 1026/1183/666 1024/732/584 1016/731/583 +f 1019/607/609 1027/563/618 1029/1184/640 1021/1185/644 +f 1021/1185/644 1029/1184/640 1030/1186/641 1022/1187/700 +f 1022/1188/700 1030/1189/641 1028/743/595 1020/742/594 +f 1023/637/604 1031/634/603 1033/931/663 1025/1190/665 +f 1025/1190/665 1033/931/663 1034/1191/670 1026/899/666 +f 1026/1192/666 1034/1193/670 1032/733/585 1024/732/584 +f 1027/749/618 1035/562/497 1037/1194/636 1029/1195/640 +f 1029/1195/640 1037/1194/636 1038/1196/637 1030/1197/641 +f 1030/1198/641 1038/1199/637 1036/744/596 1028/743/595 +f 1031/634/603 1039/631/606 1041/1200/661 1033/1201/663 +f 1033/1201/663 1041/1200/661 1042/1202/701 1034/1203/670 +f 1034/1204/670 1042/1205/701 1040/734/586 1032/733/585 +f 1035/562/497 1043/565/496 1045/1206/634 1037/1207/636 +f 1037/1207/636 1045/1206/634 1046/1208/702 1038/1209/637 +f 1038/1210/637 1046/1211/702 1044/745/597 1036/744/596 +f 1039/631/606 1047/628/605 1049/1212/657 1041/1213/661 +f 1041/1213/661 1049/1212/657 1050/1214/658 1042/1215/701 +f 1042/1216/701 1050/1217/658 1048/735/587 1040/734/586 +f 1043/565/496 1051/567/558 1053/1218/627 1045/1219/634 +f 1045/1219/634 1053/1218/627 1054/1220/629 1046/1221/702 +f 1046/1222/702 1054/1223/629 1052/714/566 1044/745/597 +f 1047/628/605 1055/625/619 1057/1224/655 1049/1225/657 +f 1049/1225/657 1057/1224/655 1058/1226/703 1050/1227/658 +f 1050/1228/658 1058/1229/703 1056/736/588 1048/735/587 +f 1051/567/558 1059/566/557 1061/1035/704 1053/1230/627 +f 1053/1230/627 1061/1035/704 1062/1231/705 1054/1232/629 +f 1054/1233/629 1062/1234/705 1060/715/567 1052/714/566 +f 1055/748/619 984/622/601 986/1235/631 1057/1236/655 +f 1057/1236/655 986/1235/631 985/1237/633 1058/1238/703 +f 1058/1239/703 985/1240/633 983/737/589 1056/736/588 +f 1064/630/563 976/633/562 978/1241/623 1066/1242/672 +f 1066/1242/672 978/1241/623 977/1243/625 1065/1068/673 +f 1065/1244/673 977/1245/625 975/726/578 1063/725/577 +f 1068/627/617 1064/630/563 1066/1246/672 1070/1247/675 +f 1070/1247/675 1066/1246/672 1065/1248/673 1069/1249/676 +f 1069/1250/676 1065/1251/673 1063/725/577 1067/724/576 +f 1072/624/564 1068/627/617 1070/1252/675 1074/1253/706 +f 1074/1253/706 1070/1252/675 1069/1254/676 1073/1255/678 +f 1073/1256/678 1069/1257/676 1067/724/576 1071/723/575 +f 1076/621/565 1072/624/564 1074/1258/706 1078/1259/679 +f 1078/1259/679 1074/1258/706 1073/1260/678 1077/1261/695 +f 1077/1262/695 1073/1263/678 1071/723/575 1075/722/574 +f 1080/618/610 1076/621/565 1078/1264/679 1082/1265/681 +f 1082/1265/681 1078/1264/679 1077/1266/695 1081/1267/696 +f 1081/1268/696 1077/1269/695 1075/722/574 1079/721/573 +f 1084/615/611 1080/618/610 1082/1270/681 1086/1271/683 +f 1086/1271/683 1082/1270/681 1081/1272/696 1085/1273/684 +f 1085/1274/684 1081/1275/696 1079/721/573 1083/720/613 +f 1088/611/612 1084/615/611 1086/1276/683 1090/1277/685 +f 1090/1277/685 1086/1276/683 1085/1278/684 1089/1026/686 +f 1089/1279/686 1085/1280/684 1083/720/613 1087/719/571 +f 1092/602/621 1088/611/612 1090/1281/685 1094/1282/687 +f 1094/1282/687 1090/1281/685 1089/1283/686 1093/1284/707 +f 1093/1285/707 1089/1286/686 1087/719/571 1091/718/570 +f 1096/603/598 1092/602/621 1094/1287/687 1098/1288/689 +f 1098/1288/689 1094/1287/687 1093/1289/707 1097/1290/690 +f 1097/1291/690 1093/1292/707 1091/718/570 1095/717/569 +f 1100/647/599 1096/603/598 1098/1293/689 1102/1294/691 +f 1102/1294/691 1098/1293/689 1097/1295/690 1101/1296/698 +f 1101/1297/698 1097/1298/690 1095/717/569 1099/716/568 +f 1059/648/557 1100/647/599 1102/1299/691 1061/1300/704 +f 1061/1300/704 1102/1299/691 1101/1301/698 1062/1302/705 +f 1062/1303/705 1101/1128/698 1099/716/568 1060/715/567 +f 634/633/549 632/636/551 723/636/608 720/633/562 +s 0 +usemtl shortBox +f 5/1/1 6/1/1 7/1/1 8/1/1 +f 9/1/2 10/1/2 11/1/2 12/1/2 +f 13/1/3 14/1/3 15/1/3 16/1/3 +f 17/1/4 18/1/4 19/1/4 20/1/4 +f 21/1/5 22/1/5 23/1/5 24/1/5 +usemtl tallBox +f 25/1/1 26/1/1 27/1/1 28/1/1 +f 29/1/6 30/1/6 31/1/6 32/1/6 +f 33/1/7 34/1/7 35/1/7 36/1/7 +f 37/1/8 38/1/8 39/1/8 40/1/8 +f 41/1/9 42/1/9 43/1/9 44/1/9 diff --git a/engine/art/shaderlib/model_fs.glsl b/engine/art/shaderlib/model_fs.glsl index a8ce291..25a0cff 100644 --- a/engine/art/shaderlib/model_fs.glsl +++ b/engine/art/shaderlib/model_fs.glsl @@ -1,7 +1,7 @@ #ifndef MODEL_FS_GLSL #define MODEL_FS_GLSL -uniform mat4 model, view; +uniform mat4 model, view, inv_view; uniform sampler2D u_texture2d; uniform vec3 u_coefficients_sh[9]; uniform bool u_textured; /// set:1 @@ -34,15 +34,6 @@ in vec3 v_vertcolor; in float v_depth; out vec4 fragcolor; - -#include "shadowmap.glsl" -in vec4 vpeye; -in vec4 vneye; -in vec4 sc; -vec4 shadowing() { - return shadowmap(vpeye, vneye, v_texcoord, sc); -} - uniform float u_global_alpha; /// set:1.0 uniform float u_global_opacity; /// set:1.0 uniform vec3 u_cam_pos; diff --git a/engine/art/shaderlib/model_vs.glsl b/engine/art/shaderlib/model_vs.glsl index 81b37df..321a86d 100644 --- a/engine/art/shaderlib/model_vs.glsl +++ b/engine/art/shaderlib/model_vs.glsl @@ -76,13 +76,17 @@ out float v_depth; // shadow uniform mat4 model, view, inv_view; uniform mat4 cameraToShadowProjector; -out vec4 vneye; +uniform mat4 cameraToShadowView; out vec4 vpeye; -out vec4 sc; -void do_shadow() { - vneye = view * model * vec4(att_normal, 0.0f); - vpeye = view * model * vec4(att_position, 1.0); - sc = cameraToShadowProjector * model * vec4(att_position, 1.0f); +out vec4 vneye; +void do_shadow(mat4 modelMat, vec3 objPos, vec3 objNormal) { +#ifdef SHADOW_CAST + gl_Position = cameraToShadowProjector * modelMat * vec4(objPos, 1.0f); + v_position = (cameraToShadowView * modelMat * vec4(objPos, 1.0f)).xyz; +#else + vpeye = view * modelMat * vec4(objPos, 1.0f); + vneye = view * modelMat * vec4(objNormal, 0.0f); +#endif } diff --git a/engine/art/shaderlib/shadowmap-old.glsl b/engine/art/shaderlib/shadowmap-old.glsl new file mode 100644 index 0000000..8be434c --- /dev/null +++ b/engine/art/shaderlib/shadowmap-old.glsl @@ -0,0 +1,118 @@ +// WIP +#ifndef SHADOWMAP_GLSL +#define SHADOWMAP_GLSL + +// uniform mat4 view = mat4(1.0); +uniform vec3 lightPos; /// set:1,1,1 +uniform float doTexture; /// set:1 +#ifdef VSMCUBE +uniform samplerCube shadowMap; // VSMCUBE +#else +uniform sampler2D shadowMap; // !VSMCUBE +#endif + + +struct light { + vec3 position; // world-space + vec4 diffuse; + vec4 specular; + float constantAttenuation, linearAttenuation, quadraticAttenuation; + }; + + light light0 = light( + vec3(1,1,1), // lightPos + vec4(1,1,1,1), // diffuse + vec4(1,1,1,1), // specular + 1.0, 0.0, 0.0 // attenuation (const, linear, quad) + ); + + // From http://fabiensanglard.net/shadowmappingVSM/index.php + #ifdef VSMCUBE + float chebyshevUpperBound(float distance, vec3 dir) { + distance = distance/20 ; + vec2 moments = texture(shadowMap, dir).rg; + #else + float chebyshevUpperBound(float distance, vec4 scPostW) { + vec2 moments = texture(shadowMap,scPostW.xy).rg; + #endif + // Surface is fully lit. as the current fragment is before the light occluder + if (distance <= moments.x) + return 1.0; + + // The fragment is either in shadow or penumbra. We now use chebyshev's upperBound to check + // How likely this pixel is to be lit (p_max) + float variance = moments.y - (moments.x*moments.x); + //variance = max(variance, 0.000002); + variance = max(variance, 0.00002); + + float d = distance - moments.x; + float p_max = variance / (variance + d*d); + + return p_max; + } + + + vec4 shadowmap(in vec4 vpeye, in vec4 vneye, in vec2 uv, in vec4 sc) { + #ifndef VSMCUBE + return vec4(1.); + #else + vec3 fragment = vec3(vpeye); + vec3 normal = vec3(normalize(vneye)); + vec3 viewDir = normalize(-fragment); + + // Lighting + // Convert to eye-space + vec3 light = vec3(view * vec4(light0.position, 1.0)); + + #ifdef VSMCUBE + // Vectors + vec3 fragmentToLight = light - fragment; + vec3 fragmentToLightDir = normalize(fragmentToLight); + + // Shadows + vec4 fragmentToLight_world = inverse(view) * vec4(fragmentToLightDir, 0.0); + float shadowFactor = chebyshevUpperBound(length(fragmentToLight), -fragmentToLight_world.xyz); + #else + // Shadows + vec4 scPostW = sc / sc.w; + scPostW = scPostW * 0.5 + 0.5; + + float shadowFactor = 1.0; // Not in shadow + + bool outsideShadowMap = sc.w <= 0.0f || (scPostW.x < 0 || scPostW.y < 0) || (scPostW.x >= 1 || scPostW.y >= 1); + if (!outsideShadowMap) { + shadowFactor = chebyshevUpperBound(scPostW.z, scPostW); + } + #endif + + vec4 diffColor = vec4(1,1,1,1); + #ifdef VSMCUBE + if(doTexture != 0) diffColor = vec4(vec3(texture(shadowMap, -fragmentToLight_world.xyz).r), 1.0); + #else + if(doTexture != 0) diffColor = vec4(vec3(texture(shadowMap, vec2(uv.x, 1.0 - uv.y)).r), 1.0); + #endif + + #if 1 + vec3 positionToLight = light - fragment; + vec3 lightDir = normalize(positionToLight); + + // Angle between fragment-normal and incoming light + float cosAngIncidence = dot(lightDir, normal); + cosAngIncidence = clamp(cosAngIncidence, 0, 1); + + float attenuation = 1.0f; + attenuation = 1.0 / (light0.constantAttenuation + light0.linearAttenuation * length(positionToLight) + light0.quadraticAttenuation * pow(length(positionToLight),2)); + + vec4 diffuse = diffColor * light0.diffuse * cosAngIncidence * attenuation; + + vec4 total_lighting; + total_lighting += vec4(0.1, 0.1, 0.1, 1.0) * diffColor; // Ambient + total_lighting += diffuse * shadowFactor; // Diffuse + #else + vec4 total_lighting = diffColor; + #endif + return vec4(clamp(vec3(total_lighting), 0., 1.), 1.0); + #endif + } + +#endif \ No newline at end of file diff --git a/engine/art/shaderlib/shadowmap.glsl b/engine/art/shaderlib/shadowmap.glsl index 8be434c..0efd43b 100644 --- a/engine/art/shaderlib/shadowmap.glsl +++ b/engine/art/shaderlib/shadowmap.glsl @@ -1,118 +1,67 @@ -// WIP -#ifndef SHADOWMAP_GLSL -#define SHADOWMAP_GLSL +in vec4 vpeye; +in vec4 vneye; +uniform bool u_shadow_receiver; +uniform samplerCube shadowMap[MAX_LIGHTS]; -// uniform mat4 view = mat4(1.0); -uniform vec3 lightPos; /// set:1,1,1 -uniform float doTexture; /// set:1 -#ifdef VSMCUBE -uniform samplerCube shadowMap; // VSMCUBE -#else -uniform sampler2D shadowMap; // !VSMCUBE -#endif - - -struct light { - vec3 position; // world-space - vec4 diffuse; - vec4 specular; - float constantAttenuation, linearAttenuation, quadraticAttenuation; - }; +//// From http://fabiensanglard.net/shadowmappingVSM/index.php +float chebyshevUpperBound(float distance, vec3 dir, int light_index) { + distance = distance/20; + vec2 moments = texture(shadowMap[light_index], dir).rg; - light light0 = light( - vec3(1,1,1), // lightPos - vec4(1,1,1,1), // diffuse - vec4(1,1,1,1), // specular - 1.0, 0.0, 0.0 // attenuation (const, linear, quad) - ); + // Surface is fully lit. as the current fragment is before the light occluder + if (distance <= moments.x) { + return 1.0; + } - // From http://fabiensanglard.net/shadowmappingVSM/index.php - #ifdef VSMCUBE - float chebyshevUpperBound(float distance, vec3 dir) { - distance = distance/20 ; - vec2 moments = texture(shadowMap, dir).rg; - #else - float chebyshevUpperBound(float distance, vec4 scPostW) { - vec2 moments = texture(shadowMap,scPostW.xy).rg; - #endif - // Surface is fully lit. as the current fragment is before the light occluder - if (distance <= moments.x) - return 1.0; - - // The fragment is either in shadow or penumbra. We now use chebyshev's upperBound to check - // How likely this pixel is to be lit (p_max) - float variance = moments.y - (moments.x*moments.x); - //variance = max(variance, 0.000002); - variance = max(variance, 0.00002); - - float d = distance - moments.x; - float p_max = variance / (variance + d*d); - - return p_max; - } - - - vec4 shadowmap(in vec4 vpeye, in vec4 vneye, in vec2 uv, in vec4 sc) { - #ifndef VSMCUBE - return vec4(1.); - #else - vec3 fragment = vec3(vpeye); - vec3 normal = vec3(normalize(vneye)); - vec3 viewDir = normalize(-fragment); - - // Lighting - // Convert to eye-space - vec3 light = vec3(view * vec4(light0.position, 1.0)); - - #ifdef VSMCUBE - // Vectors - vec3 fragmentToLight = light - fragment; - vec3 fragmentToLightDir = normalize(fragmentToLight); - - // Shadows - vec4 fragmentToLight_world = inverse(view) * vec4(fragmentToLightDir, 0.0); - float shadowFactor = chebyshevUpperBound(length(fragmentToLight), -fragmentToLight_world.xyz); - #else - // Shadows - vec4 scPostW = sc / sc.w; - scPostW = scPostW * 0.5 + 0.5; - - float shadowFactor = 1.0; // Not in shadow - - bool outsideShadowMap = sc.w <= 0.0f || (scPostW.x < 0 || scPostW.y < 0) || (scPostW.x >= 1 || scPostW.y >= 1); - if (!outsideShadowMap) { - shadowFactor = chebyshevUpperBound(scPostW.z, scPostW); - } - #endif - - vec4 diffColor = vec4(1,1,1,1); - #ifdef VSMCUBE - if(doTexture != 0) diffColor = vec4(vec3(texture(shadowMap, -fragmentToLight_world.xyz).r), 1.0); - #else - if(doTexture != 0) diffColor = vec4(vec3(texture(shadowMap, vec2(uv.x, 1.0 - uv.y)).r), 1.0); - #endif - - #if 1 - vec3 positionToLight = light - fragment; - vec3 lightDir = normalize(positionToLight); - - // Angle between fragment-normal and incoming light - float cosAngIncidence = dot(lightDir, normal); - cosAngIncidence = clamp(cosAngIncidence, 0, 1); - - float attenuation = 1.0f; - attenuation = 1.0 / (light0.constantAttenuation + light0.linearAttenuation * length(positionToLight) + light0.quadraticAttenuation * pow(length(positionToLight),2)); - - vec4 diffuse = diffColor * light0.diffuse * cosAngIncidence * attenuation; - - vec4 total_lighting; - total_lighting += vec4(0.1, 0.1, 0.1, 1.0) * diffColor; // Ambient - total_lighting += diffuse * shadowFactor; // Diffuse - #else - vec4 total_lighting = diffColor; - #endif - return vec4(clamp(vec3(total_lighting), 0., 1.), 1.0); - #endif + // The fragment is either in shadow or penumbra. We now use chebyshev's upperBound to check + // How likely this pixel is to be lit (p_max) + float variance = moments.y - (moments.x*moments.x); + //variance = max(variance, 0.000002); + variance = max(variance, 0.00002); + + float d = distance - moments.x; + float p_max = variance / (variance + d*d); + + return p_max; +} + +vec4 shadowmap(in vec4 peye, in vec4 neye) { + float shadowFactor = 0.0; + vec3 fragment = vec3(peye); + + int total_casters = 0; + for (int i = 0; i < u_num_lights; i++) { + light_t light = u_lights[i]; + float factor = 0.0; + + if (light.type == LIGHT_DIRECTIONAL) { + // shadowFactor = chebyshevUpperBound(distance, light.dir); + } else if (light.type == LIGHT_POINT) { + total_casters++; + vec3 light_pos = (view * vec4(light.pos, 1.0)).xyz; + vec3 dir = light_pos - fragment; + vec4 sc = inv_view * vec4(dir, 0.0); + factor += chebyshevUpperBound(length(dir), -sc.xyz, i); + } else if (light.type == LIGHT_SPOT) { + // shadowFactor = chebyshevUpperBound(distance, light.pos); } -#endif \ No newline at end of file + shadowFactor += factor; + } + + if (u_num_lights == 0) { + shadowFactor = 1.0; + } else { + shadowFactor /= total_casters; + } + + return vec4(vec3(shadowFactor), 1.0); +} + +vec4 shadowing() { + if (u_shadow_receiver) { + return shadowmap(vpeye, vneye); + } else { + return vec4(1.0); + } +} diff --git a/engine/art/shaderlib/surface.glsl b/engine/art/shaderlib/surface.glsl index 6d6833e..2b09569 100644 --- a/engine/art/shaderlib/surface.glsl +++ b/engine/art/shaderlib/surface.glsl @@ -4,6 +4,7 @@ #include "sh_lighting.glsl" #include "rimlight.glsl" #include "light.glsl" +#include "shadowmap.glsl" struct surface_t { vec3 normal; @@ -194,10 +195,12 @@ surface_t surface() { s.albedo *= v_color; + s.light_direct *= shadowing().xyz; + s.fragcolor = s.albedo; s.fragcolor.rgb *= s.light_direct + s.light_indirect; s.fragcolor.rgb += s.emissive; - s.fragcolor *= shadowing(); + // s.fragcolor *= shadowing(); s.fragcolor.rgb += get_rimlight(); s.fragcolor.a *= u_global_alpha; s.fragcolor *= vec4(u_global_opacity); diff --git a/engine/art/shaders/fs_shadow_vsm.glsl b/engine/art/shaders/fs_shadow_vsm.glsl index 1416cbe..eaade94 100644 --- a/engine/art/shaders/fs_shadow_vsm.glsl +++ b/engine/art/shaders/fs_shadow_vsm.glsl @@ -1,19 +1,14 @@ -in vec4 v_position; -out vec4 outColor; +in vec3 v_position; +out vec4 fragcolor; void main() { - #ifdef VSMCUBE - float depth = length( vec3(v_position) ) / 20; - #else - float depth = v_position.z / v_position.w; - depth = depth * 0.5 + 0.5; - #endif - + float depth = length(v_position) / 20; + float moment1 = depth; float moment2 = depth * depth; float dx = dFdx(depth); float dy = dFdy(depth); moment2 += 0.25*(dx*dx+dy*dy); - outColor = vec4( moment1, moment2, 0.0, 0.0); -} \ No newline at end of file + fragcolor = vec4( moment1, moment2, 0.0, 1.0); +} diff --git a/engine/art/shaders/vs_323444143_16_3322_model.glsl b/engine/art/shaders/vs_323444143_16_3322_model.glsl index 9f18cc5..63c1b59 100644 --- a/engine/art/shaders/vs_323444143_16_3322_model.glsl +++ b/engine/art/shaders/vs_323444143_16_3322_model.glsl @@ -43,5 +43,5 @@ void main() { gl_Position = P * finalPos; // Prepare shadow data for shadow mapping - do_shadow(); + do_shadow(att_instanced_matrix, objPos, v_normal); } \ No newline at end of file diff --git a/engine/art/shaders/vs_shadow_vsm.glsl b/engine/art/shaders/vs_shadow_vsm.glsl deleted file mode 100644 index 22f4e96..0000000 --- a/engine/art/shaders/vs_shadow_vsm.glsl +++ /dev/null @@ -1,15 +0,0 @@ -uniform mat4 model; -uniform mat4 cameraToShadowView; -uniform mat4 cameraToShadowProjector; - -in vec3 position; -out vec4 v_position; - -void main() { - gl_Position = cameraToShadowProjector * model * vec4(position, 1.0); - #ifdef VSMCUBE - v_position = cameraToShadowView * model * vec4(position, 1.0); - #else - v_position = gl_Position; - #endif -} \ No newline at end of file diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h index 901fdf6..3e07626 100644 --- a/engine/joint/v4k.h +++ b/engine/joint/v4k.h @@ -17033,6 +17033,9 @@ typedef struct renderstate_t { // Scissor test bool scissor_test_enabled; + + // bool Seamless Cubemap + bool seamless_cubemap; } renderstate_t; API renderstate_t renderstate(); @@ -17232,6 +17235,7 @@ API void cubemap_sh_shader(cubemap_t *c); API void cubemap_sh_add_light(cubemap_t *c, vec3 light, vec3 dir, float strength); // lighting probe blending +// @note: uploads SH coefficients to shader API void cubemap_sh_blend(vec3 pos, float max_dist, unsigned count, cubemap_t *probes); // ----------------------------------------------------------------------------- @@ -17242,6 +17246,54 @@ API void fbo_bind(unsigned id); API void fbo_unbind(); API void fbo_destroy(unsigned id); +// ----------------------------------------------------------------------------- +// lights + +enum { + MAX_LIGHTS = 16, +}; + +enum LIGHT_TYPE { + LIGHT_DIRECTIONAL, + LIGHT_POINT, + LIGHT_SPOT, +}; + +typedef struct light_t { + char type; + vec3 diffuse, specular, ambient; + vec3 pos, dir; + struct { + float constant, linear, quadratic; + } falloff; + float radius; + float specularPower; + float innerCone, outerCone; + //@todo: cookie, flare + + // Shadowmapping + bool cast_shadows; + float shadow_distance; + float shadow_bias; + + // internals + bool cached; //< used by scene to invalidate cached light data +} light_t; + +API light_t light(); +// API void light_flags(int flags); +API void light_type(light_t* l, char type); +API void light_diffuse(light_t* l, vec3 color); +API void light_specular(light_t* l, vec3 color); +API void light_ambient(light_t* l, vec3 color); +API void light_teleport(light_t* l, vec3 pos); +API void light_dir(light_t* l, vec3 dir); +API void light_power(light_t* l, float power); +API void light_radius(light_t* l, float radius); +API void light_falloff(light_t* l, float constant, float linear, float quadratic); +API void light_cone(light_t* l, float innerCone, float outerCone); +API void light_update(unsigned num_lights, light_t *lv); + // ----------------------------------------------------------------------------- // shadowmaps @@ -17253,15 +17305,19 @@ API void fbo_destroy(unsigned id); // #endif typedef struct shadowmap_t { - mat44 shadowmatrix; - mat44 mvp; - mat44 mv; - mat44 proj; - vec4 light_position; - int saved_fb; - int saved_viewport[4]; - handle fbo, texture; + mat44 V; + mat44 PV; int texture_width; + int step; + int light_step; + + struct { + handle fbos[6], texture, depth_texture; + } maps[MAX_LIGHTS]; + + handle saved_fb; + handle saved_pass; + int saved_vp[4]; } shadowmap_t; API shadowmap_t shadowmap(int texture_width); // = 1024 @@ -17269,13 +17325,10 @@ API void shadowmap_destroy(shadowmap_t *s); API void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection); API void shadowmap_begin(shadowmap_t *s); +API bool shadowmap_step(shadowmap_t *s); +API void shadowmap_light(shadowmap_t *s, light_t *l); API void shadowmap_end(shadowmap_t *s); -// shadowmap utils - -API void shadowmatrix_proj(mat44 shm_proj, float aLightFov, float znear, float zfar); -API void shadowmatrix_ortho(mat44 shm_proj, float left, float right, float bottom, float top, float znear, float zfar); - // ----------------------------------------------------------------------------- // shaders @@ -17664,6 +17717,9 @@ typedef struct model_t { unsigned num_anims; unsigned num_frames; handle program; + handle shadow_program; + shadowmap_t *shadow_map; + bool shadow_receiver; float curframe; mat44 pivot; @@ -17715,6 +17771,7 @@ API void model_lod(model_t*, float lo_detail, float hi_detail, float morph); API void model_shading(model_t*, int shading); API void model_shading_custom(model_t*, int shading, const char *vs, const char *fs, const char *defines); API void model_skybox(model_t*, skybox_t sky, bool load_sh); +API void model_shadow(model_t*, shadowmap_t *sm); API void model_fog(model_t*, unsigned mode, vec3 color, float start, float end, float density); API void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader); API void model_render_skeleton(model_t, mat44 model); @@ -17950,48 +18007,6 @@ API void object_billboard(object_t *obj, unsigned mode); // object_pose(transform); // @todo - -// light -enum LIGHT_TYPE { - LIGHT_DIRECTIONAL, - LIGHT_POINT, - LIGHT_SPOT, -}; - -enum LIGHT_FLAGS { - LIGHT_CAST_SHADOWS = 1, -}; - -typedef struct light_t { - char type; - vec3 diffuse, specular, ambient; - vec3 pos, dir; - struct { - float constant, linear, quadratic; - } falloff; - float radius; - float specularPower; - float innerCone, outerCone; - //@todo: cookie, flare - - // internals - bool cached; //< used by scene to invalidate cached light data -} light_t; - -API light_t light(); -// API void light_flags(int flags); -API void light_type(light_t* l, char type); -API void light_diffuse(light_t* l, vec3 color); -API void light_specular(light_t* l, vec3 color); -API void light_ambient(light_t* l, vec3 color); -API void light_teleport(light_t* l, vec3 pos); -API void light_dir(light_t* l, vec3 dir); -API void light_power(light_t* l, float power); -API void light_radius(light_t* l, float radius); -API void light_falloff(light_t* l, float constant, float linear, float quadratic); -API void light_cone(light_t* l, float innerCone, float outerCone); -API void light_update(unsigned num_lights, light_t *lv); - // scene enum SCENE_FLAGS { @@ -381806,6 +381821,9 @@ renderstate_t renderstate() { // Disable scissor test by default state.scissor_test_enabled = GL_FALSE; + // Enable seamless cubemap by default + state.seamless_cubemap = GL_TRUE; + return state; } @@ -381912,6 +381930,13 @@ void renderstate_apply(const renderstate_t *state) { } else { glDisable(GL_SCISSOR_TEST); } + + // Apply seamless cubemap + if (state->seamless_cubemap) { + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + } else { + glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + } } } @@ -383136,92 +383161,256 @@ texture_t texture_compressed(const char *pathfile, unsigned flags) { return texture_compressed_from_mem(data, size, flags); } + +// ----------------------------------------------------------------------------- + +light_t light() { + light_t l = {0}; + l.diffuse = vec3(1,1,1); + l.dir = vec3(1,-1,-1); + l.falloff.constant = 1.0f; + l.falloff.linear = 0.09f; + l.falloff.quadratic = 0.0032f; + l.specularPower = 32.f; + l.innerCone = 0.85f;// 31 deg + l.outerCone = 0.9f; // 25 deg + l.shadow_distance = 100.0f; + l.shadow_bias = 0.5f; + return l; +} + +void light_type(light_t* l, char type) { + l->cached = 0; + l->type = type; +} + +void light_diffuse(light_t* l, vec3 color) { + l->cached = 0; + l->diffuse = color; +} + +void light_specular(light_t* l, vec3 color) { + l->cached = 0; + l->specular = color; +} + +void light_ambient(light_t* l, vec3 color) { + l->cached = 0; + l->ambient = color; +} + +void light_teleport(light_t* l, vec3 pos) { + l->cached = 0; + l->pos = pos; +} + +void light_dir(light_t* l, vec3 dir) { + l->cached = 0; + l->dir = dir; +} + +void light_power(light_t* l, float power) { + l->cached = 0; + l->specularPower = power; +} + +void light_falloff(light_t* l, float constant, float linear, float quadratic) { + l->cached = 0; + l->falloff.constant = constant; + l->falloff.linear = linear; + l->falloff.quadratic = quadratic; +} + +void light_radius(light_t* l, float radius) { + l->cached = 0; + l->radius = radius; +} + +void light_cone(light_t* l, float innerCone, float outerCone) { + l->cached = 0; + l->innerCone = acos(innerCone); + l->outerCone = acos(outerCone); +} + +void light_update(unsigned num_lights, light_t *lv) { + if (num_lights > MAX_LIGHTS) { + PRINTF("WARNING: num_lights > MAX_LIGHTS, clamping to MAX_LIGHTS\n"); + num_lights = MAX_LIGHTS; + } + shader_int("u_num_lights", num_lights); + + for (unsigned i=0; i < num_lights; ++i) { + lv[i].cached = 1; + shader_int(va("u_lights[%d].type", i), lv[i].type); + shader_vec3(va("u_lights[%d].pos", i), lv[i].pos); + shader_vec3(va("u_lights[%d].dir", i), lv[i].dir); + shader_vec3(va("u_lights[%d].diffuse", i), lv[i].diffuse); + shader_vec3(va("u_lights[%d].specular", i), lv[i].specular); + shader_vec3(va("u_lights[%d].ambient", i), lv[i].ambient); + shader_float(va("u_lights[%d].power", i), lv[i].specularPower); + shader_float(va("u_lights[%d].radius", i), lv[i].radius); + shader_float(va("u_lights[%d].constant", i), lv[i].falloff.constant); + shader_float(va("u_lights[%d].linear", i), lv[i].falloff.linear); + shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic); + shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone); + shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone); + } +} + + // ----------------------------------------------------------------------------- // shadowmaps +static inline +shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) { + // Create a cubemap color texture + glGenTextures(1, &s->maps[light_index].texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].texture); + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB32F, texture_width, texture_width, 0, GL_RGB, GL_FLOAT, 0); + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // Create a cubemap depth texture + glGenTextures(1, &s->maps[light_index].depth_texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].depth_texture); + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + + // Create 6 framebuffers for each face of the cubemap + glGenFramebuffers(6, s->maps[light_index].fbos); + for (int i = 0; i < 6; i++) { + glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbos[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, s->maps[light_index].texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, s->maps[light_index].depth_texture, 0); + GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (GL_FRAMEBUFFER_COMPLETE != result) { + PANIC("ERROR: Framebuffer is not complete: %x\n", result); + } + } +} + shadowmap_t shadowmap(int texture_width) { // = 1024 shadowmap_t s = {0}; s.texture_width = texture_width; - + s.saved_fb = 0; glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb); - glGenFramebuffers(1, &s.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, s.fbo); - - glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &s.texture); - glBindTexture(GL_TEXTURE_2D, s.texture); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s.texture, 0); - -#if is(ems) - GLenum nones[] = { GL_NONE }; - glDrawBuffers(1, nones); - glReadBuffer(GL_NONE); -#else - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); -#endif - + for (int i = 0; i < MAX_LIGHTS; i++) { + shadowmap_init_caster(&s, i, texture_width); + } + glBindFramebuffer(GL_FRAMEBUFFER, s.saved_fb); return s; } void shadowmap_destroy(shadowmap_t *s) { - if (s->texture) { - glDeleteTextures(1, &s->texture); - } - if (s->fbo) { - glDeleteFramebuffers(1, &s->fbo); + for (int i = 0; i < MAX_LIGHTS; i++) { + glDeleteFramebuffers(6, s->maps[i].fbos); + glDeleteTextures(1, &s->maps[i].texture); + glDeleteTextures(1, &s->maps[i].depth_texture); } shadowmap_t z = {0}; *s = z; } void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection) { - copy44(s->proj, projection); - s->light_position = vec4(aLightPos.x, aLightPos.y, aLightPos.z, 1); - lookat44(s->mv, aLightPos, aLightAt, aLightUp); + // copy44(s->proj, projection); + // lookat44(s->mv, aLightPos, aLightAt, aLightUp); - mat44 bias = { - 0.5, 0.0, 0.0, 0.0, - 0.0, 0.5, 0.0, 0.0, - 0.0, 0.0, 0.5, 0.0, - 0.5, 0.5, 0.5, 1.0 }; + // mat44 bias = { + // 0.5, 0.0, 0.0, 0.0, + // 0.0, 0.5, 0.0, 0.0, + // 0.0, 0.0, 0.5, 0.0, + // 0.5, 0.5, 0.5, 1.0 }; - // s->shadowmatrix = bias; - // s->shadowmatrix *= s->proj; - // s->shadowmatrix *= s->mv; -// multiply44x3(s->shadowmatrix, s->mv, s->proj, bias); - multiply44x3(s->shadowmatrix, bias, s->proj, s->mv); - - // mvp = projection * s->mv; -// multiply44x2(s->mvp, s->mv, projection); - multiply44x2(s->mvp, projection, s->mv); + // multiply44x3(s->shadowmatrix, bias, s->proj, s->mv); + // multiply44x2(s->mvp, projection, s->mv); } +static shadowmap_t *active_shadowmap = NULL; + void shadowmap_begin(shadowmap_t *s) { - glGetIntegerv(GL_VIEWPORT, &s->saved_viewport[0]); + glGetIntegerv(GL_VIEWPORT, s->saved_vp); glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s->saved_fb); - glBindFramebuffer(GL_FRAMEBUFFER, s->fbo); - glViewport(0, 0, s->texture_width, s->texture_width); + s->saved_pass = model_setpass(RENDER_PASS_SHADOW); + s->step = 0; + s->light_step = 0; + active_shadowmap = s; - glClearDepth(1); - glClear(GL_DEPTH_BUFFER_BIT); + for (int i = 0; i < MAX_LIGHTS; i++) { + for (int j = 0; j < 6; j++) { + glBindFramebuffer(GL_FRAMEBUFFER, s->maps[i].fbos[j]); + glClearColor(0, 0, 0, 0); + glClearDepth(1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + } +} + +static void shadowmap_light_point(shadowmap_t *s, light_t *l, int dir) { + if(dir<0) return; + mat44 P, V, PV; + perspective44(P, 90.0f, 1.0f, l->shadow_bias, l->shadow_distance); + vec3 lightPos = l->pos; + + /**/ if(dir == 0) lookat44(V, lightPos, add3(lightPos, vec3(+1, 0, 0)), vec3(0, -1, 0)); // +X + else if(dir == 1) lookat44(V, lightPos, add3(lightPos, vec3(-1, 0, 0)), vec3(0, -1, 0)); // -X + else if(dir == 2) lookat44(V, lightPos, add3(lightPos, vec3( 0, +1, 0)), vec3(0, 0, +1)); // +Y + else if(dir == 3) lookat44(V, lightPos, add3(lightPos, vec3( 0, -1, 0)), vec3(0, 0, -1)); // -Y + else if(dir == 4) lookat44(V, lightPos, add3(lightPos, vec3( 0, 0, +1)), vec3(0, -1, 0)); // +Z + else /*dir == 5*/ lookat44(V, lightPos, add3(lightPos, vec3( 0, 0, -1)), vec3(0, -1, 0)); // -Z + multiply44x2(PV, P, V); // -Z + + copy44(s->V, V); + copy44(s->PV, PV); +} + +bool shadowmap_step(shadowmap_t *s) { + if (s->step >= 6) { + s->step = 0; + s->light_step++; + return false; + } + + glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbos[s->step]); + glViewport(0, 0, s->texture_width, s->texture_width); + + s->step++; + return true; +} + +void shadowmap_light(shadowmap_t *s, light_t *l) { + if (l->cast_shadows) { + int step = s->step - 1; + + if (l->type == LIGHT_POINT) { + shadowmap_light_point(s, l, step); + } else if (l->type == LIGHT_SPOT) { + // spot light + } else if (l->type == LIGHT_DIRECTIONAL) { + // directional light + } + } } void shadowmap_end(shadowmap_t *s) { - glViewport(s->saved_viewport[0], s->saved_viewport[1], s->saved_viewport[2], s->saved_viewport[3]); + glViewport(s->saved_vp[0], s->saved_vp[1], s->saved_vp[2], s->saved_vp[3]); glBindFramebuffer(GL_FRAMEBUFFER, s->saved_fb); + model_setpass(s->saved_pass); + active_shadowmap = NULL; } // shadowmap utils @@ -385397,6 +385586,25 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view, glUniform1f(loc, (float)window_time()); } + // shadow casting + if (shader == m.shadow_program) { + shadowmap_t *sm = active_shadowmap; + ASSERT(sm); + shader_mat44("cameraToShadowView", sm->V); + shader_mat44("cameraToShadowProjector", sm->PV); + } + + // shadow receiving + if (m.shadow_receiver) { + ASSERT(m.shadow_map); + shader_bool("u_shadow_receiver", GL_TRUE); + for (int i = 0; i < MAX_LIGHTS; i++) { + shader_cubemap(va("shadowMap[%d]", i), m.shadow_map->maps[i].texture); + } + } else { + shader_bool("u_shadow_receiver", GL_FALSE); + } + if (m.shading == SHADING_PBR) { handle old_shader = last_shader; shader_bind(shader); @@ -386010,12 +386218,13 @@ void model_set_renderstates(model_t *m) { transparent_rs->front_face = GL_CW; } - // Shadow pass @todo + // Shadow pass renderstate_t *shadow_rs = &m->rs[RENDER_PASS_SHADOW]; { shadow_rs->blend_enabled = 1; shadow_rs->blend_src = GL_SRC_ALPHA; shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA; + shadow_rs->cull_face_enabled = 1; shadow_rs->cull_face_mode = GL_BACK; shadow_rs->front_face = GL_CW; } @@ -386414,6 +386623,7 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ int rs_idx = model_getpass(); renderstate_t *rs = &m.rs[rs_idx]; + renderstate_apply(rs); glBindVertexArray( q->vao ); @@ -386497,31 +386707,33 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ renderstate_apply(rs); } - if (m.shading != SHADING_PBR) { - shader_texture_unit("u_texture2d", q->textures[i], texture_unit()); - shader_texture("u_lightmap", m.lightmap); + if (rs_idx != RENDER_PASS_SHADOW) { + if (m.shading != SHADING_PBR) { + shader_texture_unit("u_texture2d", q->textures[i], texture_unit()); + shader_texture("u_lightmap", m.lightmap); - int loc; - if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) { - bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id; - glUniform1i(loc, textured ? GL_TRUE : GL_FALSE); - if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) { - glUniform4f(loc, m.materials[i].layer[0].map.color.r, m.materials[i].layer[0].map.color.g, m.materials[i].layer[0].map.color.b, m.materials[i].layer[0].map.color.a); + int loc; + if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) { + bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id; + glUniform1i(loc, textured ? GL_TRUE : GL_FALSE); + if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) { + glUniform4f(loc, m.materials[i].layer[0].map.color.r, m.materials[i].layer[0].map.color.g, m.materials[i].layer[0].map.color.b, m.materials[i].layer[0].map.color.a); + } } - } - } else { - const material_t *material = &m.materials[i]; - shader_colormap_model_internal( "map_diffuse.color", "map_diffuse.has_tex", "map_diffuse_tex", material->layer[MATERIAL_CHANNEL_DIFFUSE].map ); - shader_colormap_model_internal( "map_normals.color", "map_normals.has_tex", "map_normals_tex", material->layer[MATERIAL_CHANNEL_NORMALS].map ); - shader_colormap_model_internal( "map_specular.color", "map_specular.has_tex", "map_specular_tex", material->layer[MATERIAL_CHANNEL_SPECULAR].map ); - shader_colormap_model_internal( "map_albedo.color", "map_albedo.has_tex", "map_albedo_tex", material->layer[MATERIAL_CHANNEL_ALBEDO].map ); - shader_colormap_model_internal( "map_roughness.color", "map_roughness.has_tex", "map_roughness_tex", material->layer[MATERIAL_CHANNEL_ROUGHNESS].map ); - shader_colormap_model_internal( "map_metallic.color", "map_metallic.has_tex", "map_metallic_tex", material->layer[MATERIAL_CHANNEL_METALLIC].map ); - shader_colormap_model_internal( "map_ao.color", "map_ao.has_tex", "map_ao_tex", material->layer[MATERIAL_CHANNEL_AO].map ); - shader_colormap_model_internal( "map_ambient.color", "map_ambient.has_tex", "map_ambient_tex", material->layer[MATERIAL_CHANNEL_AMBIENT].map ); - shader_colormap_model_internal( "map_emissive.color", "map_emissive.has_tex", "map_emissive_tex", material->layer[MATERIAL_CHANNEL_EMISSIVE].map ); - // shader_float( "specular_shininess", material->specular_shininess ); // unused, basic_specgloss.fs only + } else { + const material_t *material = &m.materials[i]; + shader_colormap_model_internal( "map_diffuse.color", "map_diffuse.has_tex", "map_diffuse_tex", material->layer[MATERIAL_CHANNEL_DIFFUSE].map ); + shader_colormap_model_internal( "map_normals.color", "map_normals.has_tex", "map_normals_tex", material->layer[MATERIAL_CHANNEL_NORMALS].map ); + shader_colormap_model_internal( "map_specular.color", "map_specular.has_tex", "map_specular_tex", material->layer[MATERIAL_CHANNEL_SPECULAR].map ); + shader_colormap_model_internal( "map_albedo.color", "map_albedo.has_tex", "map_albedo_tex", material->layer[MATERIAL_CHANNEL_ALBEDO].map ); + shader_colormap_model_internal( "map_roughness.color", "map_roughness.has_tex", "map_roughness_tex", material->layer[MATERIAL_CHANNEL_ROUGHNESS].map ); + shader_colormap_model_internal( "map_metallic.color", "map_metallic.has_tex", "map_metallic_tex", material->layer[MATERIAL_CHANNEL_METALLIC].map ); + shader_colormap_model_internal( "map_ao.color", "map_ao.has_tex", "map_ao_tex", material->layer[MATERIAL_CHANNEL_AO].map ); + shader_colormap_model_internal( "map_ambient.color", "map_ambient.has_tex", "map_ambient_tex", material->layer[MATERIAL_CHANNEL_AMBIENT].map ); + shader_colormap_model_internal( "map_emissive.color", "map_emissive.has_tex", "map_emissive_tex", material->layer[MATERIAL_CHANNEL_EMISSIVE].map ); + // shader_float( "specular_shininess", material->specular_shininess ); // unused, basic_specgloss.fs only + } } glDrawElementsInstanced(GL_TRIANGLES, 3*im->num_triangles, GL_UNSIGNED_INT, &tris[im->first_triangle], m.num_instances); @@ -386546,6 +386758,10 @@ void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* model model_set_state(m); } + if (model_getpass() == RENDER_PASS_SHADOW) { + shader = m.shadow_program; + } + model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); model_draw_call(m, shader > 0 ? shader : m.program, pass, pos44(view), models[0]); } @@ -386699,11 +386915,20 @@ void model_shading_custom(model_t *m, int shading, const char *vs, const char *f glUseProgram(0); if (m->program) glDeleteProgram(m->program); - const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM - int shaderprog = shader(strlerp(1,symbols,vs), strlerp(1,symbols,fs), //fs, - "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent,att_texcoord2","fragColor", - va("%s,%s,%s", defines ? defines : "NO_CUSTOM_DEFINES", shading_define, (flags&MODEL_RIMLIGHT)?"RIM":"")); - m->program = shaderprog; + + { + int shaderprog = shader(vs, fs, //fs, + "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent,att_texcoord2","fragColor", + va("%s,%s,%s", defines ? defines : "NO_CUSTOM_DEFINES", shading_define, (flags&MODEL_RIMLIGHT)?"RIM":"")); + m->program = shaderprog; + } + + { + int shaderprog = shader(vs, vfs_read("shaders/fs_shadow_vsm.glsl"), //fs, + "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent,att_texcoord2","fragcolor", + va("SHADOW_CAST,%s", defines ? defines : "NO_CUSTOM_DEFINES")); + m->shadow_program = shaderprog; + } model_init_uniforms(m); } @@ -386723,6 +386948,16 @@ void model_skybox(model_t *mdl, skybox_t sky, bool load_sh) { mdl->sky_env = sky.env; } +void model_shadow(model_t *mdl, shadowmap_t *sm) { + if (sm) { + mdl->shadow_receiver = true; + mdl->shadow_map = sm; + } else { + mdl->shadow_receiver = false; + mdl->shadow_map = NULL; + } +} + void model_fog(model_t *mdl, unsigned mode, vec3 color, float start, float end, float density) { unsigned oldprog = last_shader; shader_bind(mdl->program); @@ -388379,96 +388614,6 @@ void object_billboard(object_t *obj, unsigned mode) { // ----------------------------------------------------------------------------- -light_t light() { - light_t l = {0}; - l.diffuse = vec3(1,1,1); - l.dir = vec3(1,-1,-1); - l.falloff.constant = 1.0f; - l.falloff.linear = 0.09f; - l.falloff.quadratic = 0.0032f; - l.specularPower = 32.f; - l.innerCone = 0.85f;// 31 deg - l.outerCone = 0.9f; // 25 deg - - return l; -} - -void light_type(light_t* l, char type) { - l->cached = 0; - l->type = type; -} - -void light_diffuse(light_t* l, vec3 color) { - l->cached = 0; - l->diffuse = color; -} - -void light_specular(light_t* l, vec3 color) { - l->cached = 0; - l->specular = color; -} - -void light_ambient(light_t* l, vec3 color) { - l->cached = 0; - l->ambient = color; -} - -void light_teleport(light_t* l, vec3 pos) { - l->cached = 0; - l->pos = pos; -} - -void light_dir(light_t* l, vec3 dir) { - l->cached = 0; - l->dir = dir; -} - -void light_power(light_t* l, float power) { - l->cached = 0; - l->specularPower = power; -} - -void light_falloff(light_t* l, float constant, float linear, float quadratic) { - l->cached = 0; - l->falloff.constant = constant; - l->falloff.linear = linear; - l->falloff.quadratic = quadratic; -} - -void light_radius(light_t* l, float radius) { - l->cached = 0; - l->radius = radius; -} - -void light_cone(light_t* l, float innerCone, float outerCone) { - l->cached = 0; - l->innerCone = acos(innerCone); - l->outerCone = acos(outerCone); -} - -void light_update(unsigned num_lights, light_t *lv) { - shader_int("u_num_lights", num_lights); - - for (unsigned i=0; i < num_lights; ++i) { - lv[i].cached = 1; - shader_int(va("u_lights[%d].type", i), lv[i].type); - shader_vec3(va("u_lights[%d].pos", i), lv[i].pos); - shader_vec3(va("u_lights[%d].dir", i), lv[i].dir); - shader_vec3(va("u_lights[%d].diffuse", i), lv[i].diffuse); - shader_vec3(va("u_lights[%d].specular", i), lv[i].specular); - shader_vec3(va("u_lights[%d].ambient", i), lv[i].ambient); - shader_float(va("u_lights[%d].power", i), lv[i].specularPower); - shader_float(va("u_lights[%d].radius", i), lv[i].radius); - shader_float(va("u_lights[%d].constant", i), lv[i].falloff.constant); - shader_float(va("u_lights[%d].linear", i), lv[i].falloff.linear); - shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic); - shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone); - shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone); - } -} - -// ----------------------------------------------------------------------------- - array(scene_t*) scenes; scene_t* last_scene; diff --git a/engine/split/v4k_render.c b/engine/split/v4k_render.c index 452004e..3a3f586 100644 --- a/engine/split/v4k_render.c +++ b/engine/split/v4k_render.c @@ -119,6 +119,9 @@ renderstate_t renderstate() { // Disable scissor test by default state.scissor_test_enabled = GL_FALSE; + // Enable seamless cubemap by default + state.seamless_cubemap = GL_TRUE; + return state; } @@ -225,6 +228,13 @@ void renderstate_apply(const renderstate_t *state) { } else { glDisable(GL_SCISSOR_TEST); } + + // Apply seamless cubemap + if (state->seamless_cubemap) { + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + } else { + glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + } } } @@ -1449,92 +1459,256 @@ texture_t texture_compressed(const char *pathfile, unsigned flags) { return texture_compressed_from_mem(data, size, flags); } + +// ----------------------------------------------------------------------------- + +light_t light() { + light_t l = {0}; + l.diffuse = vec3(1,1,1); + l.dir = vec3(1,-1,-1); + l.falloff.constant = 1.0f; + l.falloff.linear = 0.09f; + l.falloff.quadratic = 0.0032f; + l.specularPower = 32.f; + l.innerCone = 0.85f;// 31 deg + l.outerCone = 0.9f; // 25 deg + l.shadow_distance = 100.0f; + l.shadow_bias = 0.5f; + return l; +} + +void light_type(light_t* l, char type) { + l->cached = 0; + l->type = type; +} + +void light_diffuse(light_t* l, vec3 color) { + l->cached = 0; + l->diffuse = color; +} + +void light_specular(light_t* l, vec3 color) { + l->cached = 0; + l->specular = color; +} + +void light_ambient(light_t* l, vec3 color) { + l->cached = 0; + l->ambient = color; +} + +void light_teleport(light_t* l, vec3 pos) { + l->cached = 0; + l->pos = pos; +} + +void light_dir(light_t* l, vec3 dir) { + l->cached = 0; + l->dir = dir; +} + +void light_power(light_t* l, float power) { + l->cached = 0; + l->specularPower = power; +} + +void light_falloff(light_t* l, float constant, float linear, float quadratic) { + l->cached = 0; + l->falloff.constant = constant; + l->falloff.linear = linear; + l->falloff.quadratic = quadratic; +} + +void light_radius(light_t* l, float radius) { + l->cached = 0; + l->radius = radius; +} + +void light_cone(light_t* l, float innerCone, float outerCone) { + l->cached = 0; + l->innerCone = acos(innerCone); + l->outerCone = acos(outerCone); +} + +void light_update(unsigned num_lights, light_t *lv) { + if (num_lights > MAX_LIGHTS) { + PRINTF("WARNING: num_lights > MAX_LIGHTS, clamping to MAX_LIGHTS\n"); + num_lights = MAX_LIGHTS; + } + shader_int("u_num_lights", num_lights); + + for (unsigned i=0; i < num_lights; ++i) { + lv[i].cached = 1; + shader_int(va("u_lights[%d].type", i), lv[i].type); + shader_vec3(va("u_lights[%d].pos", i), lv[i].pos); + shader_vec3(va("u_lights[%d].dir", i), lv[i].dir); + shader_vec3(va("u_lights[%d].diffuse", i), lv[i].diffuse); + shader_vec3(va("u_lights[%d].specular", i), lv[i].specular); + shader_vec3(va("u_lights[%d].ambient", i), lv[i].ambient); + shader_float(va("u_lights[%d].power", i), lv[i].specularPower); + shader_float(va("u_lights[%d].radius", i), lv[i].radius); + shader_float(va("u_lights[%d].constant", i), lv[i].falloff.constant); + shader_float(va("u_lights[%d].linear", i), lv[i].falloff.linear); + shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic); + shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone); + shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone); + } +} + + // ----------------------------------------------------------------------------- // shadowmaps +static inline +shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) { + // Create a cubemap color texture + glGenTextures(1, &s->maps[light_index].texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].texture); + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB32F, texture_width, texture_width, 0, GL_RGB, GL_FLOAT, 0); + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // Create a cubemap depth texture + glGenTextures(1, &s->maps[light_index].depth_texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].depth_texture); + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + + // Create 6 framebuffers for each face of the cubemap + glGenFramebuffers(6, s->maps[light_index].fbos); + for (int i = 0; i < 6; i++) { + glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbos[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, s->maps[light_index].texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, s->maps[light_index].depth_texture, 0); + GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (GL_FRAMEBUFFER_COMPLETE != result) { + PANIC("ERROR: Framebuffer is not complete: %x\n", result); + } + } +} + shadowmap_t shadowmap(int texture_width) { // = 1024 shadowmap_t s = {0}; s.texture_width = texture_width; - + s.saved_fb = 0; glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb); - glGenFramebuffers(1, &s.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, s.fbo); - - glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &s.texture); - glBindTexture(GL_TEXTURE_2D, s.texture); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s.texture, 0); - -#if is(ems) - GLenum nones[] = { GL_NONE }; - glDrawBuffers(1, nones); - glReadBuffer(GL_NONE); -#else - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); -#endif - + for (int i = 0; i < MAX_LIGHTS; i++) { + shadowmap_init_caster(&s, i, texture_width); + } + glBindFramebuffer(GL_FRAMEBUFFER, s.saved_fb); return s; } void shadowmap_destroy(shadowmap_t *s) { - if (s->texture) { - glDeleteTextures(1, &s->texture); - } - if (s->fbo) { - glDeleteFramebuffers(1, &s->fbo); + for (int i = 0; i < MAX_LIGHTS; i++) { + glDeleteFramebuffers(6, s->maps[i].fbos); + glDeleteTextures(1, &s->maps[i].texture); + glDeleteTextures(1, &s->maps[i].depth_texture); } shadowmap_t z = {0}; *s = z; } void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection) { - copy44(s->proj, projection); - s->light_position = vec4(aLightPos.x, aLightPos.y, aLightPos.z, 1); - lookat44(s->mv, aLightPos, aLightAt, aLightUp); + // copy44(s->proj, projection); + // lookat44(s->mv, aLightPos, aLightAt, aLightUp); - mat44 bias = { - 0.5, 0.0, 0.0, 0.0, - 0.0, 0.5, 0.0, 0.0, - 0.0, 0.0, 0.5, 0.0, - 0.5, 0.5, 0.5, 1.0 }; + // mat44 bias = { + // 0.5, 0.0, 0.0, 0.0, + // 0.0, 0.5, 0.0, 0.0, + // 0.0, 0.0, 0.5, 0.0, + // 0.5, 0.5, 0.5, 1.0 }; - // s->shadowmatrix = bias; - // s->shadowmatrix *= s->proj; - // s->shadowmatrix *= s->mv; -// multiply44x3(s->shadowmatrix, s->mv, s->proj, bias); - multiply44x3(s->shadowmatrix, bias, s->proj, s->mv); - - // mvp = projection * s->mv; -// multiply44x2(s->mvp, s->mv, projection); - multiply44x2(s->mvp, projection, s->mv); + // multiply44x3(s->shadowmatrix, bias, s->proj, s->mv); + // multiply44x2(s->mvp, projection, s->mv); } +static shadowmap_t *active_shadowmap = NULL; + void shadowmap_begin(shadowmap_t *s) { - glGetIntegerv(GL_VIEWPORT, &s->saved_viewport[0]); + glGetIntegerv(GL_VIEWPORT, s->saved_vp); glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s->saved_fb); - glBindFramebuffer(GL_FRAMEBUFFER, s->fbo); - glViewport(0, 0, s->texture_width, s->texture_width); + s->saved_pass = model_setpass(RENDER_PASS_SHADOW); + s->step = 0; + s->light_step = 0; + active_shadowmap = s; - glClearDepth(1); - glClear(GL_DEPTH_BUFFER_BIT); + for (int i = 0; i < MAX_LIGHTS; i++) { + for (int j = 0; j < 6; j++) { + glBindFramebuffer(GL_FRAMEBUFFER, s->maps[i].fbos[j]); + glClearColor(0, 0, 0, 0); + glClearDepth(1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + } +} + +static void shadowmap_light_point(shadowmap_t *s, light_t *l, int dir) { + if(dir<0) return; + mat44 P, V, PV; + perspective44(P, 90.0f, 1.0f, l->shadow_bias, l->shadow_distance); + vec3 lightPos = l->pos; + + /**/ if(dir == 0) lookat44(V, lightPos, add3(lightPos, vec3(+1, 0, 0)), vec3(0, -1, 0)); // +X + else if(dir == 1) lookat44(V, lightPos, add3(lightPos, vec3(-1, 0, 0)), vec3(0, -1, 0)); // -X + else if(dir == 2) lookat44(V, lightPos, add3(lightPos, vec3( 0, +1, 0)), vec3(0, 0, +1)); // +Y + else if(dir == 3) lookat44(V, lightPos, add3(lightPos, vec3( 0, -1, 0)), vec3(0, 0, -1)); // -Y + else if(dir == 4) lookat44(V, lightPos, add3(lightPos, vec3( 0, 0, +1)), vec3(0, -1, 0)); // +Z + else /*dir == 5*/ lookat44(V, lightPos, add3(lightPos, vec3( 0, 0, -1)), vec3(0, -1, 0)); // -Z + multiply44x2(PV, P, V); // -Z + + copy44(s->V, V); + copy44(s->PV, PV); +} + +bool shadowmap_step(shadowmap_t *s) { + if (s->step >= 6) { + s->step = 0; + s->light_step++; + return false; + } + + glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbos[s->step]); + glViewport(0, 0, s->texture_width, s->texture_width); + + s->step++; + return true; +} + +void shadowmap_light(shadowmap_t *s, light_t *l) { + if (l->cast_shadows) { + int step = s->step - 1; + + if (l->type == LIGHT_POINT) { + shadowmap_light_point(s, l, step); + } else if (l->type == LIGHT_SPOT) { + // spot light + } else if (l->type == LIGHT_DIRECTIONAL) { + // directional light + } + } } void shadowmap_end(shadowmap_t *s) { - glViewport(s->saved_viewport[0], s->saved_viewport[1], s->saved_viewport[2], s->saved_viewport[3]); + glViewport(s->saved_vp[0], s->saved_vp[1], s->saved_vp[2], s->saved_vp[3]); glBindFramebuffer(GL_FRAMEBUFFER, s->saved_fb); + model_setpass(s->saved_pass); + active_shadowmap = NULL; } // shadowmap utils @@ -3710,6 +3884,25 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view, glUniform1f(loc, (float)window_time()); } + // shadow casting + if (shader == m.shadow_program) { + shadowmap_t *sm = active_shadowmap; + ASSERT(sm); + shader_mat44("cameraToShadowView", sm->V); + shader_mat44("cameraToShadowProjector", sm->PV); + } + + // shadow receiving + if (m.shadow_receiver) { + ASSERT(m.shadow_map); + shader_bool("u_shadow_receiver", GL_TRUE); + for (int i = 0; i < MAX_LIGHTS; i++) { + shader_cubemap(va("shadowMap[%d]", i), m.shadow_map->maps[i].texture); + } + } else { + shader_bool("u_shadow_receiver", GL_FALSE); + } + if (m.shading == SHADING_PBR) { handle old_shader = last_shader; shader_bind(shader); @@ -4323,12 +4516,13 @@ void model_set_renderstates(model_t *m) { transparent_rs->front_face = GL_CW; } - // Shadow pass @todo + // Shadow pass renderstate_t *shadow_rs = &m->rs[RENDER_PASS_SHADOW]; { shadow_rs->blend_enabled = 1; shadow_rs->blend_src = GL_SRC_ALPHA; shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA; + shadow_rs->cull_face_enabled = 1; shadow_rs->cull_face_mode = GL_BACK; shadow_rs->front_face = GL_CW; } @@ -4727,6 +4921,7 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ int rs_idx = model_getpass(); renderstate_t *rs = &m.rs[rs_idx]; + renderstate_apply(rs); glBindVertexArray( q->vao ); @@ -4810,31 +5005,33 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ renderstate_apply(rs); } - if (m.shading != SHADING_PBR) { - shader_texture_unit("u_texture2d", q->textures[i], texture_unit()); - shader_texture("u_lightmap", m.lightmap); + if (rs_idx != RENDER_PASS_SHADOW) { + if (m.shading != SHADING_PBR) { + shader_texture_unit("u_texture2d", q->textures[i], texture_unit()); + shader_texture("u_lightmap", m.lightmap); - int loc; - if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) { - bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id; - glUniform1i(loc, textured ? GL_TRUE : GL_FALSE); - if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) { - glUniform4f(loc, m.materials[i].layer[0].map.color.r, m.materials[i].layer[0].map.color.g, m.materials[i].layer[0].map.color.b, m.materials[i].layer[0].map.color.a); + int loc; + if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) { + bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id; + glUniform1i(loc, textured ? GL_TRUE : GL_FALSE); + if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) { + glUniform4f(loc, m.materials[i].layer[0].map.color.r, m.materials[i].layer[0].map.color.g, m.materials[i].layer[0].map.color.b, m.materials[i].layer[0].map.color.a); + } } - } - } else { - const material_t *material = &m.materials[i]; - shader_colormap_model_internal( "map_diffuse.color", "map_diffuse.has_tex", "map_diffuse_tex", material->layer[MATERIAL_CHANNEL_DIFFUSE].map ); - shader_colormap_model_internal( "map_normals.color", "map_normals.has_tex", "map_normals_tex", material->layer[MATERIAL_CHANNEL_NORMALS].map ); - shader_colormap_model_internal( "map_specular.color", "map_specular.has_tex", "map_specular_tex", material->layer[MATERIAL_CHANNEL_SPECULAR].map ); - shader_colormap_model_internal( "map_albedo.color", "map_albedo.has_tex", "map_albedo_tex", material->layer[MATERIAL_CHANNEL_ALBEDO].map ); - shader_colormap_model_internal( "map_roughness.color", "map_roughness.has_tex", "map_roughness_tex", material->layer[MATERIAL_CHANNEL_ROUGHNESS].map ); - shader_colormap_model_internal( "map_metallic.color", "map_metallic.has_tex", "map_metallic_tex", material->layer[MATERIAL_CHANNEL_METALLIC].map ); - shader_colormap_model_internal( "map_ao.color", "map_ao.has_tex", "map_ao_tex", material->layer[MATERIAL_CHANNEL_AO].map ); - shader_colormap_model_internal( "map_ambient.color", "map_ambient.has_tex", "map_ambient_tex", material->layer[MATERIAL_CHANNEL_AMBIENT].map ); - shader_colormap_model_internal( "map_emissive.color", "map_emissive.has_tex", "map_emissive_tex", material->layer[MATERIAL_CHANNEL_EMISSIVE].map ); - // shader_float( "specular_shininess", material->specular_shininess ); // unused, basic_specgloss.fs only + } else { + const material_t *material = &m.materials[i]; + shader_colormap_model_internal( "map_diffuse.color", "map_diffuse.has_tex", "map_diffuse_tex", material->layer[MATERIAL_CHANNEL_DIFFUSE].map ); + shader_colormap_model_internal( "map_normals.color", "map_normals.has_tex", "map_normals_tex", material->layer[MATERIAL_CHANNEL_NORMALS].map ); + shader_colormap_model_internal( "map_specular.color", "map_specular.has_tex", "map_specular_tex", material->layer[MATERIAL_CHANNEL_SPECULAR].map ); + shader_colormap_model_internal( "map_albedo.color", "map_albedo.has_tex", "map_albedo_tex", material->layer[MATERIAL_CHANNEL_ALBEDO].map ); + shader_colormap_model_internal( "map_roughness.color", "map_roughness.has_tex", "map_roughness_tex", material->layer[MATERIAL_CHANNEL_ROUGHNESS].map ); + shader_colormap_model_internal( "map_metallic.color", "map_metallic.has_tex", "map_metallic_tex", material->layer[MATERIAL_CHANNEL_METALLIC].map ); + shader_colormap_model_internal( "map_ao.color", "map_ao.has_tex", "map_ao_tex", material->layer[MATERIAL_CHANNEL_AO].map ); + shader_colormap_model_internal( "map_ambient.color", "map_ambient.has_tex", "map_ambient_tex", material->layer[MATERIAL_CHANNEL_AMBIENT].map ); + shader_colormap_model_internal( "map_emissive.color", "map_emissive.has_tex", "map_emissive_tex", material->layer[MATERIAL_CHANNEL_EMISSIVE].map ); + // shader_float( "specular_shininess", material->specular_shininess ); // unused, basic_specgloss.fs only + } } glDrawElementsInstanced(GL_TRIANGLES, 3*im->num_triangles, GL_UNSIGNED_INT, &tris[im->first_triangle], m.num_instances); @@ -4859,6 +5056,10 @@ void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* model model_set_state(m); } + if (model_getpass() == RENDER_PASS_SHADOW) { + shader = m.shadow_program; + } + model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); model_draw_call(m, shader > 0 ? shader : m.program, pass, pos44(view), models[0]); } @@ -5012,11 +5213,20 @@ void model_shading_custom(model_t *m, int shading, const char *vs, const char *f glUseProgram(0); if (m->program) glDeleteProgram(m->program); - const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM - int shaderprog = shader(strlerp(1,symbols,vs), strlerp(1,symbols,fs), //fs, - "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent,att_texcoord2","fragColor", - va("%s,%s,%s", defines ? defines : "NO_CUSTOM_DEFINES", shading_define, (flags&MODEL_RIMLIGHT)?"RIM":"")); - m->program = shaderprog; + + { + int shaderprog = shader(vs, fs, //fs, + "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent,att_texcoord2","fragColor", + va("%s,%s,%s", defines ? defines : "NO_CUSTOM_DEFINES", shading_define, (flags&MODEL_RIMLIGHT)?"RIM":"")); + m->program = shaderprog; + } + + { + int shaderprog = shader(vs, vfs_read("shaders/fs_shadow_vsm.glsl"), //fs, + "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent,att_texcoord2","fragcolor", + va("SHADOW_CAST,%s", defines ? defines : "NO_CUSTOM_DEFINES")); + m->shadow_program = shaderprog; + } model_init_uniforms(m); } @@ -5036,6 +5246,16 @@ void model_skybox(model_t *mdl, skybox_t sky, bool load_sh) { mdl->sky_env = sky.env; } +void model_shadow(model_t *mdl, shadowmap_t *sm) { + if (sm) { + mdl->shadow_receiver = true; + mdl->shadow_map = sm; + } else { + mdl->shadow_receiver = false; + mdl->shadow_map = NULL; + } +} + void model_fog(model_t *mdl, unsigned mode, vec3 color, float start, float end, float density) { unsigned oldprog = last_shader; shader_bind(mdl->program); diff --git a/engine/split/v4k_render.h b/engine/split/v4k_render.h index 602b815..0bc3370 100644 --- a/engine/split/v4k_render.h +++ b/engine/split/v4k_render.h @@ -65,6 +65,9 @@ typedef struct renderstate_t { // Scissor test bool scissor_test_enabled; + + // bool Seamless Cubemap + bool seamless_cubemap; } renderstate_t; API renderstate_t renderstate(); @@ -264,6 +267,7 @@ API void cubemap_sh_shader(cubemap_t *c); API void cubemap_sh_add_light(cubemap_t *c, vec3 light, vec3 dir, float strength); // lighting probe blending +// @note: uploads SH coefficients to shader API void cubemap_sh_blend(vec3 pos, float max_dist, unsigned count, cubemap_t *probes); // ----------------------------------------------------------------------------- @@ -274,6 +278,54 @@ API void fbo_bind(unsigned id); API void fbo_unbind(); API void fbo_destroy(unsigned id); +// ----------------------------------------------------------------------------- +// lights + +enum { + MAX_LIGHTS = 16, +}; + +enum LIGHT_TYPE { + LIGHT_DIRECTIONAL, + LIGHT_POINT, + LIGHT_SPOT, +}; + +typedef struct light_t { + char type; + vec3 diffuse, specular, ambient; + vec3 pos, dir; + struct { + float constant, linear, quadratic; + } falloff; + float radius; + float specularPower; + float innerCone, outerCone; + //@todo: cookie, flare + + // Shadowmapping + bool cast_shadows; + float shadow_distance; + float shadow_bias; + + // internals + bool cached; //< used by scene to invalidate cached light data +} light_t; + +API light_t light(); +// API void light_flags(int flags); +API void light_type(light_t* l, char type); +API void light_diffuse(light_t* l, vec3 color); +API void light_specular(light_t* l, vec3 color); +API void light_ambient(light_t* l, vec3 color); +API void light_teleport(light_t* l, vec3 pos); +API void light_dir(light_t* l, vec3 dir); +API void light_power(light_t* l, float power); +API void light_radius(light_t* l, float radius); +API void light_falloff(light_t* l, float constant, float linear, float quadratic); +API void light_cone(light_t* l, float innerCone, float outerCone); +API void light_update(unsigned num_lights, light_t *lv); + // ----------------------------------------------------------------------------- // shadowmaps @@ -285,15 +337,19 @@ API void fbo_destroy(unsigned id); // #endif typedef struct shadowmap_t { - mat44 shadowmatrix; - mat44 mvp; - mat44 mv; - mat44 proj; - vec4 light_position; - int saved_fb; - int saved_viewport[4]; - handle fbo, texture; + mat44 V; + mat44 PV; int texture_width; + int step; + int light_step; + + struct { + handle fbos[6], texture, depth_texture; + } maps[MAX_LIGHTS]; + + handle saved_fb; + handle saved_pass; + int saved_vp[4]; } shadowmap_t; API shadowmap_t shadowmap(int texture_width); // = 1024 @@ -301,13 +357,10 @@ API void shadowmap_destroy(shadowmap_t *s); API void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection); API void shadowmap_begin(shadowmap_t *s); +API bool shadowmap_step(shadowmap_t *s); +API void shadowmap_light(shadowmap_t *s, light_t *l); API void shadowmap_end(shadowmap_t *s); -// shadowmap utils - -API void shadowmatrix_proj(mat44 shm_proj, float aLightFov, float znear, float zfar); -API void shadowmatrix_ortho(mat44 shm_proj, float left, float right, float bottom, float top, float znear, float zfar); - // ----------------------------------------------------------------------------- // shaders @@ -696,6 +749,9 @@ typedef struct model_t { unsigned num_anims; unsigned num_frames; handle program; + handle shadow_program; + shadowmap_t *shadow_map; + bool shadow_receiver; float curframe; mat44 pivot; @@ -747,6 +803,7 @@ API void model_lod(model_t*, float lo_detail, float hi_detail, float morph); API void model_shading(model_t*, int shading); API void model_shading_custom(model_t*, int shading, const char *vs, const char *fs, const char *defines); API void model_skybox(model_t*, skybox_t sky, bool load_sh); +API void model_shadow(model_t*, shadowmap_t *sm); API void model_fog(model_t*, unsigned mode, vec3 color, float start, float end, float density); API void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader); API void model_render_skeleton(model_t, mat44 model); diff --git a/engine/split/v4k_scene.c b/engine/split/v4k_scene.c index 5b5ab77..ae73906 100644 --- a/engine/split/v4k_scene.c +++ b/engine/split/v4k_scene.c @@ -297,96 +297,6 @@ void object_billboard(object_t *obj, unsigned mode) { // ----------------------------------------------------------------------------- -light_t light() { - light_t l = {0}; - l.diffuse = vec3(1,1,1); - l.dir = vec3(1,-1,-1); - l.falloff.constant = 1.0f; - l.falloff.linear = 0.09f; - l.falloff.quadratic = 0.0032f; - l.specularPower = 32.f; - l.innerCone = 0.85f;// 31 deg - l.outerCone = 0.9f; // 25 deg - - return l; -} - -void light_type(light_t* l, char type) { - l->cached = 0; - l->type = type; -} - -void light_diffuse(light_t* l, vec3 color) { - l->cached = 0; - l->diffuse = color; -} - -void light_specular(light_t* l, vec3 color) { - l->cached = 0; - l->specular = color; -} - -void light_ambient(light_t* l, vec3 color) { - l->cached = 0; - l->ambient = color; -} - -void light_teleport(light_t* l, vec3 pos) { - l->cached = 0; - l->pos = pos; -} - -void light_dir(light_t* l, vec3 dir) { - l->cached = 0; - l->dir = dir; -} - -void light_power(light_t* l, float power) { - l->cached = 0; - l->specularPower = power; -} - -void light_falloff(light_t* l, float constant, float linear, float quadratic) { - l->cached = 0; - l->falloff.constant = constant; - l->falloff.linear = linear; - l->falloff.quadratic = quadratic; -} - -void light_radius(light_t* l, float radius) { - l->cached = 0; - l->radius = radius; -} - -void light_cone(light_t* l, float innerCone, float outerCone) { - l->cached = 0; - l->innerCone = acos(innerCone); - l->outerCone = acos(outerCone); -} - -void light_update(unsigned num_lights, light_t *lv) { - shader_int("u_num_lights", num_lights); - - for (unsigned i=0; i < num_lights; ++i) { - lv[i].cached = 1; - shader_int(va("u_lights[%d].type", i), lv[i].type); - shader_vec3(va("u_lights[%d].pos", i), lv[i].pos); - shader_vec3(va("u_lights[%d].dir", i), lv[i].dir); - shader_vec3(va("u_lights[%d].diffuse", i), lv[i].diffuse); - shader_vec3(va("u_lights[%d].specular", i), lv[i].specular); - shader_vec3(va("u_lights[%d].ambient", i), lv[i].ambient); - shader_float(va("u_lights[%d].power", i), lv[i].specularPower); - shader_float(va("u_lights[%d].radius", i), lv[i].radius); - shader_float(va("u_lights[%d].constant", i), lv[i].falloff.constant); - shader_float(va("u_lights[%d].linear", i), lv[i].falloff.linear); - shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic); - shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone); - shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone); - } -} - -// ----------------------------------------------------------------------------- - array(scene_t*) scenes; scene_t* last_scene; diff --git a/engine/split/v4k_scene.h b/engine/split/v4k_scene.h index f95a8e0..e44489c 100644 --- a/engine/split/v4k_scene.h +++ b/engine/split/v4k_scene.h @@ -75,48 +75,6 @@ API void object_billboard(object_t *obj, unsigned mode); // object_pose(transform); // @todo - -// light -enum LIGHT_TYPE { - LIGHT_DIRECTIONAL, - LIGHT_POINT, - LIGHT_SPOT, -}; - -enum LIGHT_FLAGS { - LIGHT_CAST_SHADOWS = 1, -}; - -typedef struct light_t { - char type; - vec3 diffuse, specular, ambient; - vec3 pos, dir; - struct { - float constant, linear, quadratic; - } falloff; - float radius; - float specularPower; - float innerCone, outerCone; - //@todo: cookie, flare - - // internals - bool cached; //< used by scene to invalidate cached light data -} light_t; - -API light_t light(); -// API void light_flags(int flags); -API void light_type(light_t* l, char type); -API void light_diffuse(light_t* l, vec3 color); -API void light_specular(light_t* l, vec3 color); -API void light_ambient(light_t* l, vec3 color); -API void light_teleport(light_t* l, vec3 pos); -API void light_dir(light_t* l, vec3 dir); -API void light_power(light_t* l, float power); -API void light_radius(light_t* l, float radius); -API void light_falloff(light_t* l, float constant, float linear, float quadratic); -API void light_cone(light_t* l, float innerCone, float outerCone); -API void light_update(unsigned num_lights, light_t *lv); - // scene enum SCENE_FLAGS { diff --git a/engine/v4k.c b/engine/v4k.c index d8de628..4bc3bed 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -16918,6 +16918,9 @@ renderstate_t renderstate() { // Disable scissor test by default state.scissor_test_enabled = GL_FALSE; + // Enable seamless cubemap by default + state.seamless_cubemap = GL_TRUE; + return state; } @@ -17024,6 +17027,13 @@ void renderstate_apply(const renderstate_t *state) { } else { glDisable(GL_SCISSOR_TEST); } + + // Apply seamless cubemap + if (state->seamless_cubemap) { + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + } else { + glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + } } } @@ -18248,92 +18258,256 @@ texture_t texture_compressed(const char *pathfile, unsigned flags) { return texture_compressed_from_mem(data, size, flags); } + +// ----------------------------------------------------------------------------- + +light_t light() { + light_t l = {0}; + l.diffuse = vec3(1,1,1); + l.dir = vec3(1,-1,-1); + l.falloff.constant = 1.0f; + l.falloff.linear = 0.09f; + l.falloff.quadratic = 0.0032f; + l.specularPower = 32.f; + l.innerCone = 0.85f;// 31 deg + l.outerCone = 0.9f; // 25 deg + l.shadow_distance = 100.0f; + l.shadow_bias = 0.5f; + return l; +} + +void light_type(light_t* l, char type) { + l->cached = 0; + l->type = type; +} + +void light_diffuse(light_t* l, vec3 color) { + l->cached = 0; + l->diffuse = color; +} + +void light_specular(light_t* l, vec3 color) { + l->cached = 0; + l->specular = color; +} + +void light_ambient(light_t* l, vec3 color) { + l->cached = 0; + l->ambient = color; +} + +void light_teleport(light_t* l, vec3 pos) { + l->cached = 0; + l->pos = pos; +} + +void light_dir(light_t* l, vec3 dir) { + l->cached = 0; + l->dir = dir; +} + +void light_power(light_t* l, float power) { + l->cached = 0; + l->specularPower = power; +} + +void light_falloff(light_t* l, float constant, float linear, float quadratic) { + l->cached = 0; + l->falloff.constant = constant; + l->falloff.linear = linear; + l->falloff.quadratic = quadratic; +} + +void light_radius(light_t* l, float radius) { + l->cached = 0; + l->radius = radius; +} + +void light_cone(light_t* l, float innerCone, float outerCone) { + l->cached = 0; + l->innerCone = acos(innerCone); + l->outerCone = acos(outerCone); +} + +void light_update(unsigned num_lights, light_t *lv) { + if (num_lights > MAX_LIGHTS) { + PRINTF("WARNING: num_lights > MAX_LIGHTS, clamping to MAX_LIGHTS\n"); + num_lights = MAX_LIGHTS; + } + shader_int("u_num_lights", num_lights); + + for (unsigned i=0; i < num_lights; ++i) { + lv[i].cached = 1; + shader_int(va("u_lights[%d].type", i), lv[i].type); + shader_vec3(va("u_lights[%d].pos", i), lv[i].pos); + shader_vec3(va("u_lights[%d].dir", i), lv[i].dir); + shader_vec3(va("u_lights[%d].diffuse", i), lv[i].diffuse); + shader_vec3(va("u_lights[%d].specular", i), lv[i].specular); + shader_vec3(va("u_lights[%d].ambient", i), lv[i].ambient); + shader_float(va("u_lights[%d].power", i), lv[i].specularPower); + shader_float(va("u_lights[%d].radius", i), lv[i].radius); + shader_float(va("u_lights[%d].constant", i), lv[i].falloff.constant); + shader_float(va("u_lights[%d].linear", i), lv[i].falloff.linear); + shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic); + shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone); + shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone); + } +} + + // ----------------------------------------------------------------------------- // shadowmaps +static inline +shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) { + // Create a cubemap color texture + glGenTextures(1, &s->maps[light_index].texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].texture); + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB32F, texture_width, texture_width, 0, GL_RGB, GL_FLOAT, 0); + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // Create a cubemap depth texture + glGenTextures(1, &s->maps[light_index].depth_texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].depth_texture); + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + + // Create 6 framebuffers for each face of the cubemap + glGenFramebuffers(6, s->maps[light_index].fbos); + for (int i = 0; i < 6; i++) { + glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbos[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, s->maps[light_index].texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, s->maps[light_index].depth_texture, 0); + GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (GL_FRAMEBUFFER_COMPLETE != result) { + PANIC("ERROR: Framebuffer is not complete: %x\n", result); + } + } +} + shadowmap_t shadowmap(int texture_width) { // = 1024 shadowmap_t s = {0}; s.texture_width = texture_width; - + s.saved_fb = 0; glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb); - glGenFramebuffers(1, &s.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, s.fbo); - - glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &s.texture); - glBindTexture(GL_TEXTURE_2D, s.texture); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s.texture, 0); - -#if is(ems) - GLenum nones[] = { GL_NONE }; - glDrawBuffers(1, nones); - glReadBuffer(GL_NONE); -#else - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); -#endif - + for (int i = 0; i < MAX_LIGHTS; i++) { + shadowmap_init_caster(&s, i, texture_width); + } + glBindFramebuffer(GL_FRAMEBUFFER, s.saved_fb); return s; } void shadowmap_destroy(shadowmap_t *s) { - if (s->texture) { - glDeleteTextures(1, &s->texture); - } - if (s->fbo) { - glDeleteFramebuffers(1, &s->fbo); + for (int i = 0; i < MAX_LIGHTS; i++) { + glDeleteFramebuffers(6, s->maps[i].fbos); + glDeleteTextures(1, &s->maps[i].texture); + glDeleteTextures(1, &s->maps[i].depth_texture); } shadowmap_t z = {0}; *s = z; } void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection) { - copy44(s->proj, projection); - s->light_position = vec4(aLightPos.x, aLightPos.y, aLightPos.z, 1); - lookat44(s->mv, aLightPos, aLightAt, aLightUp); + // copy44(s->proj, projection); + // lookat44(s->mv, aLightPos, aLightAt, aLightUp); - mat44 bias = { - 0.5, 0.0, 0.0, 0.0, - 0.0, 0.5, 0.0, 0.0, - 0.0, 0.0, 0.5, 0.0, - 0.5, 0.5, 0.5, 1.0 }; + // mat44 bias = { + // 0.5, 0.0, 0.0, 0.0, + // 0.0, 0.5, 0.0, 0.0, + // 0.0, 0.0, 0.5, 0.0, + // 0.5, 0.5, 0.5, 1.0 }; - // s->shadowmatrix = bias; - // s->shadowmatrix *= s->proj; - // s->shadowmatrix *= s->mv; -// multiply44x3(s->shadowmatrix, s->mv, s->proj, bias); - multiply44x3(s->shadowmatrix, bias, s->proj, s->mv); - - // mvp = projection * s->mv; -// multiply44x2(s->mvp, s->mv, projection); - multiply44x2(s->mvp, projection, s->mv); + // multiply44x3(s->shadowmatrix, bias, s->proj, s->mv); + // multiply44x2(s->mvp, projection, s->mv); } +static shadowmap_t *active_shadowmap = NULL; + void shadowmap_begin(shadowmap_t *s) { - glGetIntegerv(GL_VIEWPORT, &s->saved_viewport[0]); + glGetIntegerv(GL_VIEWPORT, s->saved_vp); glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s->saved_fb); - glBindFramebuffer(GL_FRAMEBUFFER, s->fbo); - glViewport(0, 0, s->texture_width, s->texture_width); + s->saved_pass = model_setpass(RENDER_PASS_SHADOW); + s->step = 0; + s->light_step = 0; + active_shadowmap = s; - glClearDepth(1); - glClear(GL_DEPTH_BUFFER_BIT); + for (int i = 0; i < MAX_LIGHTS; i++) { + for (int j = 0; j < 6; j++) { + glBindFramebuffer(GL_FRAMEBUFFER, s->maps[i].fbos[j]); + glClearColor(0, 0, 0, 0); + glClearDepth(1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + } +} + +static void shadowmap_light_point(shadowmap_t *s, light_t *l, int dir) { + if(dir<0) return; + mat44 P, V, PV; + perspective44(P, 90.0f, 1.0f, l->shadow_bias, l->shadow_distance); + vec3 lightPos = l->pos; + + /**/ if(dir == 0) lookat44(V, lightPos, add3(lightPos, vec3(+1, 0, 0)), vec3(0, -1, 0)); // +X + else if(dir == 1) lookat44(V, lightPos, add3(lightPos, vec3(-1, 0, 0)), vec3(0, -1, 0)); // -X + else if(dir == 2) lookat44(V, lightPos, add3(lightPos, vec3( 0, +1, 0)), vec3(0, 0, +1)); // +Y + else if(dir == 3) lookat44(V, lightPos, add3(lightPos, vec3( 0, -1, 0)), vec3(0, 0, -1)); // -Y + else if(dir == 4) lookat44(V, lightPos, add3(lightPos, vec3( 0, 0, +1)), vec3(0, -1, 0)); // +Z + else /*dir == 5*/ lookat44(V, lightPos, add3(lightPos, vec3( 0, 0, -1)), vec3(0, -1, 0)); // -Z + multiply44x2(PV, P, V); // -Z + + copy44(s->V, V); + copy44(s->PV, PV); +} + +bool shadowmap_step(shadowmap_t *s) { + if (s->step >= 6) { + s->step = 0; + s->light_step++; + return false; + } + + glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbos[s->step]); + glViewport(0, 0, s->texture_width, s->texture_width); + + s->step++; + return true; +} + +void shadowmap_light(shadowmap_t *s, light_t *l) { + if (l->cast_shadows) { + int step = s->step - 1; + + if (l->type == LIGHT_POINT) { + shadowmap_light_point(s, l, step); + } else if (l->type == LIGHT_SPOT) { + // spot light + } else if (l->type == LIGHT_DIRECTIONAL) { + // directional light + } + } } void shadowmap_end(shadowmap_t *s) { - glViewport(s->saved_viewport[0], s->saved_viewport[1], s->saved_viewport[2], s->saved_viewport[3]); + glViewport(s->saved_vp[0], s->saved_vp[1], s->saved_vp[2], s->saved_vp[3]); glBindFramebuffer(GL_FRAMEBUFFER, s->saved_fb); + model_setpass(s->saved_pass); + active_shadowmap = NULL; } // shadowmap utils @@ -20509,6 +20683,25 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view, glUniform1f(loc, (float)window_time()); } + // shadow casting + if (shader == m.shadow_program) { + shadowmap_t *sm = active_shadowmap; + ASSERT(sm); + shader_mat44("cameraToShadowView", sm->V); + shader_mat44("cameraToShadowProjector", sm->PV); + } + + // shadow receiving + if (m.shadow_receiver) { + ASSERT(m.shadow_map); + shader_bool("u_shadow_receiver", GL_TRUE); + for (int i = 0; i < MAX_LIGHTS; i++) { + shader_cubemap(va("shadowMap[%d]", i), m.shadow_map->maps[i].texture); + } + } else { + shader_bool("u_shadow_receiver", GL_FALSE); + } + if (m.shading == SHADING_PBR) { handle old_shader = last_shader; shader_bind(shader); @@ -21122,12 +21315,13 @@ void model_set_renderstates(model_t *m) { transparent_rs->front_face = GL_CW; } - // Shadow pass @todo + // Shadow pass renderstate_t *shadow_rs = &m->rs[RENDER_PASS_SHADOW]; { shadow_rs->blend_enabled = 1; shadow_rs->blend_src = GL_SRC_ALPHA; shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA; + shadow_rs->cull_face_enabled = 1; shadow_rs->cull_face_mode = GL_BACK; shadow_rs->front_face = GL_CW; } @@ -21526,6 +21720,7 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ int rs_idx = model_getpass(); renderstate_t *rs = &m.rs[rs_idx]; + renderstate_apply(rs); glBindVertexArray( q->vao ); @@ -21609,31 +21804,33 @@ void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_ renderstate_apply(rs); } - if (m.shading != SHADING_PBR) { - shader_texture_unit("u_texture2d", q->textures[i], texture_unit()); - shader_texture("u_lightmap", m.lightmap); + if (rs_idx != RENDER_PASS_SHADOW) { + if (m.shading != SHADING_PBR) { + shader_texture_unit("u_texture2d", q->textures[i], texture_unit()); + shader_texture("u_lightmap", m.lightmap); - int loc; - if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) { - bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id; - glUniform1i(loc, textured ? GL_TRUE : GL_FALSE); - if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) { - glUniform4f(loc, m.materials[i].layer[0].map.color.r, m.materials[i].layer[0].map.color.g, m.materials[i].layer[0].map.color.b, m.materials[i].layer[0].map.color.a); + int loc; + if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) { + bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id; + glUniform1i(loc, textured ? GL_TRUE : GL_FALSE); + if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) { + glUniform4f(loc, m.materials[i].layer[0].map.color.r, m.materials[i].layer[0].map.color.g, m.materials[i].layer[0].map.color.b, m.materials[i].layer[0].map.color.a); + } } - } - } else { - const material_t *material = &m.materials[i]; - shader_colormap_model_internal( "map_diffuse.color", "map_diffuse.has_tex", "map_diffuse_tex", material->layer[MATERIAL_CHANNEL_DIFFUSE].map ); - shader_colormap_model_internal( "map_normals.color", "map_normals.has_tex", "map_normals_tex", material->layer[MATERIAL_CHANNEL_NORMALS].map ); - shader_colormap_model_internal( "map_specular.color", "map_specular.has_tex", "map_specular_tex", material->layer[MATERIAL_CHANNEL_SPECULAR].map ); - shader_colormap_model_internal( "map_albedo.color", "map_albedo.has_tex", "map_albedo_tex", material->layer[MATERIAL_CHANNEL_ALBEDO].map ); - shader_colormap_model_internal( "map_roughness.color", "map_roughness.has_tex", "map_roughness_tex", material->layer[MATERIAL_CHANNEL_ROUGHNESS].map ); - shader_colormap_model_internal( "map_metallic.color", "map_metallic.has_tex", "map_metallic_tex", material->layer[MATERIAL_CHANNEL_METALLIC].map ); - shader_colormap_model_internal( "map_ao.color", "map_ao.has_tex", "map_ao_tex", material->layer[MATERIAL_CHANNEL_AO].map ); - shader_colormap_model_internal( "map_ambient.color", "map_ambient.has_tex", "map_ambient_tex", material->layer[MATERIAL_CHANNEL_AMBIENT].map ); - shader_colormap_model_internal( "map_emissive.color", "map_emissive.has_tex", "map_emissive_tex", material->layer[MATERIAL_CHANNEL_EMISSIVE].map ); - // shader_float( "specular_shininess", material->specular_shininess ); // unused, basic_specgloss.fs only + } else { + const material_t *material = &m.materials[i]; + shader_colormap_model_internal( "map_diffuse.color", "map_diffuse.has_tex", "map_diffuse_tex", material->layer[MATERIAL_CHANNEL_DIFFUSE].map ); + shader_colormap_model_internal( "map_normals.color", "map_normals.has_tex", "map_normals_tex", material->layer[MATERIAL_CHANNEL_NORMALS].map ); + shader_colormap_model_internal( "map_specular.color", "map_specular.has_tex", "map_specular_tex", material->layer[MATERIAL_CHANNEL_SPECULAR].map ); + shader_colormap_model_internal( "map_albedo.color", "map_albedo.has_tex", "map_albedo_tex", material->layer[MATERIAL_CHANNEL_ALBEDO].map ); + shader_colormap_model_internal( "map_roughness.color", "map_roughness.has_tex", "map_roughness_tex", material->layer[MATERIAL_CHANNEL_ROUGHNESS].map ); + shader_colormap_model_internal( "map_metallic.color", "map_metallic.has_tex", "map_metallic_tex", material->layer[MATERIAL_CHANNEL_METALLIC].map ); + shader_colormap_model_internal( "map_ao.color", "map_ao.has_tex", "map_ao_tex", material->layer[MATERIAL_CHANNEL_AO].map ); + shader_colormap_model_internal( "map_ambient.color", "map_ambient.has_tex", "map_ambient_tex", material->layer[MATERIAL_CHANNEL_AMBIENT].map ); + shader_colormap_model_internal( "map_emissive.color", "map_emissive.has_tex", "map_emissive_tex", material->layer[MATERIAL_CHANNEL_EMISSIVE].map ); + // shader_float( "specular_shininess", material->specular_shininess ); // unused, basic_specgloss.fs only + } } glDrawElementsInstanced(GL_TRIANGLES, 3*im->num_triangles, GL_UNSIGNED_INT, &tris[im->first_triangle], m.num_instances); @@ -21658,6 +21855,10 @@ void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* model model_set_state(m); } + if (model_getpass() == RENDER_PASS_SHADOW) { + shader = m.shadow_program; + } + model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); model_draw_call(m, shader > 0 ? shader : m.program, pass, pos44(view), models[0]); } @@ -21811,11 +22012,20 @@ void model_shading_custom(model_t *m, int shading, const char *vs, const char *f glUseProgram(0); if (m->program) glDeleteProgram(m->program); - const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM - int shaderprog = shader(strlerp(1,symbols,vs), strlerp(1,symbols,fs), //fs, - "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent,att_texcoord2","fragColor", - va("%s,%s,%s", defines ? defines : "NO_CUSTOM_DEFINES", shading_define, (flags&MODEL_RIMLIGHT)?"RIM":"")); - m->program = shaderprog; + + { + int shaderprog = shader(vs, fs, //fs, + "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent,att_texcoord2","fragColor", + va("%s,%s,%s", defines ? defines : "NO_CUSTOM_DEFINES", shading_define, (flags&MODEL_RIMLIGHT)?"RIM":"")); + m->program = shaderprog; + } + + { + int shaderprog = shader(vs, vfs_read("shaders/fs_shadow_vsm.glsl"), //fs, + "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent,att_texcoord2","fragcolor", + va("SHADOW_CAST,%s", defines ? defines : "NO_CUSTOM_DEFINES")); + m->shadow_program = shaderprog; + } model_init_uniforms(m); } @@ -21835,6 +22045,16 @@ void model_skybox(model_t *mdl, skybox_t sky, bool load_sh) { mdl->sky_env = sky.env; } +void model_shadow(model_t *mdl, shadowmap_t *sm) { + if (sm) { + mdl->shadow_receiver = true; + mdl->shadow_map = sm; + } else { + mdl->shadow_receiver = false; + mdl->shadow_map = NULL; + } +} + void model_fog(model_t *mdl, unsigned mode, vec3 color, float start, float end, float density) { unsigned oldprog = last_shader; shader_bind(mdl->program); @@ -23491,96 +23711,6 @@ void object_billboard(object_t *obj, unsigned mode) { // ----------------------------------------------------------------------------- -light_t light() { - light_t l = {0}; - l.diffuse = vec3(1,1,1); - l.dir = vec3(1,-1,-1); - l.falloff.constant = 1.0f; - l.falloff.linear = 0.09f; - l.falloff.quadratic = 0.0032f; - l.specularPower = 32.f; - l.innerCone = 0.85f;// 31 deg - l.outerCone = 0.9f; // 25 deg - - return l; -} - -void light_type(light_t* l, char type) { - l->cached = 0; - l->type = type; -} - -void light_diffuse(light_t* l, vec3 color) { - l->cached = 0; - l->diffuse = color; -} - -void light_specular(light_t* l, vec3 color) { - l->cached = 0; - l->specular = color; -} - -void light_ambient(light_t* l, vec3 color) { - l->cached = 0; - l->ambient = color; -} - -void light_teleport(light_t* l, vec3 pos) { - l->cached = 0; - l->pos = pos; -} - -void light_dir(light_t* l, vec3 dir) { - l->cached = 0; - l->dir = dir; -} - -void light_power(light_t* l, float power) { - l->cached = 0; - l->specularPower = power; -} - -void light_falloff(light_t* l, float constant, float linear, float quadratic) { - l->cached = 0; - l->falloff.constant = constant; - l->falloff.linear = linear; - l->falloff.quadratic = quadratic; -} - -void light_radius(light_t* l, float radius) { - l->cached = 0; - l->radius = radius; -} - -void light_cone(light_t* l, float innerCone, float outerCone) { - l->cached = 0; - l->innerCone = acos(innerCone); - l->outerCone = acos(outerCone); -} - -void light_update(unsigned num_lights, light_t *lv) { - shader_int("u_num_lights", num_lights); - - for (unsigned i=0; i < num_lights; ++i) { - lv[i].cached = 1; - shader_int(va("u_lights[%d].type", i), lv[i].type); - shader_vec3(va("u_lights[%d].pos", i), lv[i].pos); - shader_vec3(va("u_lights[%d].dir", i), lv[i].dir); - shader_vec3(va("u_lights[%d].diffuse", i), lv[i].diffuse); - shader_vec3(va("u_lights[%d].specular", i), lv[i].specular); - shader_vec3(va("u_lights[%d].ambient", i), lv[i].ambient); - shader_float(va("u_lights[%d].power", i), lv[i].specularPower); - shader_float(va("u_lights[%d].radius", i), lv[i].radius); - shader_float(va("u_lights[%d].constant", i), lv[i].falloff.constant); - shader_float(va("u_lights[%d].linear", i), lv[i].falloff.linear); - shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic); - shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone); - shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone); - } -} - -// ----------------------------------------------------------------------------- - array(scene_t*) scenes; scene_t* last_scene; diff --git a/engine/v4k.h b/engine/v4k.h index 1a4ffae..b93a231 100644 --- a/engine/v4k.h +++ b/engine/v4k.h @@ -3100,6 +3100,9 @@ typedef struct renderstate_t { // Scissor test bool scissor_test_enabled; + + // bool Seamless Cubemap + bool seamless_cubemap; } renderstate_t; API renderstate_t renderstate(); @@ -3299,6 +3302,7 @@ API void cubemap_sh_shader(cubemap_t *c); API void cubemap_sh_add_light(cubemap_t *c, vec3 light, vec3 dir, float strength); // lighting probe blending +// @note: uploads SH coefficients to shader API void cubemap_sh_blend(vec3 pos, float max_dist, unsigned count, cubemap_t *probes); // ----------------------------------------------------------------------------- @@ -3309,6 +3313,54 @@ API void fbo_bind(unsigned id); API void fbo_unbind(); API void fbo_destroy(unsigned id); +// ----------------------------------------------------------------------------- +// lights + +enum { + MAX_LIGHTS = 16, +}; + +enum LIGHT_TYPE { + LIGHT_DIRECTIONAL, + LIGHT_POINT, + LIGHT_SPOT, +}; + +typedef struct light_t { + char type; + vec3 diffuse, specular, ambient; + vec3 pos, dir; + struct { + float constant, linear, quadratic; + } falloff; + float radius; + float specularPower; + float innerCone, outerCone; + //@todo: cookie, flare + + // Shadowmapping + bool cast_shadows; + float shadow_distance; + float shadow_bias; + + // internals + bool cached; //< used by scene to invalidate cached light data +} light_t; + +API light_t light(); +// API void light_flags(int flags); +API void light_type(light_t* l, char type); +API void light_diffuse(light_t* l, vec3 color); +API void light_specular(light_t* l, vec3 color); +API void light_ambient(light_t* l, vec3 color); +API void light_teleport(light_t* l, vec3 pos); +API void light_dir(light_t* l, vec3 dir); +API void light_power(light_t* l, float power); +API void light_radius(light_t* l, float radius); +API void light_falloff(light_t* l, float constant, float linear, float quadratic); +API void light_cone(light_t* l, float innerCone, float outerCone); +API void light_update(unsigned num_lights, light_t *lv); + // ----------------------------------------------------------------------------- // shadowmaps @@ -3320,15 +3372,19 @@ API void fbo_destroy(unsigned id); // #endif typedef struct shadowmap_t { - mat44 shadowmatrix; - mat44 mvp; - mat44 mv; - mat44 proj; - vec4 light_position; - int saved_fb; - int saved_viewport[4]; - handle fbo, texture; + mat44 V; + mat44 PV; int texture_width; + int step; + int light_step; + + struct { + handle fbos[6], texture, depth_texture; + } maps[MAX_LIGHTS]; + + handle saved_fb; + handle saved_pass; + int saved_vp[4]; } shadowmap_t; API shadowmap_t shadowmap(int texture_width); // = 1024 @@ -3336,13 +3392,10 @@ API void shadowmap_destroy(shadowmap_t *s); API void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection); API void shadowmap_begin(shadowmap_t *s); +API bool shadowmap_step(shadowmap_t *s); +API void shadowmap_light(shadowmap_t *s, light_t *l); API void shadowmap_end(shadowmap_t *s); -// shadowmap utils - -API void shadowmatrix_proj(mat44 shm_proj, float aLightFov, float znear, float zfar); -API void shadowmatrix_ortho(mat44 shm_proj, float left, float right, float bottom, float top, float znear, float zfar); - // ----------------------------------------------------------------------------- // shaders @@ -3731,6 +3784,9 @@ typedef struct model_t { unsigned num_anims; unsigned num_frames; handle program; + handle shadow_program; + shadowmap_t *shadow_map; + bool shadow_receiver; float curframe; mat44 pivot; @@ -3782,6 +3838,7 @@ API void model_lod(model_t*, float lo_detail, float hi_detail, float morph); API void model_shading(model_t*, int shading); API void model_shading_custom(model_t*, int shading, const char *vs, const char *fs, const char *defines); API void model_skybox(model_t*, skybox_t sky, bool load_sh); +API void model_shadow(model_t*, shadowmap_t *sm); API void model_fog(model_t*, unsigned mode, vec3 color, float start, float end, float density); API void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader); API void model_render_skeleton(model_t, mat44 model); @@ -4017,48 +4074,6 @@ API void object_billboard(object_t *obj, unsigned mode); // object_pose(transform); // @todo - -// light -enum LIGHT_TYPE { - LIGHT_DIRECTIONAL, - LIGHT_POINT, - LIGHT_SPOT, -}; - -enum LIGHT_FLAGS { - LIGHT_CAST_SHADOWS = 1, -}; - -typedef struct light_t { - char type; - vec3 diffuse, specular, ambient; - vec3 pos, dir; - struct { - float constant, linear, quadratic; - } falloff; - float radius; - float specularPower; - float innerCone, outerCone; - //@todo: cookie, flare - - // internals - bool cached; //< used by scene to invalidate cached light data -} light_t; - -API light_t light(); -// API void light_flags(int flags); -API void light_type(light_t* l, char type); -API void light_diffuse(light_t* l, vec3 color); -API void light_specular(light_t* l, vec3 color); -API void light_ambient(light_t* l, vec3 color); -API void light_teleport(light_t* l, vec3 pos); -API void light_dir(light_t* l, vec3 dir); -API void light_power(light_t* l, float power); -API void light_radius(light_t* l, float radius); -API void light_falloff(light_t* l, float constant, float linear, float quadratic); -API void light_cone(light_t* l, float innerCone, float outerCone); -API void light_update(unsigned num_lights, light_t *lv); - // scene enum SCENE_FLAGS {