From 879c2c04d9c3879f871cfe79f9b25fd23c5184b4 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Thu, 11 Jun 2015 11:38:49 -0400 Subject: Wrote EntityManager --- src/component.h | 7 + src/components/ai.cpp | 142 ------------------- src/components/ai.h | 73 ---------- src/components/map_collision.cpp | 241 -------------------------------- src/components/map_collision.h | 47 ------- src/components/map_render.cpp | 40 ------ src/components/map_render.h | 19 --- src/components/physics_body.cpp | 66 --------- src/components/physics_body.h | 20 --- src/components/player_physics.cpp | 118 ---------------- src/components/player_physics.h | 25 ---- src/components/player_sprite.cpp | 60 -------- src/components/player_sprite.h | 23 --- src/components/simple_collider.cpp | 14 -- src/components/simple_collider.h | 18 --- src/components/static_image.cpp | 11 -- src/components/static_image.h | 18 --- src/components/user_movement.cpp | 100 ------------- src/components/user_movement.h | 19 --- src/entity.cpp | 46 ------ src/entity.h | 64 --------- src/entity_manager.h | 279 +++++++++++++++++++++++++++++++++++++ src/entityfactory.cpp | 182 ------------------------ src/entityfactory.h | 15 -- src/game.cpp | 178 ----------------------- src/game.h | 45 ------ src/main.cpp | 12 +- src/map.cpp | 151 -------------------- src/map.h | 70 ---------- src/world.cpp | 150 -------------------- src/world.h | 21 --- 31 files changed, 294 insertions(+), 1980 deletions(-) create mode 100644 src/component.h delete mode 100644 src/components/ai.cpp delete mode 100644 src/components/ai.h delete mode 100644 src/components/map_collision.cpp delete mode 100644 src/components/map_collision.h delete mode 100644 src/components/map_render.cpp delete mode 100644 src/components/map_render.h delete mode 100644 src/components/physics_body.cpp delete mode 100644 src/components/physics_body.h delete mode 100644 src/components/player_physics.cpp delete mode 100644 src/components/player_physics.h delete mode 100644 src/components/player_sprite.cpp delete mode 100644 src/components/player_sprite.h delete mode 100644 src/components/simple_collider.cpp delete mode 100644 src/components/simple_collider.h delete mode 100644 src/components/static_image.cpp delete mode 100644 src/components/static_image.h delete mode 100644 src/components/user_movement.cpp delete mode 100644 src/components/user_movement.h delete mode 100644 src/entity.cpp delete mode 100644 src/entity.h create mode 100644 src/entity_manager.h delete mode 100644 src/entityfactory.cpp delete mode 100644 src/entityfactory.h delete mode 100644 src/game.cpp delete mode 100644 src/game.h delete mode 100644 src/map.cpp delete mode 100644 src/map.h delete mode 100644 src/world.cpp delete mode 100644 src/world.h (limited to 'src') diff --git a/src/component.h b/src/component.h new file mode 100644 index 0000000..2cbdc9d --- /dev/null +++ b/src/component.h @@ -0,0 +1,7 @@ +#ifndef COMPONENT_H_F0CE4573 +#define COMPONENT_H_F0CE4573 + +class Component { +}; + +#endif /* end of include guard: COMPONENT_H_F0CE4573 */ diff --git a/src/components/ai.cpp b/src/components/ai.cpp deleted file mode 100644 index 9f8c764..0000000 --- a/src/components/ai.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include "ai.h" -#include -#include "entity.h" - -void AIActionContainer::addAction(std::shared_ptr action) -{ - actions.push_back(action); -} - -void AIActionContainer::start(Game& game, Entity& entity) -{ - currentAction = begin(actions); - - if (currentAction != end(actions)) - { - (*currentAction)->start(game, entity); - } -} - -void AIActionContainer::perform(Game& game, Entity& entity, double dt) -{ - if (!isDone()) - { - (*currentAction)->perform(game, entity, dt); - - if ((*currentAction)->isDone()) - { - currentAction++; - - if (!isDone()) - { - (*currentAction)->start(game, entity); - } - } - } -} - -bool AIActionContainer::isDone() const -{ - return currentAction == end(actions); -} - -AI::AI(int chance) -{ - this->chance = chance; -} - -int AI::getChance() const -{ - return chance; -} - -AI& AIComponent::emplaceAI(int chance) -{ - maxChance += chance; - ais.emplace_back(chance); - - return ais.back(); -} - -void AIComponent::tick(Game& game, Entity& entity, double dt) -{ - if (currentAI == nullptr) - { - int toChoose = rand() % maxChance; - for (auto& ai : ais) - { - if (toChoose < ai.getChance()) - { - currentAI = &ai; - break; - } else { - toChoose -= ai.getChance(); - } - } - - if (currentAI != nullptr) - { - currentAI->start(game, entity); - } - } - - if (currentAI != nullptr) - { - currentAI->perform(game, entity, dt); - - if (currentAI->isDone()) - { - currentAI = nullptr; - } - } -} - -MoveAIAction::MoveAIAction(Direction dir, int len, int speed) -{ - this->dir = dir; - this->len = len; - this->speed = speed; -} - -void MoveAIAction::start(Game& game, Entity& entity) -{ - remaining = len; -} - -void MoveAIAction::perform(Game&, Entity& entity, double dt) -{ - double dist = dt * speed; - remaining -= dist; - - switch (dir) - { - case Direction::Left: - { - entity.position.first -= dist; - break; - } - - case Direction::Right: - { - entity.position.first += dist; - break; - } - - case Direction::Up: - { - entity.position.second -= dist; - break; - } - - case Direction::Down: - { - entity.position.second += dist; - break; - } - } -} - -bool MoveAIAction::isDone() const -{ - return remaining <= 0.0; -} diff --git a/src/components/ai.h b/src/components/ai.h deleted file mode 100644 index 840283b..0000000 --- a/src/components/ai.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef AI_H -#define AI_H - -#include -#include -#include -#include - -#include "entity.h" - -class AIAction { - public: - virtual void start(Game& game, Entity& entity) = 0; - virtual void perform(Game& game, Entity& entity, double dt) = 0; - virtual bool isDone() const = 0; -}; - -class AIActionContainer { - public: - void addAction(std::shared_ptr action); - virtual void start(Game& game, Entity& entity); - virtual void perform(Game& game, Entity& entity, double dt); - virtual bool isDone() const; - - private: - std::list> actions; - std::list>::iterator currentAction {end(actions)}; -}; - -class AI : public AIActionContainer { - public: - AI(int chance); - - int getChance() const; - - private: - int chance; -}; - -class AIComponent : public Component { - public: - AI& emplaceAI(int chance); - void tick(Game& game, Entity& entity, double dt); - - private: - int maxChance = 0; - std::list ais; - AI* currentAI = nullptr; -}; - -class MoveAIAction : public AIAction { - public: - enum class Direction { - Left, - Right, - Up, - Down - }; - - MoveAIAction(Direction dir, int len, int speed); - - void start(Game& game, Entity& entity); - void perform(Game& game, Entity& entity, double dt); - bool isDone() const; - - private: - Direction dir; - int len; - int speed; - double remaining; -}; - -#endif /* end of include guard: AI_H */ diff --git a/src/components/map_collision.cpp b/src/components/map_collision.cpp deleted file mode 100644 index 3ad574b..0000000 --- a/src/components/map_collision.cpp +++ /dev/null @@ -1,241 +0,0 @@ -#include "map_collision.h" -#include "map.h" -#include "game.h" -#include "consts.h" - -MapCollisionComponent::MapCollisionComponent(const Map& map) : map(map) -{ - addCollision(-6, 0, MAP_HEIGHT*TILE_HEIGHT, Direction::left, collisionFromMoveType(map.getAdjacent(Map::MoveDir::Left).type)); - addCollision(GAME_WIDTH+6, 0, MAP_HEIGHT*TILE_HEIGHT, Direction::right, collisionFromMoveType(map.getAdjacent(Map::MoveDir::Right).type)); - addCollision(-6, 0, GAME_WIDTH, Direction::up, collisionFromMoveType(map.getAdjacent(Map::MoveDir::Up).type)); - addCollision(MAP_HEIGHT*TILE_HEIGHT+6, 0, GAME_WIDTH, Direction::down, collisionFromMoveType(map.getAdjacent(Map::MoveDir::Down).type)); - - for (int i=0; i 0) && (tile < 28) && (!((tile >= 5) && (tile <= 7)))) - { - addCollision(x*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, Direction::right, Collision::Type::wall); - addCollision((x+1)*TILE_WIDTH, y*TILE_HEIGHT, (y+1)*TILE_HEIGHT, Direction::left, Collision::Type::wall); - addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::wall); - addCollision((y+1)*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::up, Collision::Type::wall); - } else if ((tile >= 5) && (tile <= 7)) - { - addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::platform); - } else if (tile == 42) - { - addCollision(y*TILE_HEIGHT, x*TILE_WIDTH, (x+1)*TILE_WIDTH, Direction::down, Collision::Type::danger); - } - } -} - -void MapCollisionComponent::addCollision(double axis, double lower, double - upper, Direction dir, Collision::Type type) -{ - std::list::iterator it; - - switch (dir) - { - case Direction::up: - it = up_collisions.begin(); - for (; it!=up_collisions.end(); it++) - { - if (it->axis < axis) break; - } - - up_collisions.insert(it, {axis, lower, upper, type}); - - break; - case Direction::down: - it = down_collisions.begin(); - for (; it!=down_collisions.end(); it++) - { - if (it->axis > axis) break; - } - - down_collisions.insert(it, {axis, lower, upper, type}); - - break; - case Direction::left: - it = left_collisions.begin(); - for (; it!=left_collisions.end(); it++) - { - if (it->axis < axis) break; - } - - left_collisions.insert(it, {axis, lower, upper, type}); - - break; - case Direction::right: - it = right_collisions.begin(); - for (; it!=right_collisions.end(); it++) - { - if (it->axis > axis) break; - } - - right_collisions.insert(it, {axis, lower, upper, type}); - - break; - } -} - -void MapCollisionComponent::detectCollision(Game& game, Entity&, Entity& collider, std::pair old_position) -{ - if (collider.position.first < old_position.first) - { - for (auto collision : left_collisions) - { - if (collision.axis > old_position.first) continue; - if (collision.axis < collider.position.first) break; - - if ((old_position.second+collider.size.second > collision.lower) && (old_position.second < collision.upper)) - { - // We have a collision! - processCollision(game, collider, collision, Direction::left, old_position); - - break; - } - } - } else if (collider.position.first > old_position.first) - { - for (auto collision : right_collisions) - { - if (collision.axis < old_position.first+collider.size.first) continue; - if (collision.axis > collider.position.first+collider.size.first) break; - - if ((old_position.second+collider.size.second > collision.lower) && (old_position.second < collision.upper)) - { - // We have a collision! - processCollision(game, collider, collision, Direction::right, old_position); - - break; - } - } - } - - if (collider.position.second < old_position.second) - { - for (auto collision : up_collisions) - { - if (collision.axis > old_position.second) continue; - if (collision.axis < collider.position.second) break; - - if ((collider.position.first+collider.size.first > collision.lower) && (collider.position.first < collision.upper)) - { - // We have a collision! - processCollision(game, collider, collision, Direction::up, old_position); - - break; - } - } - } else if (collider.position.second > old_position.second) - { - for (auto collision : down_collisions) - { - if (collision.axis < old_position.second+collider.size.second) continue; - if (collision.axis > collider.position.second+collider.size.second) break; - - if ((collider.position.first+collider.size.first > collision.lower) && (collider.position.first < collision.upper)) - { - // We have a collision! - processCollision(game, collider, collision, Direction::down, old_position); - - break; - } - } - } -} - -void MapCollisionComponent::processCollision(Game& game, Entity& collider, Collision collision, Direction dir, std::pair old_position) -{ - if (collision.type == Collision::Type::wall) - { - if (dir == Direction::left) - { - collider.position.first = collision.axis; - - Message msg(Message::Type::setHorizontalVelocity); - msg.velocity = 0.0; - collider.send(game, msg); - } else if (dir == Direction::right) - { - collider.position.first = collision.axis - collider.size.first; - - Message msg(Message::Type::setHorizontalVelocity); - msg.velocity = 0.0; - collider.send(game, msg); - } else if (dir == Direction::up) - { - collider.position.second = collision.axis; - - Message msg(Message::Type::setVerticalVelocity); - msg.velocity = 0.0; - collider.send(game, msg); - } else if (dir == Direction::down) - { - collider.position.second = collision.axis - collider.size.second; - collider.send(game, Message::Type::hitTheGround); - } - } else if (collision.type == Collision::Type::wrap) - { - if (dir == Direction::left) - { - collider.position.first = GAME_WIDTH-collider.size.first/2; - } else if (dir == Direction::right) - { - collider.position.first = -collider.size.first/2; - } else if (dir == Direction::up) - { - collider.position.second = GAME_HEIGHT-collider.size.second/2-1; - } else if (dir == Direction::down) - { - collider.position.second = -collider.size.second/2; - } - } else if (collision.type == Collision::Type::teleport) - { - if (dir == Direction::left) - { - game.loadMap(game.getWorld().getMap(map.getAdjacent(Map::MoveDir::Left).map), std::make_pair(GAME_WIDTH-collider.size.first/2, old_position.second)); - } else if (dir == Direction::right) - { - game.loadMap(game.getWorld().getMap(map.getAdjacent(Map::MoveDir::Right).map), std::make_pair(-collider.size.first/2, old_position.second)); - } else if (dir == Direction::up) - { - game.loadMap(game.getWorld().getMap(map.getAdjacent(Map::MoveDir::Up).map), std::make_pair(old_position.first, MAP_HEIGHT*TILE_HEIGHT-collider.size.second/2)); - } else if (dir == Direction::down) - { - game.loadMap(game.getWorld().getMap(map.getAdjacent(Map::MoveDir::Down).map), std::make_pair(old_position.first, -collider.size.second/2)); - } - } else if (collision.type == Collision::Type::reverse) - { - // TODO reverse - if (dir == Direction::right) - { - collider.position.first = collision.axis - collider.size.first; - collider.send(game, Message::Type::walkLeft); - } - } else if (collision.type == Collision::Type::platform) - { - Message msg(Message::Type::drop); - msg.dropAxis = collision.axis; - - collider.send(game, msg); - } else if (collision.type == Collision::Type::danger) - { - game.playerDie(); - } -} - -MapCollisionComponent::Collision::Type MapCollisionComponent::collisionFromMoveType(Map::MoveType type) -{ - switch (type) - { - case Map::MoveType::Wall: return Collision::Type::wall; - case Map::MoveType::Wrap: return Collision::Type::wrap; - case Map::MoveType::Warp: return Collision::Type::teleport; - case Map::MoveType::ReverseWarp: return Collision::Type::reverse; - } -} diff --git a/src/components/map_collision.h b/src/components/map_collision.h deleted file mode 100644 index 18b9397..0000000 --- a/src/components/map_collision.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef MAP_COLLISION_H -#define MAP_COLLISION_H - -#include "entity.h" -#include "map.h" -#include - -class Game; - -class MapCollisionComponent : public Component { - public: - MapCollisionComponent(const Map& map); - void detectCollision(Game& game, Entity& entity, Entity& collider, std::pair old_position); - - private: - enum class Direction { - up, left, down, right - }; - - struct Collision { - enum class Type { - wall, - wrap, - teleport, - reverse, - platform, - danger - }; - - double axis; - double lower; - double upper; - Type type; - }; - - void addCollision(double axis, double lower, double upper, Direction dir, Collision::Type type); - void processCollision(Game& game, Entity& collider, Collision collision, Direction dir, std::pair old_position); - Collision::Type collisionFromMoveType(Map::MoveType type); - - std::list left_collisions; - std::list right_collisions; - std::list up_collisions; - std::list down_collisions; - const Map& map; -}; - -#endif diff --git a/src/components/map_render.cpp b/src/components/map_render.cpp deleted file mode 100644 index 45766e1..0000000 --- a/src/components/map_render.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "map_render.h" -#include "map.h" -#include "game.h" -#include "consts.h" - -MapRenderComponent::MapRenderComponent(const Map& map) : screen(GAME_WIDTH, GAME_HEIGHT) -{ - screen.fill(screen.entirety(), 0, 0, 0); - - Texture tiles("res/tiles.png"); - - for (int i=0; i 0) - { - screen.blit(tiles, src, dst); - } - } - - Texture font("res/font.bmp"); - std::string map_name = map.getTitle(); - int start_x = (40/2) - (map_name.length()/2); - for (size_t i=0; i TERMINAL_VELOCITY_X) velocity.first = TERMINAL_VELOCITY_X; - if (velocity.second < -TERMINAL_VELOCITY_Y) velocity.second = -TERMINAL_VELOCITY_Y; - if (velocity.second > TERMINAL_VELOCITY_Y) velocity.second = TERMINAL_VELOCITY_Y; - - // Do the movement - entity.position.first += velocity.first * dt; - entity.position.second += velocity.second * dt; -} - -void PhysicsBodyComponent::detectCollision(Game& game, Entity& entity, Entity& collider, std::pair old_position) -{ - // If already colliding, do nothing! - if ((old_position.first + collider.size.first > entity.position.first) - && (old_position.first < entity.position.first + entity.size.first) - && (old_position.second + collider.size.second > entity.position.second) - && (old_position.second < entity.position.second + entity.size.second)) - { - return; - } - - // If newly colliding, SHOCK AND HORROR! - if ((collider.position.first + collider.size.first > entity.position.first) - && (collider.position.first < entity.position.first + entity.size.first) - && (collider.position.second + collider.size.second > entity.position.second) - && (collider.position.second < entity.position.second + entity.size.second)) - { - Message msg(Message::Type::collision); - msg.collisionEntity = &collider; - - entity.send(game, msg); - } -} diff --git a/src/components/physics_body.h b/src/components/physics_body.h deleted file mode 100644 index 079cc51..0000000 --- a/src/components/physics_body.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef PHYSICS_BODY_H -#define PHYSICS_BODY_H - -#include "entity.h" -#include - -class Game; - -class PhysicsBodyComponent : public Component { - public: - void receive(Game& game, Entity& entity, const Message& msg); - void tick(Game& game, Entity& entity, double dt); - void detectCollision(Game& game, Entity& entity, Entity& collider, std::pair old_position); - - protected: - std::pair velocity; - std::pair accel; -}; - -#endif diff --git a/src/components/player_physics.cpp b/src/components/player_physics.cpp deleted file mode 100644 index 40e9948..0000000 --- a/src/components/player_physics.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "player_physics.h" -#include "muxer.h" -#include "game.h" -#include "consts.h" - -#define JUMP_VELOCITY(h, l) (-2 * (h) / (l)) -#define JUMP_GRAVITY(h, l) (2 * ((h) / (l)) / (l)) - -PlayerPhysicsComponent::PlayerPhysicsComponent() -{ - jump_velocity = JUMP_VELOCITY(TILE_HEIGHT*4.5, 0.3); - jump_gravity = JUMP_GRAVITY(TILE_HEIGHT*4.5, 0.3); - jump_gravity_short = JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233); - - accel.second = jump_gravity_short; -} - -void PlayerPhysicsComponent::receive(Game&, Entity& entity, const Message& msg) -{ - if (msg.type == Message::Type::walkLeft) - { - velocity.first = -90; - direction = -1; - } else if (msg.type == Message::Type::walkRight) - { - velocity.first = 90; - direction = 1; - } else if (msg.type == Message::Type::stopWalking) - { - velocity.first = 0.0; - direction = 0; - } else if (msg.type == Message::Type::setHorizontalVelocity) - { - velocity.first = msg.velocity; - } else if (msg.type == Message::Type::setVerticalVelocity) - { - velocity.second = msg.velocity; - } else if (msg.type == Message::Type::hitTheGround) - { - if (isFalling) - { - playSound("res/Randomize27.wav", 0.05); - isFalling = false; - } - - velocity.second = 0.0; - } else if (msg.type == Message::Type::jump) - { - playSound("res/Randomize87.wav", 0.25); - - velocity.second = jump_velocity; - accel.second = jump_gravity; - } else if (msg.type == Message::Type::stopJump) - { - accel.second = jump_gravity_short; - } else if (msg.type == Message::Type::canDrop) - { - canDrop = true; - } else if (msg.type == Message::Type::cantDrop) - { - canDrop = false; - } else if (msg.type == Message::Type::drop) - { - if (canDrop) - { - canDrop = false; - } else { - entity.position.second = msg.dropAxis - entity.size.second; - velocity.second = 0; - } - } else if (msg.type == Message::Type::die) - { - frozen = true; - } else if (msg.type == Message::Type::stopDying) - { - frozen = false; - } -} - -void PlayerPhysicsComponent::tick(Game& game, Entity& entity, double dt) -{ - // If frozen, do nothing - if (frozen) - { - return; - } - - // Continue walking even if blocked earlier - if (velocity.first == 0) - { - if (direction < 0) - { - velocity.first = -90; - } else if (direction > 0) - { - velocity.first = 90; - } - } - - // Increase gravity at the height of jump - if ((accel.second == jump_gravity) && (velocity.second >= 0)) - { - accel.second = jump_gravity_short; - } - - // Do the movement - std::pair old_position = entity.position; - PhysicsBodyComponent::tick(game, entity, dt); - - // Check for collisions - game.detectCollision(entity, old_position); - - // Are we moving due to gravity? - if (velocity.second != 0.0) - { - isFalling = true; - } -} diff --git a/src/components/player_physics.h b/src/components/player_physics.h deleted file mode 100644 index 26f1fae..0000000 --- a/src/components/player_physics.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef PLAYER_PHYSICS_H -#define PLAYER_PHYSICS_H - -#include "entity.h" -#include "physics_body.h" - -class Game; - -class PlayerPhysicsComponent : public PhysicsBodyComponent { - public: - PlayerPhysicsComponent(); - void tick(Game& game, Entity& entity, double dt); - void receive(Game& game, Entity& entity, const Message& msg); - - private: - double jump_velocity; - double jump_gravity; - double jump_gravity_short; - int direction = 0; - bool canDrop = false; - bool frozen = false; - bool isFalling = false; -}; - -#endif diff --git a/src/components/player_sprite.cpp b/src/components/player_sprite.cpp deleted file mode 100644 index 452a940..0000000 --- a/src/components/player_sprite.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "player_sprite.h" - -PlayerSpriteComponent::PlayerSpriteComponent() : sprite("res/Starla.png") -{ - -} - -void PlayerSpriteComponent::render(Game&, Entity& entity, Texture& buffer) -{ - animFrame++; - - int frame = 0; - if (isMoving) - { - frame += 2; - - if (animFrame % 20 < 10) - { - frame += 2; - } - } - - if (facingLeft) - { - frame++; - } - - double alpha = 1.0; - if (dying && (animFrame % 4 < 2)) - { - alpha = 0.0; - } - - Rectangle src_rect {frame*10, 0, 10, 12}; - Rectangle dst_rect {(int) entity.position.first, (int) entity.position.second, entity.size.first, entity.size.second}; - buffer.blit(sprite, src_rect, dst_rect, alpha); -} - -void PlayerSpriteComponent::receive(Game&, Entity&, const Message& msg) -{ - if (msg.type == Message::Type::walkLeft) - { - facingLeft = true; - isMoving = true; - } else if (msg.type == Message::Type::walkRight) - { - facingLeft = false; - isMoving = true; - } else if (msg.type == Message::Type::stopWalking) - { - isMoving = false; - } else if (msg.type == Message::Type::die) - { - dying = true; - isMoving = false; - } else if (msg.type == Message::Type::stopDying) - { - dying = false; - } -} diff --git a/src/components/player_sprite.h b/src/components/player_sprite.h deleted file mode 100644 index b1ac0af..0000000 --- a/src/components/player_sprite.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef PLAYER_SPRITE_H -#define PLAYER_SPRITE_H - -#include "entity.h" -#include "renderer.h" - -class Game; - -class PlayerSpriteComponent : public Component { - public: - PlayerSpriteComponent(); - void render(Game& game, Entity& entity, Texture& buffer); - void receive(Game& game, Entity& entity, const Message& msg); - - private: - Texture sprite; - int animFrame = 0; - bool facingLeft = false; - bool isMoving = false; - bool dying = false; -}; - -#endif diff --git a/src/components/simple_collider.cpp b/src/components/simple_collider.cpp deleted file mode 100644 index f4b414e..0000000 --- a/src/components/simple_collider.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "simple_collider.h" - -SimpleColliderComponent::SimpleColliderComponent(std::function callback) : callback(callback) -{ - -} - -void SimpleColliderComponent::receive(Game& game, Entity&, const Message& msg) -{ - if (msg.type == Message::Type::collision) - { - callback(game, *msg.collisionEntity); - } -} diff --git a/src/components/simple_collider.h b/src/components/simple_collider.h deleted file mode 100644 index 15d78cf..0000000 --- a/src/components/simple_collider.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SIMPLE_COLLIDER_H -#define SIMPLE_COLLIDER_H - -#include "entity.h" -#include - -class Game; - -class SimpleColliderComponent : public Component { - public: - SimpleColliderComponent(std::function callback); - void receive(Game& game, Entity& entity, const Message& msg); - - private: - std::function callback; -}; - -#endif diff --git a/src/components/static_image.cpp b/src/components/static_image.cpp deleted file mode 100644 index 9fa8dca..0000000 --- a/src/components/static_image.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "static_image.h" - -StaticImageComponent::StaticImageComponent(const char* filename) : sprite(Texture(filename)) -{ - -} - -void StaticImageComponent::render(Game&, Entity& entity, Texture& buffer) -{ - buffer.blit(sprite, sprite.entirety(), {(int) entity.position.first, (int) entity.position.second, entity.size.first, entity.size.second}); -} diff --git a/src/components/static_image.h b/src/components/static_image.h deleted file mode 100644 index 2dec78b..0000000 --- a/src/components/static_image.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef STATIC_IMAGE_H -#define STATIC_IMAGE_H - -#include "entity.h" -#include "renderer.h" - -class Game; - -class StaticImageComponent : public Component { - public: - StaticImageComponent(const char* filename); - void render(Game& game, Entity& entity, Texture& buffer); - - private: - Texture sprite; -}; - -#endif diff --git a/src/components/user_movement.cpp b/src/components/user_movement.cpp deleted file mode 100644 index e499fee..0000000 --- a/src/components/user_movement.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "user_movement.h" -#include "renderer.h" - -void UserMovementComponent::input(Game& game, Entity& entity, int key, int action) -{ - if (action == GLFW_PRESS) - { - if (key == GLFW_KEY_LEFT) - { - holdingLeft = true; - - if (!frozen) - { - entity.send(game, Message::Type::walkLeft); - } - } else if (key == GLFW_KEY_RIGHT) - { - holdingRight = true; - - if (!frozen) - { - entity.send(game, Message::Type::walkRight); - } - } else if (key == GLFW_KEY_UP) - { - if (!frozen) - { - entity.send(game, Message::Type::jump); - } - } else if (key == GLFW_KEY_DOWN) - { - if (!frozen) - { - entity.send(game, Message::Type::canDrop); - } - } - } else if (action == GLFW_RELEASE) - { - if (key == GLFW_KEY_LEFT) - { - holdingLeft = false; - - if (!frozen) - { - if (holdingRight) - { - entity.send(game, Message::Type::walkRight); - } else { - entity.send(game, Message::Type::stopWalking); - } - } - } else if (key == GLFW_KEY_RIGHT) - { - holdingRight = false; - - if (!frozen) - { - if (holdingLeft) - { - entity.send(game, Message::Type::walkLeft); - } else { - entity.send(game, Message::Type::stopWalking); - } - } - } else if (key == GLFW_KEY_DOWN) - { - if (!frozen) - { - entity.send(game, Message::Type::cantDrop); - } - } else if (key == GLFW_KEY_UP) - { - if (!frozen) - { - entity.send(game, Message::Type::stopJump); - } - } - } -} - -void UserMovementComponent::receive(Game& game, Entity& entity, const Message& msg) -{ - if (msg.type == Message::Type::die) - { - frozen = true; - - entity.send(game, Message::Type::stopWalking); - } else if (msg.type == Message::Type::stopDying) - { - frozen = false; - - if (holdingLeft) - { - entity.send(game, Message::Type::walkLeft); - } else if (holdingRight) - { - entity.send(game, Message::Type::walkRight); - } - } -} diff --git a/src/components/user_movement.h b/src/components/user_movement.h deleted file mode 100644 index 1bcf05e..0000000 --- a/src/components/user_movement.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef USER_MOVEMENT_H -#define USER_MOVEMENT_H - -#include "entity.h" - -class Game; - -class UserMovementComponent : public Component { - public: - void input(Game& game, Entity& entity, int key, int action); - void receive(Game&, Entity&, const Message& msg); - - private: - bool holdingLeft = false; - bool holdingRight = false; - bool frozen = false; -}; - -#endif diff --git a/src/entity.cpp b/src/entity.cpp deleted file mode 100644 index 2b6cd7f..0000000 --- a/src/entity.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "entity.h" - -void Entity::addComponent(std::shared_ptr c) -{ - components.push_back(c); -} - -void Entity::send(Game& game, const Message& msg) -{ - for (auto component : components) - { - component->receive(game, *this, msg); - } -} - -void Entity::tick(Game& game, double dt) -{ - for (auto component : components) - { - component->tick(game, *this, dt); - } -} - -void Entity::input(Game& game, int key, int action) -{ - for (auto component : components) - { - component->input(game, *this, key, action); - } -} - -void Entity::render(Game& game, Texture& buffer) -{ - for (auto component : components) - { - component->render(game, *this, buffer); - } -} - -void Entity::detectCollision(Game& game, Entity& collider, std::pair old_position) -{ - for (auto component : components) - { - component->detectCollision(game, *this, collider, old_position); - } -} diff --git a/src/entity.h b/src/entity.h deleted file mode 100644 index 7f09f2d..0000000 --- a/src/entity.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef ENTITY_H -#define ENTITY_H - -#include -#include "renderer.h" - -class Game; -class Map; -class Entity; -class Component; - -class Message { - public: - enum class Type { - walkLeft, - walkRight, - stopWalking, - setHorizontalVelocity, - setVerticalVelocity, - collision, - jump, - stopJump, - drop, - canDrop, - cantDrop, - die, - stopDying, - hitTheGround - }; - - Message(Type type) : type(type) {} - - Type type; - Entity* collisionEntity; - int dropAxis; - double velocity; -}; - -class Entity { - public: - void addComponent(std::shared_ptr c); - void send(Game& game, const Message& msg); - void tick(Game& game, double dt); - void input(Game& game, int key, int action); - void render(Game& game, Texture& buffer); - void detectCollision(Game& game, Entity& collider, std::pair old_position); - - std::pair position; - std::pair size; - - private: - std::list> components; -}; - -class Component { - public: - virtual void receive(Game&, Entity&, const Message&) {} - virtual void render(Game&, Entity&, Texture&) {} - virtual void tick(Game&, Entity&, double) {} - virtual void input(Game&, Entity&, int, int) {} - virtual void detectCollision(Game&, Entity&, Entity&, std::pair) {} -}; - -#endif diff --git a/src/entity_manager.h b/src/entity_manager.h new file mode 100644 index 0000000..74e758c --- /dev/null +++ b/src/entity_manager.h @@ -0,0 +1,279 @@ +#ifndef ENTITY_MANAGER_H_C5832F11 +#define ENTITY_MANAGER_H_C5832F11 + +#include +#include +#include +#include +#include "component.h" + +class EntityManager { + private: + struct EntityData { + int parent = -1; + std::map> components; + }; + + std::map entities; + std::map> cachedChildren; + std::map, std::set> cachedComponents; + + int nextEntityID = 0; + + bool ensureNoParentCycles(int entity, int parent) + { + EntityData& data = entities[parent]; + if (data.parent == entity) + { + return false; + } else if (data.parent == -1) + { + return true; + } + + return ensureNoParentCycles(entity, data.parent); + } + + std::set getEntitiesWithComponents(std::set& componentTypes) + { + if (cachedComponents.count(componentTypes) == 1) + { + return cachedComponents[componentTypes]; + } + + std::set& cache = cachedComponents[componentTypes]; + for (auto& entity : entities) + { + EntityData& data = entity.second; + bool cacheEntity = true; + + for (auto& componentType : componentTypes) + { + if (data.components.count(componentType) == 0) + { + cacheEntity = false; + break; + } + } + + if (cacheEntity) + { + cache.insert(entity.first); + } + } + + return cache; + } + + template std::set getEntitiesWithComponents(std::set& componentTypes) + { + componentTypes.insert(typeid(T)); + + return getEntitiesWithComponents(componentTypes); + } + + public: + EntityManager() = default; + EntityManager(const EntityManager& copy) = delete; + + int emplaceEntity() + { + // Find a suitable entity ID + while ((entities.count(nextEntityID) == 1) && (nextEntityID >= 0)) + { + nextEntityID++; + } + + if (nextEntityID < 0) + { + nextEntityID = 0; + + while ((entities.count(nextEntityID) == 1) && (nextEntityID >= 0)) + { + nextEntityID++; + } + + assert(nextEntityID >= 0); + } + + // Initialize the data + int id = nextEntityID++; + entities[id]; + + return id; + } + + void deleteEntity(int entity) + { + assert(entities.count(entity) == 1); + + EntityData& data = entities[entity]; + + // Destroy the children + std::set children = getChildren(entity); + for (int child : children) + { + EntityData& childData = entities[child]; + childData.parent = -1; + + deleteEntity(child); + } + + // Uncache children + cachedChildren.erase(entity); + + if ((data.parent != -1) && (cachedChildren.count(data.parent) == 1)) + { + cachedChildren[data.parent].erase(entity); + } + + // Uncache components + for (auto& cache : cachedComponents) + { + cache.second.erase(entity); + } + + // Destroy the data + entities.erase(entity); + } + + std::set getChildren(int parent) + { + assert(entities.count(parent) == 1); + + if (cachedChildren.count(parent) == 1) + { + return cachedChildren[parent]; + } + + std::set& cache = cachedChildren[parent]; + for (auto& entity : entities) + { + EntityData& data = entity.second; + if (data.parent == parent) + { + cache.insert(entity.first); + } + } + + return cache; + } + + void setParent(int entity, int parent) + { + assert(entities.count(entity) == 1); + assert(entities.count(parent) == 1); + assert(ensureNoParentCycles(entity, parent)); + + EntityData& data = entities[entity]; + + // Remove from old parent + if (data.parent != -1) + { + if (cachedChildren.count(data.parent) == 1) + { + cachedChildren[data.parent].erase(entity); + } + } + + data.parent = parent; + + // Cache new parent + if (cachedChildren.count(parent) == 1) + { + cachedChildren[parent].insert(entity); + } + } + + void setNoParent(int entity) + { + assert(entities.count(entity) == 1); + + EntityData& data = entities[entity]; + + // Remove from old parent + if (data.parent != -1) + { + if (cachedChildren.count(data.parent) == 1) + { + cachedChildren[data.parent].erase(entity); + } + } + + data.parent = -1; + } + + int getParent(int entity) + { + assert(entities.count(entity) == 1); + + EntityData& data = entities[entity]; + return data.parent; + } + + template T& emplaceComponent(int entity, Args&&... args) + { + assert(entities.count(entity) == 1); + + EntityData& data = entities[entity]; + std::type_index componentType = typeid(T); + + assert(data.components.count(componentType) == 0); + + // Initialize the component + std::unique_ptr ptr = std::unique_ptr(new T(std::forward(args)...)); + T& component = *ptr; + data.components[componentType] = std::move(ptr); + + // Invalidate related caches + std::remove_if(begin(cachedComponents), end(cachedComponents), [&] (std::pair, int>& cache) { + return cache.first.count(componentType) == 1; + }); + + return component; + } + + template void removeComponent(int entity) + { + assert(entities.count(entity) == 1); + + EntityData& data = entities[entity]; + std::type_index componentType = typeid(T); + + assert(data.components.count(componentType) == 1); + + // Destroy the component + data.components.erase(componentType); + + // Uncache the component + for (auto& cache : cachedComponents) + { + if (cache.first.count(componentType) == 1) + { + cache.second.erase(entity); + } + } + } + + template T& getComponent(int entity) + { + assert(entities.count(entity) == 1); + + EntityData& data = entities[entity]; + std::type_index componentType = typeid(T); + + assert(data.components.count(componentType) == 1); + + return *(data.components[componentType]); + } + + template std::set getEntitiesWithComponents() + { + std::set componentTypes; + componentTypes.insert(typeid(T)); + + return getEntitiesWithComponents(componentTypes); + } +}; + +#endif /* end of include guard: ENTITY_MANAGER_H_C5832F11 */ diff --git a/src/entityfactory.cpp b/src/entityfactory.cpp deleted file mode 100644 index b80fe99..0000000 --- a/src/entityfactory.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "entityfactory.h" -#include -#include "muxer.h" -#include -#include -#include -#include "components/static_image.h" -#include "components/simple_collider.h" -#include "components/physics_body.h" -#include "components/ai.h" -#include "game.h" - -void parseEntityAIData(AI& ai, xmlNodePtr node, const std::map& items) -{ - xmlChar* key; - - for (xmlNodePtr aiNode = node->xmlChildrenNode; aiNode != NULL; aiNode = aiNode->next) - { - if (!xmlStrcmp(aiNode->name, (xmlChar*) "move")) - { - MoveAIAction::Direction dir; - int len; - int speed; - - key = xmlGetProp(aiNode, (xmlChar*) "direction"); - if (key == 0) exit(2); - if (!xmlStrcmp(key, (xmlChar*) "left")) - { - dir = MoveAIAction::Direction::Left; - } else if (!xmlStrcmp(key, (xmlChar*) "right")) - { - dir = MoveAIAction::Direction::Right; - } else if (!xmlStrcmp(key, (xmlChar*) "up")) - { - dir = MoveAIAction::Direction::Up; - } else if (!xmlStrcmp(key, (xmlChar*) "down")) - { - dir = MoveAIAction::Direction::Down; - } else { - exit(2); - } - xmlFree(key); - - key = xmlGetProp(aiNode, (xmlChar*) "length"); - if (key != 0) - { - len = atoi((char*) key); - } else { - key = xmlGetProp(aiNode, (xmlChar*) "length-var"); - if (key == 0) exit(2); - std::string varName = (char*) key; - len = items.at(varName); - } - xmlFree(key); - - key = xmlGetProp(aiNode, (xmlChar*) "speed"); - if (key != 0) - { - speed = atoi((char*) key); - } else { - key = xmlGetProp(aiNode, (xmlChar*) "speed-var"); - if (key == 0) exit(2); - std::string varName = (char*) key; - speed = items.at(varName); - } - xmlFree(key); - - ai.addAction(std::make_shared(dir, len, speed)); - } else if (!xmlStrcmp(aiNode->name, (xmlChar*) "switch")) - { - key = xmlGetProp(aiNode, (xmlChar*) "item"); - if (key == 0) exit(2); - std::string switchItem = (char*) key; - xmlFree(key); - - for (xmlNodePtr switchNode = aiNode->xmlChildrenNode; switchNode != NULL; switchNode = switchNode->next) - { - if (!xmlStrcmp(switchNode->name, (xmlChar*) "case")) - { - key = xmlGetProp(switchNode, (xmlChar*) "value"); - if (key == 0) exit(2); - int caseValue = atoi((char*) key); - xmlFree(key); - - if (items.at(switchItem) == caseValue) - { - parseEntityAIData(ai, switchNode, items); - } - } - } - } - } -} - -std::shared_ptr EntityFactory::createNamedEntity(const std::string name, const std::map& items) -{ - xmlDocPtr doc = xmlParseFile("res/entities.xml"); - if (doc == nullptr) - { - fprintf(stderr, "Error reading entities\n"); - exit(-1); - } - - xmlNodePtr top = xmlDocGetRootElement(doc); - if (top == nullptr) - { - fprintf(stderr, "Empty entities file\n"); - exit(-1); - } - - if (xmlStrcmp(top->name, (const xmlChar*) "entities")) - { - fprintf(stderr, "Invalid entities definition\n"); - exit(-1); - } - - auto entity = std::make_shared(); - - xmlChar* key; - for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next) - { - if (!xmlStrcmp(node->name, (xmlChar*) "entity")) - { - key = xmlGetProp(node, (xmlChar*) "id"); - if (key == 0) exit(-1); - std::string entityID = (char*) key; - xmlFree(key); - - if (entityID == name) - { - key = xmlGetProp(node, (xmlChar*) "sprite"); - if (key == 0) exit(-1); - auto spriteComponent = std::make_shared((char*) key); - entity->addComponent(spriteComponent); - xmlFree(key); - - auto physicsComponent = std::make_shared(); - entity->addComponent(physicsComponent); - - key = xmlGetProp(node, (xmlChar*) "width"); - if (key == 0) exit(-1); - entity->size.first = atoi((char*) key); - xmlFree(key); - - key = xmlGetProp(node, (xmlChar*) "height"); - if (key == 0) exit(-1); - entity->size.second = atoi((char*) key); - xmlFree(key); - - bool addAI = false; - auto aiComponent = std::make_shared(); - - for (xmlNodePtr entityNode = node->xmlChildrenNode; entityNode != NULL; entityNode = entityNode->next) - { - if (!xmlStrcmp(entityNode->name, (xmlChar*) "ai")) - { - addAI = true; - - xmlChar* chanceKey = xmlGetProp(entityNode, (xmlChar*) "chance"); - if (chanceKey == 0) exit(2); - int chance = atoi((char*) chanceKey); - xmlFree(chanceKey); - - AI& ai = aiComponent->emplaceAI(chance); - parseEntityAIData(ai, entityNode, items); - } - } - - if (addAI) - { - entity->addComponent(aiComponent); - } - - break; - } - } - } - - xmlFreeDoc(doc); - - return entity; -} diff --git a/src/entityfactory.h b/src/entityfactory.h deleted file mode 100644 index 56f7216..0000000 --- a/src/entityfactory.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef ENTITYFACTORY_H -#define ENTITYFACTORY_H - -#include -#include - -class Entity; -class Map; - -class EntityFactory { - public: - static std::shared_ptr createNamedEntity(const std::string name, const std::map& items); -}; - -#endif diff --git a/src/game.cpp b/src/game.cpp deleted file mode 100644 index 673c804..0000000 --- a/src/game.cpp +++ /dev/null @@ -1,178 +0,0 @@ -#include "game.h" -#include -#include "renderer.h" -#include "muxer.h" -#include "map.h" -#include "components/user_movement.h" -#include "components/player_physics.h" -#include "components/player_sprite.h" -#include "components/map_render.h" -#include "components/map_collision.h" -#include "consts.h" - -Game::Game(const char* mapfile) : world(mapfile) -{ - // Set up entities - player = std::make_shared(); - player->position = world.getStartingPosition(); - player->size = std::make_pair(10.0,12.0); - - auto player_input = std::make_shared(); - player->addComponent(player_input); - - auto player_physics = std::make_shared(); - player->addComponent(player_physics); - - auto player_anim = std::make_shared(); - player->addComponent(player_anim); - - const Map& startingMap = world.getStartingMap(); - save = {&startingMap, player->position}; - - loadMap(startingMap, player->position); -} - -void key_callback(GLFWwindow* window, int key, int, int action, int) -{ - Game* game = (Game*) glfwGetWindowUserPointer(window); - - if ((key == GLFW_KEY_ESCAPE) && (action == GLFW_PRESS)) - { - game->shouldQuit = true; - } - - for (auto entity : game->entities) - { - entity->input(*game, key, action); - } -} - -void Game::execute(GLFWwindow* window) -{ - glfwSwapInterval(1); - glfwSetWindowUserPointer(window, this); - glfwSetKeyCallback(window, key_callback); - - Texture buffer(GAME_WIDTH, GAME_HEIGHT); - - double lastTime = glfwGetTime(); - const double dt = 0.01; - double accumulator = 0.0; - - while (!(shouldQuit || glfwWindowShouldClose(window))) - { - double currentTime = glfwGetTime(); - double frameTime = currentTime - lastTime; - lastTime = currentTime; - - // Should we load a new world? - if (newWorld) - { - newWorld = false; - entities.clear(); - entities = std::move(nextEntities); - - player->position = nextPosition; - } - - // Handle input - glfwPollEvents(); - - // Tick! - accumulator += frameTime; - while (accumulator >= dt) - { - for (auto entity : entities) - { - entity->tick(*this, dt); - } - - accumulator -= dt; - } - - // Do any scheduled tasks - for (auto& task : scheduled) - { - task.first -= frameTime; - - if (task.first <= 0) - { - task.second(); - } - } - - scheduled.remove_if([] (std::pair> value) { return value.first <= 0; }); - - // Do rendering - buffer.fill(buffer.entirety(), 0, 0, 0); - for (auto entity : entities) - { - entity->render(*this, buffer); - } - - buffer.renderScreen(); - } -} - -void Game::loadMap(const Map& map, std::pair position) -{ - auto mapEn = std::make_shared(); - - auto map_render = std::make_shared(map); - mapEn->addComponent(map_render); - - auto map_collision = std::make_shared(map); - mapEn->addComponent(map_collision); - - // Map in the back, player on top, rest of entities in between - nextEntities.clear(); - nextEntities.push_back(mapEn); - map.createEntities(nextEntities); - nextEntities.push_back(player); - - newWorld = true; - - currentMap = ↦ - nextPosition = position; -} - -void Game::detectCollision(Entity& collider, std::pair old_position) -{ - for (auto entity : entities) - { - entity->detectCollision(*this, collider, old_position); - } -} - -void Game::saveGame() -{ - save = {currentMap, player->position}; -} - -void Game::schedule(double time, std::function callback) -{ - scheduled.emplace_front(time, std::move(callback)); -} - -void Game::playerDie() -{ - player->send(*this, Message::Type::die); - - playSound("res/Hit_Hurt5.wav", 0.25); - - schedule(0.75, [&] () { - if (*currentMap != *save.map) - { - loadMap(*save.map, save.position); - } else { - player->position = save.position; - } - - player->send(*this, Message::Type::stopDying); - }); -} - -const World& Game::getWorld() const -{ - return world; -} diff --git a/src/game.h b/src/game.h deleted file mode 100644 index dd4b2f7..0000000 --- a/src/game.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef GAME_H -#define GAME_H - -#include -#include -#include -#include -#include "map.h" -#include "world.h" - -class Entity; -struct GLFWwindow; - -struct Savefile { - const Map* map; - std::pair position; -}; - -class Game { - public: - Game(const char* maps); - void execute(GLFWwindow* window); - void loadMap(const Map& map, std::pair position); - void detectCollision(Entity& collider, std::pair old_position); - void saveGame(); - void schedule(double time, std::function callback); - void playerDie(); - const World& getWorld() const; - - private: - friend void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods); - - std::list> entities; - std::list> nextEntities; - std::pair nextPosition; - bool newWorld; - std::shared_ptr player; - const Map* currentMap; - Savefile save; - std::list>> scheduled; - bool shouldQuit = false; - World world; -}; - -#endif diff --git a/src/main.cpp b/src/main.cpp index 4157350..29a364b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,9 @@ #include #include -#include "renderer.h" #include -#include "game.h" +#include "renderer.h" #include "muxer.h" +#include "entity_manager.h" int main() { @@ -14,8 +14,12 @@ int main() // Put this in a block so game goes out of scope before we destroy the renderer { - Game game {"res/maps.xml"}; - game.execute(window); + EntityManager manager; + + int eRef = manager.emplaceEntity(); + int eRef2 = manager.emplaceEntity(); + manager.setParent(eRef, eRef2); + printf("%d\n", manager.getParent(eRef)); } destroyMuxer(); diff --git a/src/map.cpp b/src/map.cpp deleted file mode 100644 index e3725b2..0000000 --- a/src/map.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include "map.h" -#include -#include -#include -#include "entityfactory.h" -#include "entity.h" -#include "game.h" -#include "consts.h" - -Map::Map(int id) -{ - this->id = id; - mapdata = (int*) calloc(1, sizeof(int)); -} - -Map::Map(const Map& map) -{ - mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int)); - memcpy(mapdata, map.mapdata, MAP_WIDTH*MAP_HEIGHT*sizeof(int)); - - id = map.id; - title = map.title; - adjacents = map.adjacents; - entities = map.entities; -} - -Map::Map(Map&& map) : Map() -{ - swap(*this, map); -} - -Map::~Map() -{ - free(mapdata); -} - -Map& Map::operator= (Map map) -{ - swap(*this, map); - - return *this; -} - -void swap(Map& first, Map& second) -{ - std::swap(first.mapdata, second.mapdata); - std::swap(first.title, second.title); - std::swap(first.adjacents, second.adjacents); - std::swap(first.id, second.id); - std::swap(first.entities, second.entities); -} - -int Map::getID() const -{ - return id; -} - -const int* Map::getMapdata() const -{ - return mapdata; -} - -std::string Map::getTitle() const -{ - return title; -} - -void Map::createEntities(std::list>& entities) const -{ - for (auto data : this->entities) - { - auto entity = EntityFactory::createNamedEntity(data.name, data.items); - entity->position = data.position; - - entities.push_back(entity); - } -} - -bool Map::operator==(const Map& other) const -{ - return id == other.id; -} - -bool Map::operator!=(const Map& other) const -{ - return id != other.id; -} - -Map::MoveType Map::moveTypeForShort(std::string str) -{ - if (str == "wrap") return MoveType::Wrap; - if (str == "warp") return MoveType::Warp; - if (str == "reverseWarp") return MoveType::ReverseWarp; - - return MoveType::Wall; -} - -Map::MoveDir Map::moveDirForShort(std::string str) -{ - if (str == "right") return MoveDir::Right; - if (str == "up") return MoveDir::Up; - if (str == "down") return MoveDir::Down; - - return MoveDir::Left; -} - -static const Map::Adjacent defaultAdjacent {}; -const Map::Adjacent& Map::getAdjacent(MoveDir dir) const -{ - if (adjacents.count(dir) > 0) - { - return adjacents.at(dir); - } else { - return defaultAdjacent; - } -} - -bool Map::moveTypeTakesMap(MoveType type) -{ - switch (type) - { - case MoveType::Wall: return false; - case MoveType::Wrap: return false; - case MoveType::Warp: return true; - case MoveType::ReverseWarp: return true; - } -} - -void Map::setMapdata(int* mapdata) -{ - free(this->mapdata); - this->mapdata = mapdata; -} - -void Map::setTitle(std::string title) -{ - this->title = title; -} - -void Map::setAdjacent(MoveDir dir, MoveType type, int map) -{ - Adjacent& cur = adjacents[dir]; - cur.type = type; - if (map != -1) cur.map = map; -} - -void Map::addEntity(EntityData& data) -{ - entities.push_back(data); -} - diff --git a/src/map.h b/src/map.h deleted file mode 100644 index 22333aa..0000000 --- a/src/map.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef MAP_H -#define MAP_H - -#include -#include -#include - -class Entity; - -class Map { - public: - Map(int id); - Map() : Map(-1) {} - Map(const Map& map); - Map(Map&& map); - ~Map(); - Map& operator= (Map other); - friend void swap(Map& first, Map& second); - - enum class MoveType { - Wall, - Wrap, - Warp, - ReverseWarp - }; - - enum class MoveDir { - Left, - Right, - Up, - Down - }; - - struct EntityData { - std::string name; - std::pair position; - std::map items; - }; - - struct Adjacent { - MoveType type = MoveType::Wall; - int map = -1; - }; - - static MoveType moveTypeForShort(std::string str); - static MoveDir moveDirForShort(std::string str); - static bool moveTypeTakesMap(MoveType type); - - int getID() const; - const int* getMapdata() const; - std::string getTitle() const; - const Adjacent& getAdjacent(MoveDir dir) const; - - void createEntities(std::list>& entities) const; - bool operator==(const Map& other) const; - bool operator!=(const Map& other) const; - - void setMapdata(int* mapdata); - void setTitle(std::string title); - void setAdjacent(MoveDir dir, MoveType type, int map); - void addEntity(EntityData& data); - private: - int* mapdata; - std::string title; - int id; - std::list entities; - std::map adjacents; -}; - -#endif diff --git a/src/world.cpp b/src/world.cpp deleted file mode 100644 index 0c61c47..0000000 --- a/src/world.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include "world.h" -#include -#include "consts.h" - -World::World(const char* filename) -{ - xmlDocPtr doc = xmlParseFile(filename); - if (doc == nullptr) - { - exit(2); - } - - xmlNodePtr top = xmlDocGetRootElement(doc); - if (top == nullptr) - { - exit(2); - } - - if (xmlStrcmp(top->name, (const xmlChar*) "world")) - { - exit(2); - } - - xmlChar* startxKey = xmlGetProp(top, (xmlChar*) "startx"); - if (startxKey == 0) exit(2); - startX = atoi((char*) startxKey); - xmlFree(startxKey); - - xmlChar* startyKey = xmlGetProp(top, (xmlChar*) "starty"); - if (startyKey == 0) exit(2); - startY = atoi((char*) startyKey); - xmlFree(startyKey); - - xmlChar* startmapKey = xmlGetProp(top, (xmlChar*) "startmap"); - if (startxKey == 0) exit(2); - startMap = atoi((char*) startmapKey); - xmlFree(startmapKey); - - for (xmlNodePtr node = top->xmlChildrenNode; node != NULL; node = node->next) - { - if (!xmlStrcmp(node->name, (const xmlChar*) "map")) - { - xmlChar* idKey = xmlGetProp(node, (xmlChar*) "id"); - if (idKey == 0) exit(2); - int theId = atoi((char*) idKey); - xmlFree(idKey); - - maps.emplace(theId, theId); - Map& map = maps[theId]; - - xmlChar* titleKey = xmlGetProp(node, (xmlChar*) "title"); - if (titleKey == 0) exit(2); - map.setTitle((char*) titleKey); - xmlFree(titleKey); - - for (xmlNodePtr mapNode = node->xmlChildrenNode; mapNode != NULL; mapNode = mapNode->next) - { - if (!xmlStrcmp(mapNode->name, (const xmlChar*) "environment")) - { - xmlChar* key = xmlNodeGetContent(mapNode); - int* mapdata = (int*) malloc(MAP_WIDTH*MAP_HEIGHT*sizeof(int)); - mapdata[0] = atoi(strtok((char*) key, ",\n")); - for (int i=1; i<(MAP_WIDTH*MAP_HEIGHT); i++) - { - mapdata[i] = atoi(strtok(NULL, ",\n")); - } - map.setMapdata(mapdata); - xmlFree(key); - } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "entity")) - { - Map::EntityData data; - - xmlChar* typeKey = xmlGetProp(mapNode, (const xmlChar*) "type"); - if (typeKey == 0) exit(2); - data.name = (char*) typeKey; - xmlFree(typeKey); - - xmlChar* xKey = xmlGetProp(mapNode, (const xmlChar*) "x"); - if (xKey == 0) exit(2); - data.position.first = atoi((char*) xKey); - xmlFree(xKey); - - xmlChar* yKey = xmlGetProp(mapNode, (const xmlChar*) "y"); - if (yKey == 0) exit(2); - data.position.second = atoi((char*) yKey); - xmlFree(yKey); - - for (xmlNodePtr entityNode = mapNode->xmlChildrenNode; entityNode != NULL; entityNode = entityNode->next) - { - if (!xmlStrcmp(entityNode->name, (xmlChar*) "item")) - { - xmlChar* itemIdKey = xmlGetProp(entityNode, (const xmlChar*) "id"); - if (itemIdKey == 0) exit(2); - std::string itemId = (char*) itemIdKey; - xmlFree(itemIdKey); - - xmlChar* itemIdVal = xmlNodeGetContent(entityNode); - if (itemIdVal == 0) exit(2); - data.items[itemId] = atoi((char*) itemIdVal); - xmlFree(itemIdVal); - } - } - - map.addEntity(data); - } else if (!xmlStrcmp(mapNode->name, (const xmlChar*) "adjacent")) - { - Map::MoveDir direction; - Map::MoveType moveType; - int mapId = 0; - - xmlChar* dirKey = xmlGetProp(mapNode, (const xmlChar*) "dir"); - if (dirKey == 0) exit(2); - direction = Map::moveDirForShort((char*) dirKey); - xmlFree(dirKey); - - xmlChar* typeKey = xmlGetProp(mapNode, (const xmlChar*) "type"); - if (typeKey == 0) exit(2); - moveType = Map::moveTypeForShort((char*) typeKey); - xmlFree(typeKey); - - xmlChar* mapIdKey = xmlGetProp(mapNode, (const xmlChar*) "map"); - if (mapIdKey != 0) - { - mapId = atoi((char*) mapIdKey); - } - xmlFree(mapIdKey); - - map.setAdjacent(direction, moveType, mapId); - } - } - } - } - - xmlFreeDoc(doc); -} - -const Map& World::getMap(int id) const -{ - return maps.at(id); -} - -const Map& World::getStartingMap() const -{ - return maps.at(startMap); -} - -std::pair World::getStartingPosition() const -{ - return std::make_pair(startX, startY); -} diff --git a/src/world.h b/src/world.h deleted file mode 100644 index f566487..0000000 --- a/src/world.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef WORLD_H -#define WORLD_H - -#include -#include "map.h" - -class World { - public: - World(const char* filename); - const Map& getMap(int id) const; - const Map& getStartingMap() const; - std::pair getStartingPosition() const; - - private: - std::map maps; - int startMap; - int startX; - int startY; -}; - -#endif /* end of include guard: WORLD_H */ -- cgit 1.4.1 From 55c8a14a7e2b2dadf0def3e09f970818164366f5 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Thu, 18 Jun 2015 12:14:05 -0400 Subject: Now displaying player character --- CMakeLists.txt | 4 + src/algorithms.h | 12 +++ src/components/sprite_renderable.cpp | 27 ++++++ src/components/sprite_renderable.h | 25 ++++++ src/components/transformable.cpp | 47 ++++++++++ src/components/transformable.h | 27 ++++++ src/entity_manager.cpp | 38 ++++++++ src/entity_manager.h | 169 +++++------------------------------ src/main.cpp | 25 +++++- src/system.h | 11 +++ src/systems/rendering.cpp | 21 +++++ src/systems/rendering.h | 16 ++++ 12 files changed, 270 insertions(+), 152 deletions(-) create mode 100644 src/algorithms.h create mode 100644 src/components/sprite_renderable.cpp create mode 100644 src/components/sprite_renderable.h create mode 100644 src/components/transformable.cpp create mode 100644 src/components/transformable.h create mode 100644 src/entity_manager.cpp create mode 100644 src/system.h create mode 100644 src/systems/rendering.cpp create mode 100644 src/systems/rendering.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dfce6f..2bfde77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,10 @@ add_executable(Aromatherapy src/main.cpp src/renderer.cpp src/muxer.cpp + src/entity_manager.cpp + src/components/sprite_renderable.cpp + src/components/transformable.cpp + src/systems/rendering.cpp ) target_link_libraries(Aromatherapy ${ALL_LIBS}) install(TARGETS Aromatherapy RUNTIME DESTINATION ${BIN_DIR}) diff --git a/src/algorithms.h b/src/algorithms.h new file mode 100644 index 0000000..80e3e27 --- /dev/null +++ b/src/algorithms.h @@ -0,0 +1,12 @@ +#ifndef ALGORITHMS_H_1DDC517E +#define ALGORITHMS_H_1DDC517E + +template< typename ContainerT, typename PredicateT > +void erase_if( ContainerT& items, const PredicateT& predicate ) { + for( auto it = items.begin(); it != items.end(); ) { + if( predicate(*it) ) it = items.erase(it); + else ++it; + } +}; + +#endif /* end of include guard: ALGORITHMS_H_1DDC517E */ diff --git a/src/components/sprite_renderable.cpp b/src/components/sprite_renderable.cpp new file mode 100644 index 0000000..4c61111 --- /dev/null +++ b/src/components/sprite_renderable.cpp @@ -0,0 +1,27 @@ +#include "sprite_renderable.h" + +SpriteRenderableComponent::SpriteRenderableComponent(const char* filename, int frame_width, int frame_height, int frames_across) + : texture(filename), frame_width(frame_width), frame_height(frame_height), frames_across(frames_across) +{ + +} + +int SpriteRenderableComponent::getFrame() const +{ + return frame; +} + +void SpriteRenderableComponent::setFrame(int frame) +{ + this->frame = frame; +} + +const Texture& SpriteRenderableComponent::getTexture() const +{ + return texture; +} + +Rectangle SpriteRenderableComponent::getFrameRect() const +{ + return {frame_width * (frame % frames_across), frame_height * (frame / frames_across), frame_width, frame_height}; +} diff --git a/src/components/sprite_renderable.h b/src/components/sprite_renderable.h new file mode 100644 index 0000000..b4465c3 --- /dev/null +++ b/src/components/sprite_renderable.h @@ -0,0 +1,25 @@ +#ifndef SPRITE_RENDERABLE_H_D3AACBBF +#define SPRITE_RENDERABLE_H_D3AACBBF + +#include "component.h" +#include "renderer.h" + +class SpriteRenderableComponent : public Component { + public: + SpriteRenderableComponent(const char* filename, int frame_width, int frame_height, int frames_across); + + int getFrame() const; + void setFrame(int frame); + + const Texture& getTexture() const; + Rectangle getFrameRect() const; + + private: + Texture texture; + int frame_width; + int frame_height; + int frames_across; + int frame = 0; +}; + +#endif /* end of include guard: SPRITE_RENDERABLE_H_D3AACBBF */ diff --git a/src/components/transformable.cpp b/src/components/transformable.cpp new file mode 100644 index 0000000..0d6b67e --- /dev/null +++ b/src/components/transformable.cpp @@ -0,0 +1,47 @@ +#include "transformable.h" + +TransformableComponent::TransformableComponent(double x, double y, int w, int h) + : x(x), y(y), w(w), h(h) +{ + +} + +double TransformableComponent::getX() const +{ + return x; +} + +double TransformableComponent::getY() const +{ + return y; +} + +int TransformableComponent::getW() const +{ + return w; +} + +int TransformableComponent::getH() const +{ + return h; +} + +void TransformableComponent::setX(double v) +{ + x = v; +} + +void TransformableComponent::setY(double v) +{ + y = v; +} + +void TransformableComponent::setW(int v) +{ + w = v; +} + +void TransformableComponent::setH(int v) +{ + h = v; +} diff --git a/src/components/transformable.h b/src/components/transformable.h new file mode 100644 index 0000000..87ba84d --- /dev/null +++ b/src/components/transformable.h @@ -0,0 +1,27 @@ +#ifndef LOCATABLE_H_39E526CA +#define LOCATABLE_H_39E526CA + +#include "component.h" + +class TransformableComponent : public Component { + public: + TransformableComponent(double x, double y, int w, int h); + + double getX() const; + double getY() const; + int getW() const; + int getH() const; + + void setX(double v); + void setY(double v); + void setW(int v); + void setH(int v); + + private: + double x; + double y; + int w; + int h; +}; + +#endif /* end of include guard: LOCATABLE_H_39E526CA */ diff --git a/src/entity_manager.cpp b/src/entity_manager.cpp new file mode 100644 index 0000000..4bdfe8a --- /dev/null +++ b/src/entity_manager.cpp @@ -0,0 +1,38 @@ +#ifndef ENTITY_MANAGER_CPP_42D78C22 +#define ENTITY_MANAGER_CPP_42D78C22 + +#include "entity_manager.h" + +template <> +std::set EntityManager::getEntitiesWithComponents<>(std::set& componentTypes) +{ + if (cachedComponents.count(componentTypes) == 1) + { + return cachedComponents[componentTypes]; + } + + std::set& cache = cachedComponents[componentTypes]; + for (auto& entity : entities) + { + EntityData& data = entity.second; + bool cacheEntity = true; + + for (auto& componentType : componentTypes) + { + if (data.components.count(componentType) == 0) + { + cacheEntity = false; + break; + } + } + + if (cacheEntity) + { + cache.insert(entity.first); + } + } + + return cache; +} + +#endif /* end of include guard: ENTITY_MANAGER_CPP_42D78C22 */ diff --git a/src/entity_manager.h b/src/entity_manager.h index 74e758c..5f0f2d4 100644 --- a/src/entity_manager.h +++ b/src/entity_manager.h @@ -6,70 +6,31 @@ #include #include #include "component.h" +#include "algorithms.h" class EntityManager { private: struct EntityData { - int parent = -1; std::map> components; }; std::map entities; - std::map> cachedChildren; std::map, std::set> cachedComponents; int nextEntityID = 0; - bool ensureNoParentCycles(int entity, int parent) + template + std::set getEntitiesWithComponentsHelper(std::set& componentTypes) { - EntityData& data = entities[parent]; - if (data.parent == entity) - { - return false; - } else if (data.parent == -1) - { - return true; - } + componentTypes.insert(typeid(T)); - return ensureNoParentCycles(entity, data.parent); + return getEntitiesWithComponents(componentTypes); } + template std::set getEntitiesWithComponents(std::set& componentTypes) { - if (cachedComponents.count(componentTypes) == 1) - { - return cachedComponents[componentTypes]; - } - - std::set& cache = cachedComponents[componentTypes]; - for (auto& entity : entities) - { - EntityData& data = entity.second; - bool cacheEntity = true; - - for (auto& componentType : componentTypes) - { - if (data.components.count(componentType) == 0) - { - cacheEntity = false; - break; - } - } - - if (cacheEntity) - { - cache.insert(entity.first); - } - } - - return cache; - } - - template std::set getEntitiesWithComponents(std::set& componentTypes) - { - componentTypes.insert(typeid(T)); - - return getEntitiesWithComponents(componentTypes); + return getEntitiesWithComponentsHelper(componentTypes); } public: @@ -107,26 +68,6 @@ class EntityManager { { assert(entities.count(entity) == 1); - EntityData& data = entities[entity]; - - // Destroy the children - std::set children = getChildren(entity); - for (int child : children) - { - EntityData& childData = entities[child]; - childData.parent = -1; - - deleteEntity(child); - } - - // Uncache children - cachedChildren.erase(entity); - - if ((data.parent != -1) && (cachedChildren.count(data.parent) == 1)) - { - cachedChildren[data.parent].erase(entity); - } - // Uncache components for (auto& cache : cachedComponents) { @@ -137,81 +78,8 @@ class EntityManager { entities.erase(entity); } - std::set getChildren(int parent) - { - assert(entities.count(parent) == 1); - - if (cachedChildren.count(parent) == 1) - { - return cachedChildren[parent]; - } - - std::set& cache = cachedChildren[parent]; - for (auto& entity : entities) - { - EntityData& data = entity.second; - if (data.parent == parent) - { - cache.insert(entity.first); - } - } - - return cache; - } - - void setParent(int entity, int parent) - { - assert(entities.count(entity) == 1); - assert(entities.count(parent) == 1); - assert(ensureNoParentCycles(entity, parent)); - - EntityData& data = entities[entity]; - - // Remove from old parent - if (data.parent != -1) - { - if (cachedChildren.count(data.parent) == 1) - { - cachedChildren[data.parent].erase(entity); - } - } - - data.parent = parent; - - // Cache new parent - if (cachedChildren.count(parent) == 1) - { - cachedChildren[parent].insert(entity); - } - } - - void setNoParent(int entity) - { - assert(entities.count(entity) == 1); - - EntityData& data = entities[entity]; - - // Remove from old parent - if (data.parent != -1) - { - if (cachedChildren.count(data.parent) == 1) - { - cachedChildren[data.parent].erase(entity); - } - } - - data.parent = -1; - } - - int getParent(int entity) - { - assert(entities.count(entity) == 1); - - EntityData& data = entities[entity]; - return data.parent; - } - - template T& emplaceComponent(int entity, Args&&... args) + template + T& emplaceComponent(int entity, Args&&... args) { assert(entities.count(entity) == 1); @@ -226,14 +94,15 @@ class EntityManager { data.components[componentType] = std::move(ptr); // Invalidate related caches - std::remove_if(begin(cachedComponents), end(cachedComponents), [&] (std::pair, int>& cache) { + erase_if(cachedComponents, [&componentType] (std::pair, std::set>& cache) { return cache.first.count(componentType) == 1; }); return component; } - template void removeComponent(int entity) + template + void removeComponent(int entity) { assert(entities.count(entity) == 1); @@ -255,7 +124,8 @@ class EntityManager { } } - template T& getComponent(int entity) + template + T& getComponent(int entity) { assert(entities.count(entity) == 1); @@ -264,16 +134,19 @@ class EntityManager { assert(data.components.count(componentType) == 1); - return *(data.components[componentType]); + return *((T*)data.components[componentType].get()); } - template std::set getEntitiesWithComponents() + template + std::set getEntitiesWithComponents() { std::set componentTypes; - componentTypes.insert(typeid(T)); - return getEntitiesWithComponents(componentTypes); + return getEntitiesWithComponentsHelper(componentTypes); } }; +template <> +std::set EntityManager::getEntitiesWithComponents<>(std::set& componentTypes); + #endif /* end of include guard: ENTITY_MANAGER_H_C5832F11 */ diff --git a/src/main.cpp b/src/main.cpp index 29a364b..dcf8d87 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,22 +4,39 @@ #include "renderer.h" #include "muxer.h" #include "entity_manager.h" +#include "components/sprite_renderable.h" +#include "components/transformable.h" +#include "systems/rendering.h" int main() { srand(time(NULL)); GLFWwindow* window = initRenderer(); + glfwSwapInterval(1); + initMuxer(); // Put this in a block so game goes out of scope before we destroy the renderer { EntityManager manager; - int eRef = manager.emplaceEntity(); - int eRef2 = manager.emplaceEntity(); - manager.setParent(eRef, eRef2); - printf("%d\n", manager.getParent(eRef)); + int player = manager.emplaceEntity(); + manager.emplaceComponent(player, "res/Starla.png", 10, 12, 6); + manager.emplaceComponent(player, 203, 44, 10, 12); + + std::list> loop; + loop.push_back(std::unique_ptr(new RenderingSystem())); + + while (!glfwWindowShouldClose(window)) + { + for (auto& sys : loop) + { + sys->tick(manager, 1.0); + } + + glfwPollEvents(); + } } destroyMuxer(); diff --git a/src/system.h b/src/system.h new file mode 100644 index 0000000..85415f0 --- /dev/null +++ b/src/system.h @@ -0,0 +1,11 @@ +#ifndef SYSTEM_H_B61A8CEA +#define SYSTEM_H_B61A8CEA + +class EntityManager; + +class System { + public: + virtual void tick(EntityManager& manager, float dt) = 0; +}; + +#endif /* end of include guard: SYSTEM_H_B61A8CEA */ diff --git a/src/systems/rendering.cpp b/src/systems/rendering.cpp new file mode 100644 index 0000000..0034dc3 --- /dev/null +++ b/src/systems/rendering.cpp @@ -0,0 +1,21 @@ +#include "rendering.h" +#include "entity_manager.h" +#include "components/sprite_renderable.h" +#include "components/transformable.h" + +void RenderingSystem::tick(EntityManager& manager, float dt) +{ + texture.fill(texture.entirety(), 0, 0, 0); + + std::set spriteEntities = manager.getEntitiesWithComponents(); + for (int entity : spriteEntities) + { + auto& sprite = manager.getComponent(entity); + auto& transform = manager.getComponent(entity); + Rectangle dstrect {(int) transform.getX(), (int) transform.getY(), transform.getW(), transform.getH()}; + + texture.blit(sprite.getTexture(), sprite.getFrameRect(), dstrect); + } + + texture.renderScreen(); +} diff --git a/src/systems/rendering.h b/src/systems/rendering.h new file mode 100644 index 0000000..80ea79e --- /dev/null +++ b/src/systems/rendering.h @@ -0,0 +1,16 @@ +#ifndef RENDERING_H_76ABC02A +#define RENDERING_H_76ABC02A + +#include "system.h" +#include "renderer.h" +#include "consts.h" + +class RenderingSystem : public System { + public: + void tick(EntityManager& manager, float dt); + + private: + Texture texture {GAME_WIDTH, GAME_HEIGHT}; +}; + +#endif /* end of include guard: RENDERING_H_76ABC02A */ -- cgit 1.4.1 From 428c401f9c1053f7e13ffe641758dfb72791d8dc Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 26 Jun 2015 19:59:28 -0400 Subject: Player now moves --- CMakeLists.txt | 8 +- src/components/animatable.cpp | 27 ++++++ src/components/animatable.h | 31 +++++++ src/components/controllable.cpp | 71 +++++++++++++++ src/components/controllable.h | 36 ++++++++ src/components/droppable.cpp | 11 +++ src/components/droppable.h | 15 ++++ src/components/ponderable.cpp | 41 +++++++++ src/components/ponderable.h | 24 +++++ src/components/sprite_renderable.cpp | 27 ------ src/components/sprite_renderable.h | 25 ------ src/consts.h | 3 + src/direction.h | 11 +++ src/game.cpp | 75 ++++++++++++++++ src/game.h | 24 +++++ src/main.cpp | 25 +----- src/system.h | 10 ++- src/system_manager.h | 37 ++++++++ src/systems/controlling.cpp | 168 +++++++++++++++++++++++++++++++++++ src/systems/controlling.h | 26 ++++++ src/systems/pondering.cpp | 23 +++++ src/systems/pondering.h | 14 +++ src/systems/rendering.cpp | 12 +-- src/systems/rendering.h | 5 +- 24 files changed, 665 insertions(+), 84 deletions(-) create mode 100644 src/components/animatable.cpp create mode 100644 src/components/animatable.h create mode 100644 src/components/controllable.cpp create mode 100644 src/components/controllable.h create mode 100644 src/components/droppable.cpp create mode 100644 src/components/droppable.h create mode 100644 src/components/ponderable.cpp create mode 100644 src/components/ponderable.h delete mode 100644 src/components/sprite_renderable.cpp delete mode 100644 src/components/sprite_renderable.h create mode 100644 src/direction.h create mode 100644 src/game.cpp create mode 100644 src/game.h create mode 100644 src/system_manager.h create mode 100644 src/systems/controlling.cpp create mode 100644 src/systems/controlling.h create mode 100644 src/systems/pondering.cpp create mode 100644 src/systems/pondering.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bfde77..9e4ac25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,9 +50,15 @@ add_executable(Aromatherapy src/renderer.cpp src/muxer.cpp src/entity_manager.cpp - src/components/sprite_renderable.cpp + src/game.cpp src/components/transformable.cpp + src/components/droppable.cpp + src/components/controllable.cpp + src/components/ponderable.cpp + src/components/animatable.cpp src/systems/rendering.cpp + src/systems/controlling.cpp + src/systems/pondering.cpp ) target_link_libraries(Aromatherapy ${ALL_LIBS}) install(TARGETS Aromatherapy RUNTIME DESTINATION ${BIN_DIR}) diff --git a/src/components/animatable.cpp b/src/components/animatable.cpp new file mode 100644 index 0000000..fcd277c --- /dev/null +++ b/src/components/animatable.cpp @@ -0,0 +1,27 @@ +#include "animatable.h" + +AnimatableComponent::AnimatableComponent(const char* filename, int frame_width, int frame_height, int frames_across) + : texture(filename), frame_width(frame_width), frame_height(frame_height), frames_across(frames_across) +{ + +} + +int AnimatableComponent::getFrame() const +{ + return frame; +} + +void AnimatableComponent::setFrame(int frame) +{ + this->frame = frame; +} + +const Texture& AnimatableComponent::getTexture() const +{ + return texture; +} + +Rectangle AnimatableComponent::getFrameRect() const +{ + return {frame_width * (frame % frames_across), frame_height * (frame / frames_across), frame_width, frame_height}; +} diff --git a/src/components/animatable.h b/src/components/animatable.h new file mode 100644 index 0000000..cf6ee54 --- /dev/null +++ b/src/components/animatable.h @@ -0,0 +1,31 @@ +#ifndef SPRITE_RENDERABLE_H_D3AACBBF +#define SPRITE_RENDERABLE_H_D3AACBBF + +#include "component.h" +#include "renderer.h" +#include "direction.h" + +class AnimatableComponent : public Component { + public: + AnimatableComponent(const char* filename, int frame_width, int frame_height, int frames_across); + + int getFrame() const; + void setFrame(int frame); + + const Texture& getTexture() const; + Rectangle getFrameRect() const; + + void setDirection(Direction dir) {}; + void setWalking(bool w) {}; + void setJumping(bool w) {}; + void setCrouching(bool w) {}; + + private: + Texture texture; + int frame_width; + int frame_height; + int frames_across; + int frame = 0; +}; + +#endif /* end of include guard: SPRITE_RENDERABLE_H_D3AACBBF */ diff --git a/src/components/controllable.cpp b/src/components/controllable.cpp new file mode 100644 index 0000000..a4d45f2 --- /dev/null +++ b/src/components/controllable.cpp @@ -0,0 +1,71 @@ +#include "controllable.h" + +int ControllableComponent::getLeftKey() const +{ + return leftKey; +} + +void ControllableComponent::setLeftKey(int k) +{ + leftKey = k; +} + +int ControllableComponent::getRightKey() const +{ + return rightKey; +} + +void ControllableComponent::setRightKey(int k) +{ + rightKey = k; +} + +int ControllableComponent::getJumpKey() const +{ + return jumpKey; +} + +void ControllableComponent::setJumpKey(int k) +{ + jumpKey = k; +} + +int ControllableComponent::getDropKey() const +{ + return dropKey; +} + +void ControllableComponent::setDropKey(int k) +{ + dropKey = k; +} + +bool ControllableComponent::isFrozen() const +{ + return frozen; +} + +void ControllableComponent::setFrozen(bool f) +{ + frozen = f; +} + +bool ControllableComponent::isHoldingLeft() const +{ + return holdingLeft; +} + +void ControllableComponent::setHoldingLeft(bool f) +{ + holdingLeft = f; +} + +bool ControllableComponent::isHoldingRight() const +{ + return holdingRight; +} + +void ControllableComponent::setHoldingRight(bool f) +{ + holdingRight = f; +} diff --git a/src/components/controllable.h b/src/components/controllable.h new file mode 100644 index 0000000..317d68d --- /dev/null +++ b/src/components/controllable.h @@ -0,0 +1,36 @@ +#ifndef CONTROLLABLE_H_4E0B85B4 +#define CONTROLLABLE_H_4E0B85B4 + +#include "component.h" +#include "renderer.h" + +class ControllableComponent : public Component { + public: + int getLeftKey() const; + void setLeftKey(int k); + int getRightKey() const; + void setRightKey(int k); + int getJumpKey() const; + void setJumpKey(int k); + int getDropKey() const; + void setDropKey(int k); + + bool isFrozen() const; + void setFrozen(bool f); + bool isHoldingLeft() const; + void setHoldingLeft(bool f); + bool isHoldingRight() const; + void setHoldingRight(bool f); + + private: + int leftKey = GLFW_KEY_LEFT; + int rightKey = GLFW_KEY_RIGHT; + int jumpKey = GLFW_KEY_UP; + int dropKey = GLFW_KEY_DOWN; + + bool frozen = false; + bool holdingLeft = false; + bool holdingRight = false; +}; + +#endif /* end of include guard: CONTROLLABLE_H_4E0B85B4 */ diff --git a/src/components/droppable.cpp b/src/components/droppable.cpp new file mode 100644 index 0000000..534fd9a --- /dev/null +++ b/src/components/droppable.cpp @@ -0,0 +1,11 @@ +#include "droppable.h" + +void DroppableComponent::setDroppable(bool can) +{ + droppable = can; +} + +bool DroppableComponent::isDroppable() const +{ + return droppable; +} diff --git a/src/components/droppable.h b/src/components/droppable.h new file mode 100644 index 0000000..1f5608b --- /dev/null +++ b/src/components/droppable.h @@ -0,0 +1,15 @@ +#ifndef DROPPABLE_H_5DB254EF +#define DROPPABLE_H_5DB254EF + +#include "component.h" + +class DroppableComponent : public Component { + public: + void setDroppable(bool can); + bool isDroppable() const; + + private: + bool droppable = false; +}; + +#endif /* end of include guard: DROPPABLE_H_5DB254EF */ diff --git a/src/components/ponderable.cpp b/src/components/ponderable.cpp new file mode 100644 index 0000000..2cfa6a6 --- /dev/null +++ b/src/components/ponderable.cpp @@ -0,0 +1,41 @@ +#include "ponderable.h" + +double PonderableComponent::getVelocityX() const +{ + return velocityX; +} + +void PonderableComponent::setVelocityX(double v) +{ + velocityX = v; +} + +double PonderableComponent::getVelocityY() const +{ + return velocityY; +} + +void PonderableComponent::setVelocityY(double v) +{ + velocityY = v; +} + +double PonderableComponent::getAccelX() const +{ + return accelX; +} + +void PonderableComponent::setAccelX(double v) +{ + accelX = v; +} + +double PonderableComponent::getAccelY() const +{ + return accelY; +} + +void PonderableComponent::setAccelY(double v) +{ + accelY = v; +} diff --git a/src/components/ponderable.h b/src/components/ponderable.h new file mode 100644 index 0000000..5aab4b3 --- /dev/null +++ b/src/components/ponderable.h @@ -0,0 +1,24 @@ +#ifndef TANGIBLE_H_746DB3EE +#define TANGIBLE_H_746DB3EE + +#include "component.h" + +class PonderableComponent : public Component { + public: + double getVelocityX() const; + void setVelocityX(double v); + double getVelocityY() const; + void setVelocityY(double v); + double getAccelX() const; + void setAccelX(double v); + double getAccelY() const; + void setAccelY(double v); + + private: + double velocityX = 0.0; + double velocityY = 0.0; + double accelX = 0.0; + double accelY = 0.0; +}; + +#endif /* end of include guard: TANGIBLE_H_746DB3EE */ diff --git a/src/components/sprite_renderable.cpp b/src/components/sprite_renderable.cpp deleted file mode 100644 index 4c61111..0000000 --- a/src/components/sprite_renderable.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "sprite_renderable.h" - -SpriteRenderableComponent::SpriteRenderableComponent(const char* filename, int frame_width, int frame_height, int frames_across) - : texture(filename), frame_width(frame_width), frame_height(frame_height), frames_across(frames_across) -{ - -} - -int SpriteRenderableComponent::getFrame() const -{ - return frame; -} - -void SpriteRenderableComponent::setFrame(int frame) -{ - this->frame = frame; -} - -const Texture& SpriteRenderableComponent::getTexture() const -{ - return texture; -} - -Rectangle SpriteRenderableComponent::getFrameRect() const -{ - return {frame_width * (frame % frames_across), frame_height * (frame / frames_across), frame_width, frame_height}; -} diff --git a/src/components/sprite_renderable.h b/src/components/sprite_renderable.h deleted file mode 100644 index b4465c3..0000000 --- a/src/components/sprite_renderable.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef SPRITE_RENDERABLE_H_D3AACBBF -#define SPRITE_RENDERABLE_H_D3AACBBF - -#include "component.h" -#include "renderer.h" - -class SpriteRenderableComponent : public Component { - public: - SpriteRenderableComponent(const char* filename, int frame_width, int frame_height, int frames_across); - - int getFrame() const; - void setFrame(int frame); - - const Texture& getTexture() const; - Rectangle getFrameRect() const; - - private: - Texture texture; - int frame_width; - int frame_height; - int frames_across; - int frame = 0; -}; - -#endif /* end of include guard: SPRITE_RENDERABLE_H_D3AACBBF */ diff --git a/src/consts.h b/src/consts.h index 804c761..4595719 100644 --- a/src/consts.h +++ b/src/consts.h @@ -11,4 +11,7 @@ const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT - 1; const int FRAMES_PER_SECOND = 60; const double SECONDS_PER_FRAME = 1.0 / FRAMES_PER_SECOND; +#define JUMP_VELOCITY(h, l) (-2 * (h) / (l)) +#define JUMP_GRAVITY(h, l) (2 * ((h) / (l)) / (l)) + #endif diff --git a/src/direction.h b/src/direction.h new file mode 100644 index 0000000..32d6b41 --- /dev/null +++ b/src/direction.h @@ -0,0 +1,11 @@ +#ifndef DIRECTION_H_9C49EAFD +#define DIRECTION_H_9C49EAFD + +enum class Direction { + Left, + Right, + Up, + Down +}; + +#endif /* end of include guard: DIRECTION_H_9C49EAFD */ diff --git a/src/game.cpp b/src/game.cpp new file mode 100644 index 0000000..b3fa9a8 --- /dev/null +++ b/src/game.cpp @@ -0,0 +1,75 @@ +#include "game.h" +#include "components/animatable.h" +#include "components/transformable.h" +#include "components/controllable.h" +#include "components/droppable.h" +#include "components/ponderable.h" +#include "systems/rendering.h" +#include "systems/controlling.h" +#include "systems/pondering.h" + +void key_callback(GLFWwindow* window, int key, int, int action, int) +{ + Game& game = *((Game*) glfwGetWindowUserPointer(window)); + + if ((action == GLFW_PRESS) && (key == GLFW_KEY_ESCAPE)) + { + game.shouldQuit = true; + + return; + } + + game.systemManager.getSystem().input(key, action); +} + +Game::Game(GLFWwindow* window) : window(window) +{ + systemManager.emplaceSystem(*this); + systemManager.emplaceSystem(*this); + systemManager.emplaceSystem(*this); + + int player = entityManager.emplaceEntity(); + entityManager.emplaceComponent(player, "res/Starla.png", 10, 12, 6); + entityManager.emplaceComponent(player, 203, 44, 10, 12); + entityManager.emplaceComponent(player); + entityManager.emplaceComponent(player); + entityManager.emplaceComponent(player); + + glfwSwapInterval(1); + glfwSetWindowUserPointer(window, this); + glfwSetKeyCallback(window, key_callback); +} + +void Game::execute() +{ + double lastTime = glfwGetTime(); + const double dt = 0.01; + double accumulator = 0.0; + + while (!(shouldQuit || glfwWindowShouldClose(window))) + { + double currentTime = glfwGetTime(); + double frameTime = currentTime - lastTime; + lastTime = currentTime; + + glfwPollEvents(); + + accumulator += frameTime; + while (accumulator >= dt) + { + systemManager.getSystem().tick(dt); + systemManager.getSystem().tick(dt); + + accumulator -= dt; + } + + systemManager.getSystem().tick(frameTime); + } +} + +EntityManager& Game::getEntityManager() +{ + return entityManager; +} + + diff --git a/src/game.h b/src/game.h new file mode 100644 index 0000000..3822700 --- /dev/null +++ b/src/game.h @@ -0,0 +1,24 @@ +#ifndef GAME_H_1014DDC9 +#define GAME_H_1014DDC9 + +#include "renderer.h" +#include "entity_manager.h" +#include "system_manager.h" + +class Game { + public: + Game(GLFWwindow* window); + + void execute(); + EntityManager& getEntityManager(); + + friend void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods); + + private: + EntityManager entityManager; + SystemManager systemManager; + GLFWwindow* const window; + bool shouldQuit = false; +}; + +#endif /* end of include guard: GAME_H_1014DDC9 */ diff --git a/src/main.cpp b/src/main.cpp index dcf8d87..35749f5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,10 +3,7 @@ #include #include "renderer.h" #include "muxer.h" -#include "entity_manager.h" -#include "components/sprite_renderable.h" -#include "components/transformable.h" -#include "systems/rendering.h" +#include "game.h" int main() { @@ -19,24 +16,8 @@ int main() // Put this in a block so game goes out of scope before we destroy the renderer { - EntityManager manager; - - int player = manager.emplaceEntity(); - manager.emplaceComponent(player, "res/Starla.png", 10, 12, 6); - manager.emplaceComponent(player, 203, 44, 10, 12); - - std::list> loop; - loop.push_back(std::unique_ptr(new RenderingSystem())); - - while (!glfwWindowShouldClose(window)) - { - for (auto& sys : loop) - { - sys->tick(manager, 1.0); - } - - glfwPollEvents(); - } + Game game {window}; + game.execute(); } destroyMuxer(); diff --git a/src/system.h b/src/system.h index 85415f0..e08db0a 100644 --- a/src/system.h +++ b/src/system.h @@ -1,11 +1,17 @@ #ifndef SYSTEM_H_B61A8CEA #define SYSTEM_H_B61A8CEA -class EntityManager; +class Game; class System { public: - virtual void tick(EntityManager& manager, float dt) = 0; + System(Game& game) + : game(game) {} + + virtual void tick(double dt) = 0; + + protected: + Game& game; }; #endif /* end of include guard: SYSTEM_H_B61A8CEA */ diff --git a/src/system_manager.h b/src/system_manager.h new file mode 100644 index 0000000..8f76db2 --- /dev/null +++ b/src/system_manager.h @@ -0,0 +1,37 @@ +#ifndef SYSTEM_MANAGER_H_544E6056 +#define SYSTEM_MANAGER_H_544E6056 + +#include +#include +#include +#include +#include "system.h" + +class SystemManager { + private: + std::list> loop; + std::map systems; + + public: + template + void emplaceSystem(Game& game, Args&&... args) + { + std::unique_ptr ptr = std::unique_ptr(new T(game, std::forward(args)...)); + std::type_index systemType = typeid(T); + + systems[systemType] = ptr.get(); + loop.push_back(std::move(ptr)); + } + + template + T& getSystem() + { + std::type_index systemType = typeid(T); + + assert(systems.count(systemType) == 1); + + return *((T*)systems[systemType]); + } +}; + +#endif /* end of include guard: SYSTEM_MANAGER_H_544E6056 */ diff --git a/src/systems/controlling.cpp b/src/systems/controlling.cpp new file mode 100644 index 0000000..b1e73ad --- /dev/null +++ b/src/systems/controlling.cpp @@ -0,0 +1,168 @@ +#include "controlling.h" +#include "game.h" +#include "components/controllable.h" +#include "components/ponderable.h" +#include "components/animatable.h" +#include "components/droppable.h" +#include "direction.h" +#include "muxer.h" +#include "consts.h" + +void ControllingSystem::tick(double dt) +{ + while (!actions.empty()) + { + int key = actions.front().first; + int action = actions.front().second; + + auto entities = game.getEntityManager().getEntitiesWithComponents(); + for (auto entity : entities) + { + auto& controllable = game.getEntityManager().getComponent(entity); + + if (action == GLFW_PRESS) + { + if (key == controllable.getLeftKey()) + { + controllable.setHoldingLeft(true); + + if (!controllable.isFrozen()) + { + walkLeft(entity); + } + } else if (key == controllable.getRightKey()) + { + controllable.setHoldingRight(true); + + if (!controllable.isFrozen()) + { + walkRight(entity); + } + } else if (key == controllable.getJumpKey()) + { + if (!controllable.isFrozen()) + { + jump(entity); + } + } else if (key == controllable.getDropKey()) + { + if (!controllable.isFrozen()) + { + drop(entity, true); + } + } + } else if (action == GLFW_RELEASE) + { + if (key == controllable.getLeftKey()) + { + controllable.setHoldingLeft(false); + + if (!controllable.isFrozen()) + { + if (controllable.isHoldingRight()) + { + walkRight(entity); + } else { + stopWalking(entity); + } + } + } else if (key == controllable.getRightKey()) + { + controllable.setHoldingRight(false); + + if (!controllable.isFrozen()) + { + if (controllable.isHoldingRight()) + { + walkLeft(entity); + } else { + stopWalking(entity); + } + } + } else if (key == controllable.getDropKey()) + { + if (!controllable.isFrozen()) + { + drop(entity, false); + } + } else if (key == controllable.getJumpKey()) + { + if (!controllable.isFrozen()) + { + stopJumping(entity); + } + } + } + } + + actions.pop(); + } +} + +void ControllingSystem::input(int key, int action) +{ + actions.push(std::make_pair(key, action)); +} + +void ControllingSystem::walkLeft(int entity) +{ + auto& ponderable = game.getEntityManager().getComponent(entity); + auto& animatable = game.getEntityManager().getComponent(entity); + + ponderable.setVelocityX(-90); + + animatable.setDirection(Direction::Left); + animatable.setWalking(true); +} + +void ControllingSystem::walkRight(int entity) +{ + auto& ponderable = game.getEntityManager().getComponent(entity); + auto& animatable = game.getEntityManager().getComponent(entity); + + ponderable.setVelocityX(90); + + animatable.setDirection(Direction::Right); + animatable.setWalking(true); +} + +void ControllingSystem::stopWalking(int entity) +{ + auto& ponderable = game.getEntityManager().getComponent(entity); + auto& animatable = game.getEntityManager().getComponent(entity); + + ponderable.setVelocityX(0); + + animatable.setWalking(false); +} + +void ControllingSystem::jump(int entity) +{ + auto& ponderable = game.getEntityManager().getComponent(entity); + auto& animatable = game.getEntityManager().getComponent(entity); + + playSound("res/Randomize87.wav", 0.25); + + ponderable.setVelocityY(JUMP_VELOCITY(TILE_HEIGHT*4.5, 0.3)); + ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*4.5, 0.3)); + + animatable.setJumping(true); +} + +void ControllingSystem::stopJumping(int entity) +{ + auto& ponderable = game.getEntityManager().getComponent(entity); + auto& animatable = game.getEntityManager().getComponent(entity); + + ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233)); + animatable.setJumping(false); +} + +void ControllingSystem::drop(int entity, bool start) +{ + auto& animatable = game.getEntityManager().getComponent(entity); + auto& droppable = game.getEntityManager().getComponent(entity); + + droppable.setDroppable(start); + animatable.setCrouching(start); +} diff --git a/src/systems/controlling.h b/src/systems/controlling.h new file mode 100644 index 0000000..61f86eb --- /dev/null +++ b/src/systems/controlling.h @@ -0,0 +1,26 @@ +#ifndef CONTROLLING_H_80B1BB8D +#define CONTROLLING_H_80B1BB8D + +#include "system.h" +#include + +class ControllingSystem : public System { + public: + ControllingSystem(Game& game) + : System(game) {} + + void tick(double dt); + void input(int key, int action); + + private: + void walkLeft(int entity); + void walkRight(int entity); + void stopWalking(int entity); + void jump(int entity); + void stopJumping(int entity); + void drop(int entity, bool start); + + std::queue> actions; +}; + +#endif /* end of include guard: CONTROLLING_H_80B1BB8D */ diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp new file mode 100644 index 0000000..96775d0 --- /dev/null +++ b/src/systems/pondering.cpp @@ -0,0 +1,23 @@ +#include "pondering.h" +#include "game.h" +#include "components/ponderable.h" +#include "components/transformable.h" + +void PonderingSystem::tick(double dt) +{ + auto entities = game.getEntityManager().getEntitiesWithComponents(); + + for (auto entity : entities) + { + auto& transformable = game.getEntityManager().getComponent(entity); + auto& ponderable = game.getEntityManager().getComponent(entity); + + // Accelerate + ponderable.setVelocityX(ponderable.getVelocityX() + ponderable.getAccelX() * dt); + ponderable.setVelocityY(ponderable.getVelocityY() + ponderable.getAccelY() * dt); + + // Move + transformable.setX(transformable.getX() + ponderable.getVelocityX() * dt); + transformable.setY(transformable.getY() + ponderable.getVelocityY() * dt); + } +} diff --git a/src/systems/pondering.h b/src/systems/pondering.h new file mode 100644 index 0000000..ad01a22 --- /dev/null +++ b/src/systems/pondering.h @@ -0,0 +1,14 @@ +#ifndef PONDERING_H_F2530E0E +#define PONDERING_H_F2530E0E + +#include "system.h" + +class PonderingSystem : public System { + public: + PonderingSystem(Game& game) + : System(game) {} + + void tick(double dt); +}; + +#endif /* end of include guard: PONDERING_H_F2530E0E */ diff --git a/src/systems/rendering.cpp b/src/systems/rendering.cpp index 0034dc3..251c2bc 100644 --- a/src/systems/rendering.cpp +++ b/src/systems/rendering.cpp @@ -1,17 +1,17 @@ #include "rendering.h" -#include "entity_manager.h" -#include "components/sprite_renderable.h" +#include "game.h" +#include "components/animatable.h" #include "components/transformable.h" -void RenderingSystem::tick(EntityManager& manager, float dt) +void RenderingSystem::tick(double dt) { texture.fill(texture.entirety(), 0, 0, 0); - std::set spriteEntities = manager.getEntitiesWithComponents(); + std::set spriteEntities = game.getEntityManager().getEntitiesWithComponents(); for (int entity : spriteEntities) { - auto& sprite = manager.getComponent(entity); - auto& transform = manager.getComponent(entity); + auto& sprite = game.getEntityManager().getComponent(entity); + auto& transform = game.getEntityManager().getComponent(entity); Rectangle dstrect {(int) transform.getX(), (int) transform.getY(), transform.getW(), transform.getH()}; texture.blit(sprite.getTexture(), sprite.getFrameRect(), dstrect); diff --git a/src/systems/rendering.h b/src/systems/rendering.h index 80ea79e..9b6e27e 100644 --- a/src/systems/rendering.h +++ b/src/systems/rendering.h @@ -7,7 +7,10 @@ class RenderingSystem : public System { public: - void tick(EntityManager& manager, float dt); + RenderingSystem(Game& game) + : System(game) {} + + void tick(double dt); private: Texture texture {GAME_WIDTH, GAME_HEIGHT}; -- cgit 1.4.1 From a855ce0262e17b85e8670c511acf179ebddd24fe Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Mon, 5 Feb 2018 11:41:48 -0500 Subject: Removed bare pointer from Sound class Also whitespace changes. --- src/muxer.cpp | 61 +++++++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/muxer.cpp b/src/muxer.cpp index d831e6d..ecce82b 100644 --- a/src/muxer.cpp +++ b/src/muxer.cpp @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include #define SAMPLE_RATE (44100) #define DELAY_IN_SECS (0.075) @@ -17,11 +20,14 @@ const int delaySize = SAMPLE_RATE * DELAY_IN_SECS; class Sound { public: Sound(const char* filename, float vol); - ~Sound(); - - float* ptr; + + inline bool isDone() const + { + return pos >= data.size(); + } + + std::vector data; unsigned long pos; - unsigned long len; float vol; }; @@ -45,29 +51,29 @@ int paMuxerCallback(const void*, void* outputBuffer, unsigned long framesPerBuff { Muxer* muxer = (Muxer*) userData; float* out = (float*) outputBuffer; - + for (unsigned long i = 0; iplaying) { - if (sound.pos < sound.len) + if (sound.pos < sound.data.size()) { - in += sound.ptr[sound.pos++] * sound.vol; + in += sound.data[sound.pos++] * sound.vol; } } - + if (in > 1) in = 1; if (in < -1) in = -1; - + float sample = muxer->delay[muxer->delayPos] * GAIN; muxer->delay[muxer->delayPos] = in + (muxer->delay[muxer->delayPos] * FEEDBACK); muxer->delayPos++; if (muxer->delayPos > delaySize) muxer->delayPos = 0; *out++ = (in * DRY) + (sample * WET); } - + return 0; } @@ -76,11 +82,11 @@ static Muxer* muxer; void initMuxer() { muxer = new Muxer(); - + dealWithPaError(Pa_Initialize()); dealWithPaError(Pa_OpenDefaultStream(&muxer->stream, 0, 1, paFloat32, SAMPLE_RATE, paFramesPerBufferUnspecified, paMuxerCallback, muxer)); dealWithPaError(Pa_StartStream(muxer->stream)); - + muxer->delay = (float*) calloc(delaySize, sizeof(float)); } @@ -89,7 +95,7 @@ void destroyMuxer() dealWithPaError(Pa_AbortStream(muxer->stream)); dealWithPaError(Pa_CloseStream(muxer->stream)); dealWithPaError(Pa_Terminate()); - + free(muxer->delay); delete muxer; muxer = 0; @@ -98,8 +104,8 @@ void destroyMuxer() void playSound(const char* filename, float vol) { // First, clear out any sounds that have finished playing - muxer->playing.remove_if([] (Sound& value) { return value.pos >= value.len; }); - + muxer->playing.remove_if([] (Sound& value) { return value.isDone(); }); + // Then, add the new sound muxer->playing.emplace_back(filename, vol); } @@ -110,21 +116,18 @@ Sound::Sound(const char* filename, float vol) SNDFILE* file = sf_open(filename, SFM_READ, &info); if (file == nullptr) { - printf("LibSndFile error: %s\n", sf_strerror(file)); - exit(-1); + std::ostringstream errmsg; + errmsg << "LibSndFile error: "; + errmsg << sf_strerror(file); + + throw std::logic_error(errmsg.str()); } - - ptr = (float*) malloc(info.frames * info.channels * sizeof(float)); - len = info.frames * info.channels; + + data.resize(info.frames * info.channels); pos = 0; this->vol = vol; - - sf_readf_float(file, ptr, info.frames); - - sf_close(file); -} -Sound::~Sound() -{ - free(ptr); + sf_readf_float(file, data.data(), info.frames); + + sf_close(file); } -- cgit 1.4.1 From da3df061699203eccc9a0c98becaee3ce8050a4f Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Mon, 5 Feb 2018 11:51:24 -0500 Subject: Whitespace changes --- src/components/controllable.h | 6 +- src/components/droppable.h | 2 +- src/components/ponderable.h | 2 +- src/components/transformable.cpp | 2 +- src/components/transformable.h | 6 +- src/entity_manager.cpp | 8 +- src/entity_manager.h | 64 +++++------ src/game.cpp | 10 +- src/game.h | 6 +- src/main.cpp | 10 +- src/renderer.cpp | 228 +++++++++++++++++++-------------------- src/renderer.h | 2 +- src/system.h | 4 +- src/system_manager.h | 8 +- src/systems/controlling.cpp | 12 +-- src/systems/controlling.h | 6 +- src/systems/pondering.cpp | 6 +- src/systems/pondering.h | 2 +- src/systems/rendering.h | 4 +- 19 files changed, 194 insertions(+), 194 deletions(-) (limited to 'src') diff --git a/src/components/controllable.h b/src/components/controllable.h index 317d68d..baccf13 100644 --- a/src/components/controllable.h +++ b/src/components/controllable.h @@ -14,20 +14,20 @@ class ControllableComponent : public Component { void setJumpKey(int k); int getDropKey() const; void setDropKey(int k); - + bool isFrozen() const; void setFrozen(bool f); bool isHoldingLeft() const; void setHoldingLeft(bool f); bool isHoldingRight() const; void setHoldingRight(bool f); - + private: int leftKey = GLFW_KEY_LEFT; int rightKey = GLFW_KEY_RIGHT; int jumpKey = GLFW_KEY_UP; int dropKey = GLFW_KEY_DOWN; - + bool frozen = false; bool holdingLeft = false; bool holdingRight = false; diff --git a/src/components/droppable.h b/src/components/droppable.h index 1f5608b..83fcb9d 100644 --- a/src/components/droppable.h +++ b/src/components/droppable.h @@ -7,7 +7,7 @@ class DroppableComponent : public Component { public: void setDroppable(bool can); bool isDroppable() const; - + private: bool droppable = false; }; diff --git a/src/components/ponderable.h b/src/components/ponderable.h index 5aab4b3..c836d2a 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -13,7 +13,7 @@ class PonderableComponent : public Component { void setAccelX(double v); double getAccelY() const; void setAccelY(double v); - + private: double velocityX = 0.0; double velocityY = 0.0; diff --git a/src/components/transformable.cpp b/src/components/transformable.cpp index 0d6b67e..89b1e5d 100644 --- a/src/components/transformable.cpp +++ b/src/components/transformable.cpp @@ -3,7 +3,7 @@ TransformableComponent::TransformableComponent(double x, double y, int w, int h) : x(x), y(y), w(w), h(h) { - + } double TransformableComponent::getX() const diff --git a/src/components/transformable.h b/src/components/transformable.h index 87ba84d..69f4f0e 100644 --- a/src/components/transformable.h +++ b/src/components/transformable.h @@ -6,17 +6,17 @@ class TransformableComponent : public Component { public: TransformableComponent(double x, double y, int w, int h); - + double getX() const; double getY() const; int getW() const; int getH() const; - + void setX(double v); void setY(double v); void setW(int v); void setH(int v); - + private: double x; double y; diff --git a/src/entity_manager.cpp b/src/entity_manager.cpp index 4bdfe8a..9ad758b 100644 --- a/src/entity_manager.cpp +++ b/src/entity_manager.cpp @@ -10,13 +10,13 @@ std::set EntityManager::getEntitiesWithComponents<>(std::set& cache = cachedComponents[componentTypes]; for (auto& entity : entities) { EntityData& data = entity.second; bool cacheEntity = true; - + for (auto& componentType : componentTypes) { if (data.components.count(componentType) == 0) @@ -25,13 +25,13 @@ std::set EntityManager::getEntitiesWithComponents<>(std::set> components; }; - + std::map entities; std::map, std::set> cachedComponents; - + int nextEntityID = 0; - + template std::set getEntitiesWithComponentsHelper(std::set& componentTypes) { componentTypes.insert(typeid(T)); - + return getEntitiesWithComponents(componentTypes); } - + template std::set getEntitiesWithComponents(std::set& componentTypes) { return getEntitiesWithComponentsHelper(componentTypes); } - + public: EntityManager() = default; EntityManager(const EntityManager& copy) = delete; - + int emplaceEntity() { // Find a suitable entity ID @@ -44,76 +44,76 @@ class EntityManager { { nextEntityID++; } - + if (nextEntityID < 0) { nextEntityID = 0; - + while ((entities.count(nextEntityID) == 1) && (nextEntityID >= 0)) { nextEntityID++; } - + assert(nextEntityID >= 0); } - + // Initialize the data int id = nextEntityID++; entities[id]; - + return id; } - + void deleteEntity(int entity) { assert(entities.count(entity) == 1); - + // Uncache components for (auto& cache : cachedComponents) { cache.second.erase(entity); } - + // Destroy the data entities.erase(entity); } - + template T& emplaceComponent(int entity, Args&&... args) { assert(entities.count(entity) == 1); - + EntityData& data = entities[entity]; std::type_index componentType = typeid(T); - + assert(data.components.count(componentType) == 0); - + // Initialize the component std::unique_ptr ptr = std::unique_ptr(new T(std::forward(args)...)); T& component = *ptr; data.components[componentType] = std::move(ptr); - + // Invalidate related caches erase_if(cachedComponents, [&componentType] (std::pair, std::set>& cache) { return cache.first.count(componentType) == 1; }); - + return component; } - + template void removeComponent(int entity) { assert(entities.count(entity) == 1); - + EntityData& data = entities[entity]; std::type_index componentType = typeid(T); - + assert(data.components.count(componentType) == 1); - + // Destroy the component data.components.erase(componentType); - + // Uncache the component for (auto& cache : cachedComponents) { @@ -123,25 +123,25 @@ class EntityManager { } } } - + template T& getComponent(int entity) { assert(entities.count(entity) == 1); - + EntityData& data = entities[entity]; std::type_index componentType = typeid(T); - + assert(data.components.count(componentType) == 1); - + return *((T*)data.components[componentType].get()); } - + template std::set getEntitiesWithComponents() { std::set componentTypes; - + return getEntitiesWithComponentsHelper(componentTypes); } }; diff --git a/src/game.cpp b/src/game.cpp index b3fa9a8..5d1ec18 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -45,24 +45,24 @@ void Game::execute() double lastTime = glfwGetTime(); const double dt = 0.01; double accumulator = 0.0; - + while (!(shouldQuit || glfwWindowShouldClose(window))) { double currentTime = glfwGetTime(); double frameTime = currentTime - lastTime; lastTime = currentTime; - + glfwPollEvents(); - + accumulator += frameTime; while (accumulator >= dt) { systemManager.getSystem().tick(dt); systemManager.getSystem().tick(dt); - + accumulator -= dt; } - + systemManager.getSystem().tick(frameTime); } } diff --git a/src/game.h b/src/game.h index 3822700..ec667c8 100644 --- a/src/game.h +++ b/src/game.h @@ -8,12 +8,12 @@ class Game { public: Game(GLFWwindow* window); - + void execute(); EntityManager& getEntityManager(); - + friend void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods); - + private: EntityManager entityManager; SystemManager systemManager; diff --git a/src/main.cpp b/src/main.cpp index 35749f5..d51da7d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,20 +8,20 @@ int main() { srand(time(NULL)); - + GLFWwindow* window = initRenderer(); glfwSwapInterval(1); - + initMuxer(); - + // Put this in a block so game goes out of scope before we destroy the renderer { Game game {window}; game.execute(); } - + destroyMuxer(); destroyRenderer(); - + return 0; } diff --git a/src/renderer.cpp b/src/renderer.cpp index 99d5389..d0d2b75 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -56,11 +56,11 @@ static GLuint mesh_normalbuffer; static int mesh_numvertices; GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path) -{ +{ // Create the shaders GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); - + // Read the Vertex Shader code from the file std::string VertexShaderCode; std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); @@ -71,7 +71,7 @@ GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path) VertexShaderCode += "\n" + Line; VertexShaderStream.close(); } - + // Read the Fragment Shader code from the file std::string FragmentShaderCode; std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); @@ -81,53 +81,53 @@ GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path) FragmentShaderCode += "\n" + Line; FragmentShaderStream.close(); } - + GLint Result = GL_FALSE; int InfoLogLength; - + // Compile Vertex Shader printf("Compiling shader : %s\n", vertex_file_path); char const * VertexSourcePointer = VertexShaderCode.c_str(); glShaderSource(VertexShaderID, 1, &VertexSourcePointer , nullptr); glCompileShader(VertexShaderID); - + // Check Vertex Shader glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); std::vector VertexShaderErrorMessage(InfoLogLength); glGetShaderInfoLog(VertexShaderID, InfoLogLength, nullptr, &VertexShaderErrorMessage[0]); fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]); - + // Compile Fragment Shader printf("Compiling shader : %s\n", fragment_file_path); char const * FragmentSourcePointer = FragmentShaderCode.c_str(); glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , nullptr); glCompileShader(FragmentShaderID); - + // Check Fragment Shader glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); std::vector FragmentShaderErrorMessage(InfoLogLength); glGetShaderInfoLog(FragmentShaderID, InfoLogLength, nullptr, &FragmentShaderErrorMessage[0]); fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]); - + // Link the program fprintf(stdout, "Linking program\n"); GLuint ProgramID = glCreateProgram(); glAttachShader(ProgramID, VertexShaderID); glAttachShader(ProgramID, FragmentShaderID); glLinkProgram(ProgramID); - + // Check the program glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); std::vector ProgramErrorMessage( glm::max(InfoLogLength, int(1)) ); glGetProgramInfoLog(ProgramID, InfoLogLength, nullptr, &ProgramErrorMessage[0]); fprintf(stdout, "%s\n", &ProgramErrorMessage[0]); - + glDeleteShader(VertexShaderID); glDeleteShader(FragmentShaderID); - + return ProgramID; } @@ -135,14 +135,14 @@ void flipImageData(unsigned char* data, int width, int height, int comps) { unsigned char* data_copy = (unsigned char*) malloc(width*height*comps*sizeof(unsigned char)); memcpy(data_copy, data, width*height*comps); - + int row_size = width * comps; - + for (int i=0;i& out_vertices, std::v fprintf(stderr, "Could not open mesh file %s\n", filename); exit(1); } - + std::vector temp_vertices; std::vector temp_uvs; std::vector temp_normals; - + for (;;) { char lineHeader[256]; @@ -167,7 +167,7 @@ void loadMesh(const char* filename, std::vector& out_vertices, std::v { break; } - + if (!strncmp(lineHeader, "v", 2)) { glm::vec3 vertex; @@ -187,7 +187,7 @@ void loadMesh(const char* filename, std::vector& out_vertices, std::v { int vertexIDs[3], uvIDs[3], normalIDs[3]; fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIDs[0], &uvIDs[0], &normalIDs[0], &vertexIDs[1], &uvIDs[1], &normalIDs[1], &vertexIDs[2], &uvIDs[2], &normalIDs[2]); - + for (int i=0; i<3; i++) { out_vertices.push_back(temp_vertices[vertexIDs[i] - 1]); @@ -202,24 +202,24 @@ void setFramebufferSize(GLFWwindow* w, int width, int height) { buffer_width = width; buffer_height = height; - + glDeleteFramebuffers(1, &bloom_framebuffer); glDeleteRenderbuffers(1, &bloom_depthbuffer); - + glGenFramebuffers(1, &bloom_framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT1}; glDrawBuffers(1, DrawBuffers); - + glGenRenderbuffers(1, &bloom_depthbuffer); glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer); - + glDeleteTextures(1, &preBloomTex); glDeleteTextures(1, &bloomPassTex1); glDeleteTextures(1, &bloomPassTex2); - + glGenTextures(1, &preBloomTex); glBindTexture(GL_TEXTURE_2D, preBloomTex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); @@ -227,7 +227,7 @@ void setFramebufferSize(GLFWwindow* w, int width, int height) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + glGenTextures(1, &bloomPassTex1); glBindTexture(GL_TEXTURE_2D, bloomPassTex1); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); @@ -235,7 +235,7 @@ void setFramebufferSize(GLFWwindow* w, int width, int height) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + glGenTextures(1, &bloomPassTex2); glBindTexture(GL_TEXTURE_2D, bloomPassTex2); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); @@ -252,20 +252,20 @@ GLFWwindow* initRenderer() fprintf(stderr, "Renderer already initialized\n"); exit(-1); } - + // Initialize GLFW if (!glfwInit()) { fprintf(stderr, "Failed to initialize GLFW\n"); exit(-1); } - + glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want version 3.3 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Mac requires this glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - + // Create a window window = glfwCreateWindow(1024, 768, "Aromatherapy", nullptr, nullptr); if (window == nullptr) @@ -274,7 +274,7 @@ GLFWwindow* initRenderer() glfwTerminate(); exit(-1); } - + glfwMakeContextCurrent(window); glewExperimental = true; // Needed in core profile if (glewInit() != GLEW_OK) @@ -282,37 +282,37 @@ GLFWwindow* initRenderer() fprintf(stderr, "Failed to initialize GLEW\n"); exit(-1); } - + glfwSetFramebufferSizeCallback(window, &setFramebufferSize); - + // Set up vertex array object glGenVertexArrays(1, &VertexArrayID); glBindVertexArray(VertexArrayID); - + // Enable depth testing glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); - + // Enable blending glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - + // Set up the framebuffer glGenFramebuffers(1, &generic_framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; glDrawBuffers(1, DrawBuffers); - + glGenFramebuffers(1, &bloom_framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); GLenum DrawBuffers2[1] = {GL_COLOR_ATTACHMENT1}; glDrawBuffers(1, DrawBuffers2); - + glGenRenderbuffers(1, &bloom_depthbuffer); glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1024, 768); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer); - + // Set up the NTSC rendering buffers glGenTextures(1, &renderedTex1); glBindTexture(GL_TEXTURE_2D, renderedTex1); @@ -322,7 +322,7 @@ GLFWwindow* initRenderer() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); renderedTexBufs[0] = renderedTex1; - + glGenTextures(1, &renderedTex2); glBindTexture(GL_TEXTURE_2D, renderedTex2); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); @@ -331,7 +331,7 @@ GLFWwindow* initRenderer() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); renderedTexBufs[1] = renderedTex2; - + // Set up bloom rendering buffers glGenTextures(1, &preBloomTex); glBindTexture(GL_TEXTURE_2D, preBloomTex); @@ -340,7 +340,7 @@ GLFWwindow* initRenderer() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + glGenTextures(1, &bloomPassTex1); glBindTexture(GL_TEXTURE_2D, bloomPassTex1); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024/4, 768/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); @@ -348,7 +348,7 @@ GLFWwindow* initRenderer() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + glGenTextures(1, &bloomPassTex2); glBindTexture(GL_TEXTURE_2D, bloomPassTex2); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024/4, 768/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); @@ -356,31 +356,31 @@ GLFWwindow* initRenderer() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + curBuf = 0; - + // Load the mesh! std::vector mesh_vertices; std::vector mesh_uvs; std::vector mesh_normals; loadMesh("res/monitor-fef.obj", mesh_vertices, mesh_uvs, mesh_normals); - + mesh_numvertices = mesh_vertices.size(); - + glGenBuffers(1, &mesh_vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer); glBufferData(GL_ARRAY_BUFFER, mesh_vertices.size() * sizeof(glm::vec3), &mesh_vertices[0], GL_STATIC_DRAW); - + glGenBuffers(1, &mesh_uvbuffer); glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer); glBufferData(GL_ARRAY_BUFFER, mesh_uvs.size() * sizeof(glm::vec3), &mesh_uvs[0], GL_STATIC_DRAW); - + glGenBuffers(1, &mesh_normalbuffer); glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer); glBufferData(GL_ARRAY_BUFFER, mesh_normals.size() * sizeof(glm::vec3), &mesh_normals[0], GL_STATIC_DRAW); - + // Load the vertices of a flat surface - GLfloat g_quad_vertex_buffer_data[] = { + GLfloat g_quad_vertex_buffer_data[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, @@ -392,7 +392,7 @@ GLFWwindow* initRenderer() glGenBuffers(1, &quad_vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW); - + glGenTextures(1, &artifactsTex); glBindTexture(GL_TEXTURE_2D, artifactsTex); int atdw, atdh; @@ -403,7 +403,7 @@ GLFWwindow* initRenderer() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); glGenerateMipmap(GL_TEXTURE_2D); - + glGenTextures(1, &scanlinesTex); glBindTexture(GL_TEXTURE_2D, scanlinesTex); int stdw, stdh; @@ -414,7 +414,7 @@ GLFWwindow* initRenderer() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); glGenerateMipmap(GL_TEXTURE_2D); - + // Load the shaders ntscShader = LoadShaders("shaders/ntsc.vertex", "shaders/ntsc.fragment"); finalShader = LoadShaders("shaders/final.vertex", "shaders/final.fragment"); @@ -422,9 +422,9 @@ GLFWwindow* initRenderer() fillShader = LoadShaders("shaders/fill.vertex", "shaders/fill.fragment"); bloom1Shader = LoadShaders("shaders/bloom1.vertex", "shaders/bloom1.fragment"); bloom2Shader = LoadShaders("shaders/bloom2.vertex", "shaders/bloom2.fragment"); - + rendererInitialized = true; - + return window; } @@ -435,13 +435,13 @@ void destroyRenderer() fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + // Delete the plane buffer glDeleteBuffers(1, &quad_vertexbuffer); glDeleteBuffers(1, &mesh_vertexbuffer); glDeleteBuffers(1, &mesh_uvbuffer); glDeleteBuffers(1, &mesh_normalbuffer); - + // Delete the shaders glDeleteProgram(ntscShader); glDeleteProgram(finalShader); @@ -449,7 +449,7 @@ void destroyRenderer() glDeleteProgram(fillShader); glDeleteProgram(bloom1Shader); glDeleteProgram(bloom2Shader); - + // Delete the NTSC rendering buffers glDeleteTextures(1, &renderedTex1); glDeleteTextures(1, &renderedTex2); @@ -458,18 +458,18 @@ void destroyRenderer() glDeleteTextures(1, &preBloomTex); glDeleteTextures(1, &bloomPassTex1); glDeleteTextures(1, &bloomPassTex2); - + // Delete the framebuffer glDeleteRenderbuffers(1, &bloom_depthbuffer); glDeleteFramebuffers(1, &bloom_framebuffer); glDeleteFramebuffers(1, &generic_framebuffer); - + // Delete the VAO glDeleteVertexArrays(1, &VertexArrayID); - + // Kill the window glfwTerminate(); - + rendererInitialized = false; } @@ -480,10 +480,10 @@ Texture::Texture(int width, int height) fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + this->width = width; this->height = height; - + glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); @@ -500,7 +500,7 @@ Texture::Texture(const char* filename) fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); unsigned char* data = stbi_load(filename, &width, &height, 0, 4); @@ -520,14 +520,14 @@ Texture::Texture(const Texture& tex) fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + width = tex.width; height = tex.height; - + unsigned char* data = (unsigned char*) malloc(4 * width * height); glBindTexture(GL_TEXTURE_2D, tex.texID); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - + glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); @@ -535,7 +535,7 @@ Texture::Texture(const Texture& tex) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - + free(data); } @@ -551,14 +551,14 @@ Texture::~Texture() fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + glDeleteTextures(1, &texID); } Texture& Texture::operator= (Texture tex) { swap(*this, tex); - + return *this; } @@ -576,17 +576,17 @@ void Texture::fill(Rectangle dstrect, int r, int g, int b) fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + // Target the framebuffer glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0); - + // Set up the vertex attributes GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); - + GLfloat vertexbuffer_data[] = { minx, miny, maxx, miny, @@ -601,14 +601,14 @@ void Texture::fill(Rectangle dstrect, int r, int g, int b) glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - + glViewport(0, 0, width, height); glClear(GL_DEPTH_BUFFER_BIT); glUseProgram(fillShader); glUniform3f(glGetUniformLocation(fillShader, "vecColor"), r / 255.0, g / 255.0, b / 255.0); - + glDrawArrays(GL_TRIANGLES, 0, 6); - + glDisableVertexAttribArray(0); glDeleteBuffers(1, &vertexbuffer); } @@ -620,19 +620,19 @@ void Texture::blit(const Texture& srctex, Rectangle srcrect, Rectangle dstrect, fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + alpha = glm::clamp(alpha, 0.0, 1.0); - + // Target the framebuffer glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0); - + // Set up the vertex attributes GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); - + GLfloat vertexbuffer_data[] = { minx, miny, maxx, miny, @@ -645,12 +645,12 @@ void Texture::blit(const Texture& srctex, Rectangle srcrect, Rectangle dstrect, glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - + GLfloat minu = (GLfloat) srcrect.x / srctex.width; GLfloat minv = 1 - ((GLfloat) srcrect.y / srctex.height); GLfloat maxu = (GLfloat) (srcrect.x + srcrect.w) / srctex.width; GLfloat maxv = 1 - ((GLfloat) (srcrect.y + srcrect.h) / srctex.height); - + GLfloat texcoordbuffer_data[] = { minu, minv, maxu, minv, @@ -663,20 +663,20 @@ void Texture::blit(const Texture& srctex, Rectangle srcrect, Rectangle dstrect, glBufferData(GL_ARRAY_BUFFER, sizeof(texcoordbuffer_data), texcoordbuffer_data, GL_STATIC_DRAW); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - + // Set up the shader glUseProgram(blitShader); glClear(GL_DEPTH_BUFFER_BIT); glViewport(0, 0, width, height); - + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, srctex.texID); glUniform1i(glGetUniformLocation(blitShader, "srctex"), 0); glUniform1f(glGetUniformLocation(blitShader, "alpha"), alpha); - + // Blit! glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - + // Unload everything glDisableVertexAttribArray(1); glDisableVertexAttribArray(0); @@ -691,11 +691,11 @@ void bloomPass1(GLuint srcTex, GLuint dstTex, bool horizontal, glm::vec2 srcRes, glViewport(0,0,dstRes.x,dstRes.y); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(bloom1Shader); - + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, srcTex); glUniform1i(glGetUniformLocation(bloom1Shader, "inTex"), 0); - + glm::vec2 offset = glm::vec2(0.0); if (horizontal) { @@ -703,9 +703,9 @@ void bloomPass1(GLuint srcTex, GLuint dstTex, bool horizontal, glm::vec2 srcRes, } else { offset.y = 1.2/srcRes.y; } - + glUniform2f(glGetUniformLocation(bloom1Shader, "offset"), offset.x, offset.y); - + glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); @@ -720,17 +720,17 @@ void Texture::renderScreen() const fprintf(stderr, "Renderer not initialized\n"); exit(-1); } - + // First we're going to composite our frame with the previous frame // We start by setting up the framebuffer glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexBufs[curBuf], 0); - + // Set up the shader glViewport(0,0,GAME_WIDTH,GAME_HEIGHT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(ntscShader); - + // Use the current frame texture, nearest neighbor and clamped to edge glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texID); @@ -739,7 +739,7 @@ void Texture::renderScreen() const glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glUniform1i(glGetUniformLocation(ntscShader, "curFrameSampler"), 0); - + // Use the previous frame composite texture, nearest neighbor and clamped to edge glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, renderedTexBufs[(curBuf + 1) % 2]); @@ -748,13 +748,13 @@ void Texture::renderScreen() const glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glUniform1i(glGetUniformLocation(ntscShader, "prevFrameSampler"), 1); - + // Load the NTSC artifact texture glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, artifactsTex); glUniform1i(glGetUniformLocation(ntscShader, "NTSCArtifactSampler"), 2); glUniform1f(glGetUniformLocation(ntscShader, "NTSCLerp"), curBuf * 1.0); - + if ((rand() % 60) == 0) { // Change the 0.0 to a 1.0 or a 10.0 for a glitchy effect! @@ -762,7 +762,7 @@ void Texture::renderScreen() const } else { glUniform1f(glGetUniformLocation(ntscShader, "Tuning_NTSC"), 0.0); } - + // Render our composition glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); @@ -776,7 +776,7 @@ void Texture::renderScreen() const glViewport(0,0,buffer_width,buffer_height); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(finalShader); - + // Use the composited frame texture, linearly filtered and filling in black for the border glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, renderedTexBufs[curBuf]); @@ -788,69 +788,69 @@ void Texture::renderScreen() const glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); glGenerateMipmap(GL_TEXTURE_2D); glUniform1i(glGetUniformLocation(finalShader, "rendertex"), 0); - + // Use the scanlines texture glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, scanlinesTex); glUniform1i(glGetUniformLocation(finalShader, "scanlinestex"), 1); - + // Initialize the MVP matrices glm::mat4 p_matrix = glm::perspective(42.5f, (float) buffer_width / (float) buffer_height, 0.1f, 100.0f); glm::mat4 v_matrix = glm::lookAt(glm::vec3(2,0,0), glm::vec3(0,0,0), glm::vec3(0,1,0)); glm::mat4 m_matrix = glm::mat4(1.0); glm::mat4 mvp_matrix = p_matrix * v_matrix * m_matrix; - + glUniformMatrix4fv(glGetUniformLocation(finalShader, "MVP"), 1, GL_FALSE, &mvp_matrix[0][0]); glUniformMatrix4fv(glGetUniformLocation(finalShader, "worldMat"), 1, GL_FALSE, &m_matrix[0][0]); glUniform2f(glGetUniformLocation(finalShader, "resolution"), buffer_width, buffer_height); glUniform1f(glGetUniformLocation(finalShader, "iGlobalTime"), glfwGetTime()); - + glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - + glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - + glEnableVertexAttribArray(2); glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - + glDrawArrays(GL_TRIANGLES, 0, mesh_numvertices); glDisableVertexAttribArray(2); glDisableVertexAttribArray(1); glDisableVertexAttribArray(0); - + // First pass of bloom! glm::vec2 buffer_size = glm::vec2(buffer_width, buffer_height); bloomPass1(preBloomTex, bloomPassTex1, true, buffer_size, buffer_size / 4.0f); bloomPass1(bloomPassTex1, bloomPassTex2, false, buffer_size / 4.0f, buffer_size / 4.0f); - + // Do the second pass of bloom and render to screen glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, 0, buffer_width, buffer_height); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(bloom2Shader); - + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, preBloomTex); glUniform1i(glGetUniformLocation(bloom2Shader, "clearTex"), 0); - + glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, bloomPassTex2); glUniform1i(glGetUniformLocation(bloom2Shader, "blurTex"), 1); - + glUniform1f(glGetUniformLocation(bloom2Shader, "iGlobalTime"), glfwGetTime()); - + glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); glDrawArrays(GL_TRIANGLES, 0, 6); glDisableVertexAttribArray(0); - + glfwSwapBuffers(window); - + curBuf = (curBuf + 1) % 2; } diff --git a/src/renderer.h b/src/renderer.h index 84ad688..6dccf7a 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -24,7 +24,7 @@ class Texture { void blit(const Texture& src, Rectangle srcrect, Rectangle dstrect, double alpha = 1.0); void renderScreen() const; Rectangle entirety() const; - + private: GLuint texID; int width; diff --git a/src/system.h b/src/system.h index e08db0a..af3fb77 100644 --- a/src/system.h +++ b/src/system.h @@ -7,9 +7,9 @@ class System { public: System(Game& game) : game(game) {} - + virtual void tick(double dt) = 0; - + protected: Game& game; }; diff --git a/src/system_manager.h b/src/system_manager.h index 8f76db2..087b71c 100644 --- a/src/system_manager.h +++ b/src/system_manager.h @@ -18,18 +18,18 @@ class SystemManager { { std::unique_ptr ptr = std::unique_ptr(new T(game, std::forward(args)...)); std::type_index systemType = typeid(T); - + systems[systemType] = ptr.get(); loop.push_back(std::move(ptr)); } - + template T& getSystem() { std::type_index systemType = typeid(T); - + assert(systems.count(systemType) == 1); - + return *((T*)systems[systemType]); } }; diff --git a/src/systems/controlling.cpp b/src/systems/controlling.cpp index b1e73ad..456da3b 100644 --- a/src/systems/controlling.cpp +++ b/src/systems/controlling.cpp @@ -14,12 +14,12 @@ void ControllingSystem::tick(double dt) { int key = actions.front().first; int action = actions.front().second; - + auto entities = game.getEntityManager().getEntitiesWithComponents(); for (auto entity : entities) { auto& controllable = game.getEntityManager().getComponent(entity); - + if (action == GLFW_PRESS) { if (key == controllable.getLeftKey()) @@ -33,7 +33,7 @@ void ControllingSystem::tick(double dt) } else if (key == controllable.getRightKey()) { controllable.setHoldingRight(true); - + if (!controllable.isFrozen()) { walkRight(entity); @@ -56,7 +56,7 @@ void ControllingSystem::tick(double dt) if (key == controllable.getLeftKey()) { controllable.setHoldingLeft(false); - + if (!controllable.isFrozen()) { if (controllable.isHoldingRight()) @@ -69,7 +69,7 @@ void ControllingSystem::tick(double dt) } else if (key == controllable.getRightKey()) { controllable.setHoldingRight(false); - + if (!controllable.isFrozen()) { if (controllable.isHoldingRight()) @@ -94,7 +94,7 @@ void ControllingSystem::tick(double dt) } } } - + actions.pop(); } } diff --git a/src/systems/controlling.h b/src/systems/controlling.h index 61f86eb..30210b3 100644 --- a/src/systems/controlling.h +++ b/src/systems/controlling.h @@ -8,10 +8,10 @@ class ControllingSystem : public System { public: ControllingSystem(Game& game) : System(game) {} - + void tick(double dt); void input(int key, int action); - + private: void walkLeft(int entity); void walkRight(int entity); @@ -19,7 +19,7 @@ class ControllingSystem : public System { void jump(int entity); void stopJumping(int entity); void drop(int entity, bool start); - + std::queue> actions; }; diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 96775d0..50a8bc8 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -6,16 +6,16 @@ void PonderingSystem::tick(double dt) { auto entities = game.getEntityManager().getEntitiesWithComponents(); - + for (auto entity : entities) { auto& transformable = game.getEntityManager().getComponent(entity); auto& ponderable = game.getEntityManager().getComponent(entity); - + // Accelerate ponderable.setVelocityX(ponderable.getVelocityX() + ponderable.getAccelX() * dt); ponderable.setVelocityY(ponderable.getVelocityY() + ponderable.getAccelY() * dt); - + // Move transformable.setX(transformable.getX() + ponderable.getVelocityX() * dt); transformable.setY(transformable.getY() + ponderable.getVelocityY() * dt); diff --git a/src/systems/pondering.h b/src/systems/pondering.h index ad01a22..3fe5473 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -7,7 +7,7 @@ class PonderingSystem : public System { public: PonderingSystem(Game& game) : System(game) {} - + void tick(double dt); }; diff --git a/src/systems/rendering.h b/src/systems/rendering.h index 9b6e27e..cec72e2 100644 --- a/src/systems/rendering.h +++ b/src/systems/rendering.h @@ -9,9 +9,9 @@ class RenderingSystem : public System { public: RenderingSystem(Game& game) : System(game) {} - + void tick(double dt); - + private: Texture texture {GAME_WIDTH, GAME_HEIGHT}; }; -- cgit 1.4.1 From 97d7fb425da906947cc45e11fadb35f708da50d6 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Wed, 7 Feb 2018 14:13:32 -0500 Subject: Changed EntityManager to dense vector This should improve speed, because entity lookup will be O(1) instead of O(log n). Deletion is also O(1). Insert stays at potentially O(n), but still should be overall faster than the previous method. Also replaced some asserts with exceptions. Also made Component polymorphic so that deletion actually works properly. --- src/component.h | 4 + src/entity_manager.cpp | 11 +-- src/entity_manager.h | 235 +++++++++++++++++++++++++++++-------------------- src/system.h | 15 ++-- src/system_manager.h | 43 +++++---- 5 files changed, 184 insertions(+), 124 deletions(-) (limited to 'src') diff --git a/src/component.h b/src/component.h index 2cbdc9d..b81dbee 100644 --- a/src/component.h +++ b/src/component.h @@ -2,6 +2,10 @@ #define COMPONENT_H_F0CE4573 class Component { +public: + + virtual ~Component() = default; + }; #endif /* end of include guard: COMPONENT_H_F0CE4573 */ diff --git a/src/entity_manager.cpp b/src/entity_manager.cpp index 9ad758b..f792e17 100644 --- a/src/entity_manager.cpp +++ b/src/entity_manager.cpp @@ -4,17 +4,18 @@ #include "entity_manager.h" template <> -std::set EntityManager::getEntitiesWithComponents<>(std::set& componentTypes) +std::set EntityManager::getEntitiesWithComponents<>( + std::set& componentTypes) { if (cachedComponents.count(componentTypes) == 1) { return cachedComponents[componentTypes]; } - std::set& cache = cachedComponents[componentTypes]; - for (auto& entity : entities) + std::set& cache = cachedComponents[componentTypes]; + for (id_type entity = 0; entity < entities.size(); entity++) { - EntityData& data = entity.second; + EntityData& data = entities[entity]; bool cacheEntity = true; for (auto& componentType : componentTypes) @@ -28,7 +29,7 @@ std::set EntityManager::getEntitiesWithComponents<>(std::set +#include #include #include -#include +#include #include "component.h" #include "algorithms.h" class EntityManager { - private: - struct EntityData { - std::map> components; - }; +private: - std::map entities; - std::map, std::set> cachedComponents; + struct EntityData { + std::map> components; + }; - int nextEntityID = 0; + using database_type = std::vector; - template - std::set getEntitiesWithComponentsHelper(std::set& componentTypes) - { - componentTypes.insert(typeid(T)); +public: - return getEntitiesWithComponents(componentTypes); - } + using id_type = database_type::size_type; - template - std::set getEntitiesWithComponents(std::set& componentTypes) - { - return getEntitiesWithComponentsHelper(componentTypes); - } +private: - public: - EntityManager() = default; - EntityManager(const EntityManager& copy) = delete; + database_type entities; + std::vector slotAvailable; + std::map, std::set> cachedComponents; - int emplaceEntity() - { - // Find a suitable entity ID - while ((entities.count(nextEntityID) == 1) && (nextEntityID >= 0)) - { - nextEntityID++; - } + id_type nextEntityID = 0; - if (nextEntityID < 0) - { - nextEntityID = 0; + template + std::set getEntitiesWithComponentsHelper( + std::set& componentTypes) + { + componentTypes.insert(typeid(T)); - while ((entities.count(nextEntityID) == 1) && (nextEntityID >= 0)) - { - nextEntityID++; - } + return getEntitiesWithComponents(componentTypes); + } - assert(nextEntityID >= 0); - } + template + std::set getEntitiesWithComponents( + std::set& componentTypes) + { + return getEntitiesWithComponentsHelper(componentTypes); + } - // Initialize the data - int id = nextEntityID++; - entities[id]; +public: - return id; - } + EntityManager() = default; - void deleteEntity(int entity) - { - assert(entities.count(entity) == 1); + EntityManager(const EntityManager& copy) = delete; - // Uncache components - for (auto& cache : cachedComponents) + id_type emplaceEntity() + { + if (nextEntityID >= entities.size()) + { + // If the database is saturated, add a new element for the new entity. + entities.emplace_back(); + slotAvailable.push_back(false); + + return nextEntityID++; + } else { + // If there is an available slot in the database, use it. + id_type id = nextEntityID++; + slotAvailable[id] = false; + + // Fast forward the next available slot pointer to an available slot. + while ((nextEntityID < entities.size()) && !slotAvailable[nextEntityID]) { - cache.second.erase(entity); + nextEntityID++; } - // Destroy the data - entities.erase(entity); + return id; + } + } + + void deleteEntity(id_type entity) + { + if ((entity >= entities.size()) || slotAvailable[entity]) + { + throw std::invalid_argument("Cannot delete non-existent entity"); } - template - T& emplaceComponent(int entity, Args&&... args) + // Uncache components + for (auto& cache : cachedComponents) { - assert(entities.count(entity) == 1); + cache.second.erase(entity); + } + + // Destroy the data + entities[entity].components.clear(); - EntityData& data = entities[entity]; - std::type_index componentType = typeid(T); + // Mark the slot as available + slotAvailable[entity] = true; - assert(data.components.count(componentType) == 0); + if (entity < nextEntityID) + { + nextEntityID = entity; + } + } - // Initialize the component - std::unique_ptr ptr = std::unique_ptr(new T(std::forward(args)...)); - T& component = *ptr; - data.components[componentType] = std::move(ptr); + template + T& emplaceComponent(id_type entity, Args&&... args) + { + if ((entity >= entities.size()) || slotAvailable[entity]) + { + throw std::invalid_argument("Cannot delete non-existent entity"); + } - // Invalidate related caches - erase_if(cachedComponents, [&componentType] (std::pair, std::set>& cache) { - return cache.first.count(componentType) == 1; - }); + EntityData& data = entities[entity]; + std::type_index componentType = typeid(T); - return component; + if (data.components.count(componentType)) + { + throw std::invalid_argument("Cannot emplace already-existent component"); } - template - void removeComponent(int entity) + // Initialize the component + std::unique_ptr ptr(new T(std::forward(args)...)); + T& component = *ptr; + data.components[componentType] = std::move(ptr); + + // Invalidate related caches + erase_if( + cachedComponents, + [&componentType] ( + std::pair, std::set>& cache) { + return cache.first.count(componentType) == 1; + }); + + return component; + } + + template + void removeComponent(id_type entity) + { + if ((entity >= entities.size()) || slotAvailable[entity]) { - assert(entities.count(entity) == 1); + throw std::invalid_argument("Cannot delete non-existent entity"); + } - EntityData& data = entities[entity]; - std::type_index componentType = typeid(T); + EntityData& data = entities[entity]; + std::type_index componentType = typeid(T); - assert(data.components.count(componentType) == 1); + if (!data.components.count(componentType)) + { + throw std::invalid_argument("Cannot delete non-existent component"); + } - // Destroy the component - data.components.erase(componentType); + // Destroy the component + data.components.erase(componentType); - // Uncache the component - for (auto& cache : cachedComponents) + // Uncache the component + for (auto& cache : cachedComponents) + { + if (cache.first.count(componentType) == 1) { - if (cache.first.count(componentType) == 1) - { - cache.second.erase(entity); - } + cache.second.erase(entity); } } + } - template - T& getComponent(int entity) + template + T& getComponent(id_type entity) + { + if ((entity >= entities.size()) || slotAvailable[entity]) { - assert(entities.count(entity) == 1); - - EntityData& data = entities[entity]; - std::type_index componentType = typeid(T); + throw std::invalid_argument("Cannot delete non-existent entity"); + } - assert(data.components.count(componentType) == 1); + EntityData& data = entities[entity]; + std::type_index componentType = typeid(T); - return *((T*)data.components[componentType].get()); + if (!data.components.count(componentType)) + { + throw std::invalid_argument("Cannot get non-existent component"); } - template - std::set getEntitiesWithComponents() - { - std::set componentTypes; + return *dynamic_cast(data.components[componentType].get()); + } - return getEntitiesWithComponentsHelper(componentTypes); - } + template + std::set getEntitiesWithComponents() + { + std::set componentTypes; + + return getEntitiesWithComponentsHelper(componentTypes); + } }; template <> -std::set EntityManager::getEntitiesWithComponents<>(std::set& componentTypes); +std::set EntityManager::getEntitiesWithComponents<>( + std::set& componentTypes); #endif /* end of include guard: ENTITY_MANAGER_H_C5832F11 */ diff --git a/src/system.h b/src/system.h index af3fb77..489afd0 100644 --- a/src/system.h +++ b/src/system.h @@ -4,14 +4,17 @@ class Game; class System { - public: - System(Game& game) - : game(game) {} +public: + System(Game& game) + : game(game) {} - virtual void tick(double dt) = 0; + virtual ~System() = default; - protected: - Game& game; + virtual void tick(double dt) = 0; + +protected: + + Game& game; }; #endif /* end of include guard: SYSTEM_H_B61A8CEA */ diff --git a/src/system_manager.h b/src/system_manager.h index 087b71c..e2c98cb 100644 --- a/src/system_manager.h +++ b/src/system_manager.h @@ -5,33 +5,40 @@ #include #include #include +#include #include "system.h" class SystemManager { - private: - std::list> loop; - std::map systems; +private: - public: - template - void emplaceSystem(Game& game, Args&&... args) - { - std::unique_ptr ptr = std::unique_ptr(new T(game, std::forward(args)...)); - std::type_index systemType = typeid(T); + std::list> loop; + std::map systems; - systems[systemType] = ptr.get(); - loop.push_back(std::move(ptr)); - } +public: - template - T& getSystem() - { - std::type_index systemType = typeid(T); + template + void emplaceSystem(Game& game, Args&&... args) + { + std::unique_ptr ptr(new T(game, std::forward(args)...)); + std::type_index systemType = typeid(T); + + systems[systemType] = ptr.get(); + loop.push_back(std::move(ptr)); + } - assert(systems.count(systemType) == 1); + template + T& getSystem() + { + std::type_index systemType = typeid(T); - return *((T*)systems[systemType]); + if (!systems.count(systemType)) + { + throw std::invalid_argument("Cannot get non-existent system"); } + + return *dynamic_cast(systems[systemType]); + } + }; #endif /* end of include guard: SYSTEM_MANAGER_H_544E6056 */ -- cgit 1.4.1 From f9448d36db7c076f5091f70b7921dceddf63fdf9 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Wed, 7 Feb 2018 15:18:48 -0500 Subject: Inlined some components --- CMakeLists.txt | 5 +- src/components/controllable.cpp | 71 ------------------------- src/components/controllable.h | 108 +++++++++++++++++++++++++++++---------- src/components/droppable.cpp | 11 ---- src/components/droppable.h | 19 +++++-- src/components/ponderable.cpp | 41 --------------- src/components/ponderable.h | 68 ++++++++++++++++++------ src/components/transformable.cpp | 47 ----------------- src/components/transformable.h | 78 +++++++++++++++++++++------- 9 files changed, 210 insertions(+), 238 deletions(-) delete mode 100644 src/components/controllable.cpp delete mode 100644 src/components/droppable.cpp delete mode 100644 src/components/ponderable.cpp delete mode 100644 src/components/transformable.cpp (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 12d2551..e43b056 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,10 +60,7 @@ add_executable(Aromatherapy src/muxer.cpp src/entity_manager.cpp src/game.cpp - src/components/transformable.cpp - src/components/droppable.cpp - src/components/controllable.cpp - src/components/ponderable.cpp + src/animation.cpp src/components/animatable.cpp src/systems/rendering.cpp src/systems/controlling.cpp diff --git a/src/components/controllable.cpp b/src/components/controllable.cpp deleted file mode 100644 index a4d45f2..0000000 --- a/src/components/controllable.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "controllable.h" - -int ControllableComponent::getLeftKey() const -{ - return leftKey; -} - -void ControllableComponent::setLeftKey(int k) -{ - leftKey = k; -} - -int ControllableComponent::getRightKey() const -{ - return rightKey; -} - -void ControllableComponent::setRightKey(int k) -{ - rightKey = k; -} - -int ControllableComponent::getJumpKey() const -{ - return jumpKey; -} - -void ControllableComponent::setJumpKey(int k) -{ - jumpKey = k; -} - -int ControllableComponent::getDropKey() const -{ - return dropKey; -} - -void ControllableComponent::setDropKey(int k) -{ - dropKey = k; -} - -bool ControllableComponent::isFrozen() const -{ - return frozen; -} - -void ControllableComponent::setFrozen(bool f) -{ - frozen = f; -} - -bool ControllableComponent::isHoldingLeft() const -{ - return holdingLeft; -} - -void ControllableComponent::setHoldingLeft(bool f) -{ - holdingLeft = f; -} - -bool ControllableComponent::isHoldingRight() const -{ - return holdingRight; -} - -void ControllableComponent::setHoldingRight(bool f) -{ - holdingRight = f; -} diff --git a/src/components/controllable.h b/src/components/controllable.h index baccf13..fa78c8b 100644 --- a/src/components/controllable.h +++ b/src/components/controllable.h @@ -5,32 +5,88 @@ #include "renderer.h" class ControllableComponent : public Component { - public: - int getLeftKey() const; - void setLeftKey(int k); - int getRightKey() const; - void setRightKey(int k); - int getJumpKey() const; - void setJumpKey(int k); - int getDropKey() const; - void setDropKey(int k); - - bool isFrozen() const; - void setFrozen(bool f); - bool isHoldingLeft() const; - void setHoldingLeft(bool f); - bool isHoldingRight() const; - void setHoldingRight(bool f); - - private: - int leftKey = GLFW_KEY_LEFT; - int rightKey = GLFW_KEY_RIGHT; - int jumpKey = GLFW_KEY_UP; - int dropKey = GLFW_KEY_DOWN; - - bool frozen = false; - bool holdingLeft = false; - bool holdingRight = false; +public: + + inline int getLeftKey() const + { + return leftKey_; + } + + inline void setLeftKey(int k) + { + leftKey_ = k; + } + + inline int getRightKey() const + { + return rightKey_; + } + + inline void setRightKey(int k) + { + rightKey_ = k; + } + + inline int getJumpKey() const + { + return jumpKey_; + } + + inline void setJumpKey(int k) + { + jumpKey_ = k; + } + + inline int getDropKey() const + { + return dropKey_; + } + + inline void setDropKey(int k) + { + dropKey_ = k; + } + + inline bool isFrozen() const + { + return frozen_; + } + + inline void setFrozen(bool f) + { + frozen_ = f; + } + + inline bool isHoldingLeft() const + { + return holdingLeft_; + } + + inline void setHoldingLeft(bool f) + { + holdingLeft_ = f; + } + + inline bool isHoldingRight() const + { + return holdingRight_; + } + + inline void setHoldingRight(bool f) + { + holdingRight_ = f; + } + +private: + + int leftKey_ = GLFW_KEY_LEFT; + int rightKey_ = GLFW_KEY_RIGHT; + int jumpKey_ = GLFW_KEY_UP; + int dropKey_ = GLFW_KEY_DOWN; + + bool frozen_ = false; + bool holdingLeft_ = false; + bool holdingRight_ = false; }; #endif /* end of include guard: CONTROLLABLE_H_4E0B85B4 */ diff --git a/src/components/droppable.cpp b/src/components/droppable.cpp deleted file mode 100644 index 534fd9a..0000000 --- a/src/components/droppable.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "droppable.h" - -void DroppableComponent::setDroppable(bool can) -{ - droppable = can; -} - -bool DroppableComponent::isDroppable() const -{ - return droppable; -} diff --git a/src/components/droppable.h b/src/components/droppable.h index 83fcb9d..722c139 100644 --- a/src/components/droppable.h +++ b/src/components/droppable.h @@ -4,12 +4,21 @@ #include "component.h" class DroppableComponent : public Component { - public: - void setDroppable(bool can); - bool isDroppable() const; +public: - private: - bool droppable = false; + inline bool isDroppable() const + { + return droppable_; + } + + inline void setDroppable(bool can) + { + droppable_ = can; + } + +private: + + bool droppable_ = false; }; #endif /* end of include guard: DROPPABLE_H_5DB254EF */ diff --git a/src/components/ponderable.cpp b/src/components/ponderable.cpp deleted file mode 100644 index 2cfa6a6..0000000 --- a/src/components/ponderable.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "ponderable.h" - -double PonderableComponent::getVelocityX() const -{ - return velocityX; -} - -void PonderableComponent::setVelocityX(double v) -{ - velocityX = v; -} - -double PonderableComponent::getVelocityY() const -{ - return velocityY; -} - -void PonderableComponent::setVelocityY(double v) -{ - velocityY = v; -} - -double PonderableComponent::getAccelX() const -{ - return accelX; -} - -void PonderableComponent::setAccelX(double v) -{ - accelX = v; -} - -double PonderableComponent::getAccelY() const -{ - return accelY; -} - -void PonderableComponent::setAccelY(double v) -{ - accelY = v; -} diff --git a/src/components/ponderable.h b/src/components/ponderable.h index c836d2a..80100d7 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -4,21 +4,59 @@ #include "component.h" class PonderableComponent : public Component { - public: - double getVelocityX() const; - void setVelocityX(double v); - double getVelocityY() const; - void setVelocityY(double v); - double getAccelX() const; - void setAccelX(double v); - double getAccelY() const; - void setAccelY(double v); - - private: - double velocityX = 0.0; - double velocityY = 0.0; - double accelX = 0.0; - double accelY = 0.0; +public: + + inline double getVelocityX() const + { + return velX_; + } + + inline void setVelocityX(double v) + { + velX_ = v; + } + + inline double getVelocityY() const + { + return velY_; + } + + inline void setVelocityY(double v) + { + velY_ = v; + } + + inline double getAccelX() const + { + return accelX_; + } + + inline void setAccelX(double v) + { + accelX_ = v; + } + + inline double getAccelY() const + { + return accelY_; + } + + inline void setAccelY(double v) + { + accelY_ = v; + } + + inline state getState() const + { + return state_; + } + +private: + + double velX_ = 0.0; + double velY_ = 0.0; + double accelX_ = 0.0; + double accelY_ = 0.0; }; #endif /* end of include guard: TANGIBLE_H_746DB3EE */ diff --git a/src/components/transformable.cpp b/src/components/transformable.cpp deleted file mode 100644 index 89b1e5d..0000000 --- a/src/components/transformable.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "transformable.h" - -TransformableComponent::TransformableComponent(double x, double y, int w, int h) - : x(x), y(y), w(w), h(h) -{ - -} - -double TransformableComponent::getX() const -{ - return x; -} - -double TransformableComponent::getY() const -{ - return y; -} - -int TransformableComponent::getW() const -{ - return w; -} - -int TransformableComponent::getH() const -{ - return h; -} - -void TransformableComponent::setX(double v) -{ - x = v; -} - -void TransformableComponent::setY(double v) -{ - y = v; -} - -void TransformableComponent::setW(int v) -{ - w = v; -} - -void TransformableComponent::setH(int v) -{ - h = v; -} diff --git a/src/components/transformable.h b/src/components/transformable.h index 69f4f0e..6ed2637 100644 --- a/src/components/transformable.h +++ b/src/components/transformable.h @@ -4,24 +4,66 @@ #include "component.h" class TransformableComponent : public Component { - public: - TransformableComponent(double x, double y, int w, int h); - - double getX() const; - double getY() const; - int getW() const; - int getH() const; - - void setX(double v); - void setY(double v); - void setW(int v); - void setH(int v); - - private: - double x; - double y; - int w; - int h; +public: + + TransformableComponent( + double x, + double y, + int w, + int h) : + x_(x), + y_(y), + w_(w), + h_(h) + { + } + + inline double getX() const + { + return x_; + } + + inline void setX(double v) + { + x_ = v; + } + + inline double getY() const + { + return y_; + } + + inline void setY(double v) + { + y_ = v; + } + + inline int getW() const + { + return w_; + } + + inline void setW(int v) + { + w_ = v; + } + + inline int getH() const + { + return h_; + } + + inline void setH(int v) + { + h_ = v; + } + +private: + + double x_; + double y_; + int w_; + int h_; }; #endif /* end of include guard: LOCATABLE_H_39E526CA */ -- cgit 1.4.1 From cec0ed92c4035c4421d3cc2448f5423fcbb7f7d4 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Wed, 7 Feb 2018 17:55:29 -0500 Subject: Fixed behavior of letting go of the right button --- src/systems/controlling.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/systems/controlling.cpp b/src/systems/controlling.cpp index 456da3b..ec62e9a 100644 --- a/src/systems/controlling.cpp +++ b/src/systems/controlling.cpp @@ -72,7 +72,7 @@ void ControllingSystem::tick(double dt) if (!controllable.isFrozen()) { - if (controllable.isHoldingRight()) + if (controllable.isHoldingLeft()) { walkLeft(entity); } else { -- cgit 1.4.1 From cefe66cdbb8786dc455657376e36f0ff8785d5bc Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Thu, 8 Feb 2018 12:34:42 -0500 Subject: Introduced animated sprites Also restyled a lot of the code. --- CMakeLists.txt | 2 +- src/animation.cpp | 35 +++++++++++ src/animation.h | 100 ++++++++++++++++++++++++++++++ src/components/animatable.cpp | 27 --------- src/components/animatable.h | 75 ++++++++++++++++------- src/components/orientable.h | 24 ++++++++ src/components/ponderable.h | 13 ++++ src/game.cpp | 73 +++++++++++++--------- src/game.h | 36 ++++++++--- src/system.h | 12 +++- src/systems/animating.cpp | 38 ++++++++++++ src/systems/animating.h | 20 ++++++ src/systems/controlling.cpp | 138 +++++++++++++++++++++++++++--------------- src/systems/controlling.h | 36 ++++++----- src/systems/pondering.cpp | 10 +-- src/systems/pondering.h | 10 +-- src/systems/rendering.cpp | 40 ++++++++---- src/systems/rendering.h | 15 +++-- 18 files changed, 521 insertions(+), 183 deletions(-) create mode 100644 src/animation.cpp create mode 100644 src/animation.h delete mode 100644 src/components/animatable.cpp create mode 100644 src/components/orientable.h create mode 100644 src/systems/animating.cpp create mode 100644 src/systems/animating.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index e43b056..0ac3a38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,10 +61,10 @@ add_executable(Aromatherapy src/entity_manager.cpp src/game.cpp src/animation.cpp - src/components/animatable.cpp src/systems/rendering.cpp src/systems/controlling.cpp src/systems/pondering.cpp + src/systems/animating.cpp ) target_link_libraries(Aromatherapy ${ALL_LIBS}) install(TARGETS Aromatherapy RUNTIME DESTINATION ${BIN_DIR}) diff --git a/src/animation.cpp b/src/animation.cpp new file mode 100644 index 0000000..31ba21f --- /dev/null +++ b/src/animation.cpp @@ -0,0 +1,35 @@ +#include "animation.h" + +AnimationSet::AnimationSet( + Texture texture, + int frameWidth, + int frameHeight, + int framesAcross) : + texture_(std::move(texture)), + frameWidth_(frameWidth), + frameHeight_(frameHeight), + framesAcross_(framesAcross) +{ +} + +void AnimationSet::emplaceAnimation( + std::string animation, + size_t firstFrame, + size_t numFrames, + size_t delay) +{ + animations_.emplace( + std::piecewise_construct, + std::make_tuple(animation), + std::make_tuple(firstFrame, numFrames, delay)); +} + +Rectangle AnimationSet::getFrameRect(int frame) const +{ + return { + frameWidth_ * (frame % framesAcross_), + frameHeight_ * (frame / framesAcross_), + frameWidth_, + frameHeight_ + }; +} diff --git a/src/animation.h b/src/animation.h new file mode 100644 index 0000000..50446d0 --- /dev/null +++ b/src/animation.h @@ -0,0 +1,100 @@ +#ifndef ANIMATION_H_74EB0901 +#define ANIMATION_H_74EB0901 + +#include "renderer.h" +#include +#include +#include + +class Animation { +public: + + Animation( + size_t firstFrame, + size_t numFrames, + size_t delay) : + firstFrame_(firstFrame), + numFrames_(numFrames), + delay_(delay) + { + } + + inline size_t getFirstFrame() const + { + return firstFrame_; + } + + inline size_t getNumFrames() const + { + return numFrames_; + } + + inline size_t getDelay() const + { + return delay_; + } + +private: + + size_t firstFrame_; + size_t numFrames_; + size_t delay_; +}; + +class AnimationSet { +public: + + AnimationSet( + Texture texture, + int frameWidth, + int frameHeight, + int framesAcross); + + void emplaceAnimation( + std::string animation, + size_t firstFrame, + size_t numFrames, + size_t delay); + + inline const Animation& getAnimation(std::string animation) const + { + if (!animations_.count(animation)) + { + throw std::invalid_argument("Animation does not exist"); + } + + return animations_.at(animation); + } + + inline const Texture& getTexture() const + { + return texture_; + } + + inline int getFrameWidth() const + { + return frameWidth_; + } + + inline int getFrameHeight() const + { + return frameHeight_; + } + + inline int getFramesAcross() const + { + return framesAcross_; + } + + Rectangle getFrameRect(int frame) const; + +private: + + std::map animations_; + Texture texture_; + int frameWidth_; + int frameHeight_; + int framesAcross_; +}; + +#endif /* end of include guard: ANIMATION_H_74EB0901 */ diff --git a/src/components/animatable.cpp b/src/components/animatable.cpp deleted file mode 100644 index fcd277c..0000000 --- a/src/components/animatable.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "animatable.h" - -AnimatableComponent::AnimatableComponent(const char* filename, int frame_width, int frame_height, int frames_across) - : texture(filename), frame_width(frame_width), frame_height(frame_height), frames_across(frames_across) -{ - -} - -int AnimatableComponent::getFrame() const -{ - return frame; -} - -void AnimatableComponent::setFrame(int frame) -{ - this->frame = frame; -} - -const Texture& AnimatableComponent::getTexture() const -{ - return texture; -} - -Rectangle AnimatableComponent::getFrameRect() const -{ - return {frame_width * (frame % frames_across), frame_height * (frame / frames_across), frame_width, frame_height}; -} diff --git a/src/components/animatable.h b/src/components/animatable.h index cf6ee54..ed0133e 100644 --- a/src/components/animatable.h +++ b/src/components/animatable.h @@ -2,30 +2,61 @@ #define SPRITE_RENDERABLE_H_D3AACBBF #include "component.h" -#include "renderer.h" -#include "direction.h" +#include "animation.h" +#include class AnimatableComponent : public Component { - public: - AnimatableComponent(const char* filename, int frame_width, int frame_height, int frames_across); - - int getFrame() const; - void setFrame(int frame); - - const Texture& getTexture() const; - Rectangle getFrameRect() const; - - void setDirection(Direction dir) {}; - void setWalking(bool w) {}; - void setJumping(bool w) {}; - void setCrouching(bool w) {}; - - private: - Texture texture; - int frame_width; - int frame_height; - int frames_across; - int frame = 0; +public: + + AnimatableComponent( + AnimationSet animationSet, + std::string animation) : + animationSet_(std::move(animationSet)), + animation_(std::move(animation)) + { + } + + inline size_t getFrame() const + { + return frame_; + } + + inline void setFrame(size_t v) + { + frame_ = v; + } + + inline size_t getCountdown() const + { + return countdown_; + } + + inline void setCountdown(size_t v) + { + countdown_ = v; + } + + inline const AnimationSet& getAnimationSet() const + { + return animationSet_; + } + + inline const Animation& getAnimation() const + { + return animationSet_.getAnimation(animation_); + } + + inline void setAnimation(std::string animation) + { + animation_ = std::move(animation); + } + +private: + + AnimationSet animationSet_; + std::string animation_; + size_t frame_ = 0; + size_t countdown_ = 0; }; #endif /* end of include guard: SPRITE_RENDERABLE_H_D3AACBBF */ diff --git a/src/components/orientable.h b/src/components/orientable.h new file mode 100644 index 0000000..8f56912 --- /dev/null +++ b/src/components/orientable.h @@ -0,0 +1,24 @@ +#ifndef ORIENTABLE_H_EDB6C4A1 +#define ORIENTABLE_H_EDB6C4A1 + +#include "component.h" + +class OrientableComponent : public Component { +public: + + inline bool isFacingRight() const + { + return facingRight_; + } + + inline void setFacingRight(bool v) + { + facingRight_ = v; + } + +private: + + bool facingRight_ = false; +}; + +#endif /* end of include guard: ORIENTABLE_H_EDB6C4A1 */ diff --git a/src/components/ponderable.h b/src/components/ponderable.h index 80100d7..dfbf908 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -6,6 +6,13 @@ class PonderableComponent : public Component { public: + enum class state { + grounded, + jumping, + falling, + dropping + }; + inline double getVelocityX() const { return velX_; @@ -51,12 +58,18 @@ public: return state_; } + inline void setState(state arg) + { + state_ = arg; + } + private: double velX_ = 0.0; double velY_ = 0.0; double accelX_ = 0.0; double accelY_ = 0.0; + state state_ = state::grounded; }; #endif /* end of include guard: TANGIBLE_H_746DB3EE */ diff --git a/src/game.cpp b/src/game.cpp index 5d1ec18..492e4d0 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -4,40 +4,59 @@ #include "components/controllable.h" #include "components/droppable.h" #include "components/ponderable.h" +#include "components/orientable.h" #include "systems/rendering.h" #include "systems/controlling.h" #include "systems/pondering.h" +#include "systems/animating.h" +#include "animation.h" void key_callback(GLFWwindow* window, int key, int, int action, int) { Game& game = *((Game*) glfwGetWindowUserPointer(window)); - + if ((action == GLFW_PRESS) && (key == GLFW_KEY_ESCAPE)) { - game.shouldQuit = true; - + game.shouldQuit_ = true; + return; } - - game.systemManager.getSystem().input(key, action); + + game.systemManager_.getSystem().input(key, action); } -Game::Game(GLFWwindow* window) : window(window) +Game::Game(GLFWwindow* window) : window_(window) { - systemManager.emplaceSystem(*this); - systemManager.emplaceSystem(*this); - systemManager.emplaceSystem(*this); - - int player = entityManager.emplaceEntity(); - entityManager.emplaceComponent(player, "res/Starla.png", 10, 12, 6); - entityManager.emplaceComponent(player, 203, 44, 10, 12); - entityManager.emplaceComponent(player); - entityManager.emplaceComponent(player); - entityManager.emplaceComponent(player); - + systemManager_.emplaceSystem(*this); + systemManager_.emplaceSystem(*this); + systemManager_.emplaceSystem(*this); + systemManager_.emplaceSystem(*this); + + int player = entityManager_.emplaceEntity(); + + AnimationSet playerGraphics {"res/Starla2.bmp", 10, 12, 6}; + playerGraphics.emplaceAnimation("stillLeft", 3, 1, 1); + playerGraphics.emplaceAnimation("stillRight", 0, 1, 1); + playerGraphics.emplaceAnimation("walkingLeft", 4, 2, 10); + playerGraphics.emplaceAnimation("walkingRight", 1, 2, 10); + + entityManager_.emplaceComponent( + player, + std::move(playerGraphics), + "stillLeft"); + + entityManager_.emplaceComponent( + player, + 203, 44, 10, 12); + + entityManager_.emplaceComponent(player); + entityManager_.emplaceComponent(player); + entityManager_.emplaceComponent(player); + entityManager_.emplaceComponent(player); + glfwSwapInterval(1); - glfwSetWindowUserPointer(window, this); - glfwSetKeyCallback(window, key_callback); + glfwSetWindowUserPointer(window_, this); + glfwSetKeyCallback(window_, key_callback); } void Game::execute() @@ -46,7 +65,7 @@ void Game::execute() const double dt = 0.01; double accumulator = 0.0; - while (!(shouldQuit || glfwWindowShouldClose(window))) + while (!(shouldQuit_ || glfwWindowShouldClose(window_))) { double currentTime = glfwGetTime(); double frameTime = currentTime - lastTime; @@ -57,19 +76,13 @@ void Game::execute() accumulator += frameTime; while (accumulator >= dt) { - systemManager.getSystem().tick(dt); - systemManager.getSystem().tick(dt); + systemManager_.getSystem().tick(dt); + systemManager_.getSystem().tick(dt); + systemManager_.getSystem().tick(dt); accumulator -= dt; } - systemManager.getSystem().tick(frameTime); + systemManager_.getSystem().tick(frameTime); } } - -EntityManager& Game::getEntityManager() -{ - return entityManager; -} - - diff --git a/src/game.h b/src/game.h index ec667c8..7bd038e 100644 --- a/src/game.h +++ b/src/game.h @@ -6,19 +6,35 @@ #include "system_manager.h" class Game { - public: - Game(GLFWwindow* window); +public: - void execute(); - EntityManager& getEntityManager(); + Game(GLFWwindow* window); - friend void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods); + void execute(); - private: - EntityManager entityManager; - SystemManager systemManager; - GLFWwindow* const window; - bool shouldQuit = false; + inline EntityManager& getEntityManager() + { + return entityManager_; + } + + inline SystemManager& getSystemManager() + { + return systemManager_; + } + + friend void key_callback( + GLFWwindow* window, + int key, + int scancode, + int action, + int mods); + +private: + + EntityManager entityManager_; + SystemManager systemManager_; + GLFWwindow* const window_; + bool shouldQuit_ = false; }; #endif /* end of include guard: GAME_H_1014DDC9 */ diff --git a/src/system.h b/src/system.h index 489afd0..6a3cd14 100644 --- a/src/system.h +++ b/src/system.h @@ -1,12 +1,18 @@ #ifndef SYSTEM_H_B61A8CEA #define SYSTEM_H_B61A8CEA +#include "entity_manager.h" + class Game; class System { public: - System(Game& game) - : game(game) {} + + using id_type = EntityManager::id_type; + + System(Game& game) : game_(game) + { + } virtual ~System() = default; @@ -14,7 +20,7 @@ public: protected: - Game& game; + Game& game_; }; #endif /* end of include guard: SYSTEM_H_B61A8CEA */ diff --git a/src/systems/animating.cpp b/src/systems/animating.cpp new file mode 100644 index 0000000..fcbfca5 --- /dev/null +++ b/src/systems/animating.cpp @@ -0,0 +1,38 @@ +#include "animating.h" +#include "game.h" +#include "components/animatable.h" + +void AnimatingSystem::tick(double) +{ + std::set spriteEntities = + game_.getEntityManager().getEntitiesWithComponents(); + + for (id_type entity : spriteEntities) + { + auto& sprite = game_.getEntityManager(). + getComponent(entity); + + sprite.setCountdown(sprite.getCountdown() + 1); + + const Animation& anim = sprite.getAnimation(); + if (sprite.getCountdown() >= anim.getDelay()) + { + sprite.setFrame(sprite.getFrame() + 1); + sprite.setCountdown(0); + + if (sprite.getFrame() >= anim.getFirstFrame() + anim.getNumFrames()) + { + sprite.setFrame(anim.getFirstFrame()); + } + } + } +} + +void AnimatingSystem::startAnimation(id_type entity, std::string animation) +{ + auto& sprite = game_.getEntityManager(). + getComponent(entity); + + sprite.setAnimation(animation); + sprite.setFrame(sprite.getAnimation().getFirstFrame()); +} diff --git a/src/systems/animating.h b/src/systems/animating.h new file mode 100644 index 0000000..150a74a --- /dev/null +++ b/src/systems/animating.h @@ -0,0 +1,20 @@ +#ifndef ANIMATING_H_5BBF0094 +#define ANIMATING_H_5BBF0094 + +#include "system.h" +#include + +class AnimatingSystem : public System { +public: + + AnimatingSystem(Game& game) : System(game) + { + } + + void tick(double dt); + + void startAnimation(id_type entity, std::string animation); + +}; + +#endif /* end of include guard: ANIMATING_H_5BBF0094 */ diff --git a/src/systems/controlling.cpp b/src/systems/controlling.cpp index ec62e9a..3647ff8 100644 --- a/src/systems/controlling.cpp +++ b/src/systems/controlling.cpp @@ -4,21 +4,30 @@ #include "components/ponderable.h" #include "components/animatable.h" #include "components/droppable.h" +#include "components/orientable.h" +#include "systems/animating.h" #include "direction.h" #include "muxer.h" #include "consts.h" -void ControllingSystem::tick(double dt) +void ControllingSystem::tick(double) { - while (!actions.empty()) + while (!actions_.empty()) { - int key = actions.front().first; - int action = actions.front().second; + int key = actions_.front().first; + int action = actions_.front().second; + + auto entities = game_.getEntityManager().getEntitiesWithComponents< + ControllableComponent, + PonderableComponent, + AnimatableComponent, + DroppableComponent, + OrientableComponent>(); - auto entities = game.getEntityManager().getEntitiesWithComponents(); for (auto entity : entities) { - auto& controllable = game.getEntityManager().getComponent(entity); + auto& controllable = game_.getEntityManager(). + getComponent(entity); if (action == GLFW_PRESS) { @@ -95,74 +104,107 @@ void ControllingSystem::tick(double dt) } } - actions.pop(); + actions_.pop(); } } void ControllingSystem::input(int key, int action) { - actions.push(std::make_pair(key, action)); + actions_.push(std::make_pair(key, action)); } -void ControllingSystem::walkLeft(int entity) +void ControllingSystem::walkLeft(id_type entity) { - auto& ponderable = game.getEntityManager().getComponent(entity); - auto& animatable = game.getEntityManager().getComponent(entity); - + auto& ponderable = game_.getEntityManager().getComponent(entity); + auto& orientable = game_.getEntityManager().getComponent(entity); + + orientable.setFacingRight(false); ponderable.setVelocityX(-90); - - animatable.setDirection(Direction::Left); - animatable.setWalking(true); + + auto& animating = game_.getSystemManager().getSystem(); + + if (ponderable.getState() == PonderableComponent::state::grounded) + { + animating.startAnimation(entity, "walkingLeft"); + } else { + animating.startAnimation(entity, "stillLeft"); + } } -void ControllingSystem::walkRight(int entity) +void ControllingSystem::walkRight(id_type entity) { - auto& ponderable = game.getEntityManager().getComponent(entity); - auto& animatable = game.getEntityManager().getComponent(entity); - + auto& ponderable = game_.getEntityManager().getComponent(entity); + auto& orientable = game_.getEntityManager().getComponent(entity); + + orientable.setFacingRight(true); ponderable.setVelocityX(90); - animatable.setDirection(Direction::Right); - animatable.setWalking(true); + auto& animating = game_.getSystemManager().getSystem(); + + if (ponderable.getState() == PonderableComponent::state::grounded) + { + animating.startAnimation(entity, "walkingRight"); + } else { + animating.startAnimation(entity, "stillRight"); + } } -void ControllingSystem::stopWalking(int entity) +void ControllingSystem::stopWalking(id_type entity) { - auto& ponderable = game.getEntityManager().getComponent(entity); - auto& animatable = game.getEntityManager().getComponent(entity); - + auto& ponderable = game_.getEntityManager().getComponent(entity); + auto& orientable = game_.getEntityManager().getComponent(entity); + ponderable.setVelocityX(0); - - animatable.setWalking(false); + + if (ponderable.getState() == PonderableComponent::state::grounded) + { + auto& animating = game_.getSystemManager().getSystem(); + + if (orientable.isFacingRight()) + { + animating.startAnimation(entity, "stillRight"); + } else { + animating.startAnimation(entity, "stillLeft"); + } + } } -void ControllingSystem::jump(int entity) +void ControllingSystem::jump(id_type entity) { - auto& ponderable = game.getEntityManager().getComponent(entity); - auto& animatable = game.getEntityManager().getComponent(entity); - - playSound("res/Randomize87.wav", 0.25); - - ponderable.setVelocityY(JUMP_VELOCITY(TILE_HEIGHT*4.5, 0.3)); - ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*4.5, 0.3)); - - animatable.setJumping(true); + auto& ponderable = game_.getEntityManager().getComponent(entity); + + if (ponderable.getState() == PonderableComponent::state::grounded) + { + playSound("res/Randomize87.wav", 0.25); + + ponderable.setVelocityY(JUMP_VELOCITY(TILE_HEIGHT*4.5, 0.3)); + ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*4.5, 0.3)); + ponderable.setState(PonderableComponent::state::jumping); + } } -void ControllingSystem::stopJumping(int entity) +void ControllingSystem::stopJumping(id_type entity) { - auto& ponderable = game.getEntityManager().getComponent(entity); - auto& animatable = game.getEntityManager().getComponent(entity); - - ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233)); - animatable.setJumping(false); + auto& ponderable = game_.getEntityManager().getComponent(entity); + + if (ponderable.getState() == PonderableComponent::state::jumping) + { + ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233)); + ponderable.setState(PonderableComponent::state::falling); + } } -void ControllingSystem::drop(int entity, bool start) +void ControllingSystem::drop(id_type entity, bool start) { - auto& animatable = game.getEntityManager().getComponent(entity); - auto& droppable = game.getEntityManager().getComponent(entity); - + auto& droppable = game_.getEntityManager().getComponent(entity); + auto& ponderable = game_.getEntityManager().getComponent(entity); + + if (start && (ponderable.getState() == PonderableComponent::state::grounded)) + { + ponderable.setState(PonderableComponent::state::dropping); + } else if ((!start) && (ponderable.getState() == PonderableComponent::state::dropping)) + { + ponderable.setState(PonderableComponent::state::grounded); + } droppable.setDroppable(start); - animatable.setCrouching(start); } diff --git a/src/systems/controlling.h b/src/systems/controlling.h index 30210b3..1f1e8a0 100644 --- a/src/systems/controlling.h +++ b/src/systems/controlling.h @@ -3,24 +3,28 @@ #include "system.h" #include +#include "entity_manager.h" class ControllingSystem : public System { - public: - ControllingSystem(Game& game) - : System(game) {} - - void tick(double dt); - void input(int key, int action); - - private: - void walkLeft(int entity); - void walkRight(int entity); - void stopWalking(int entity); - void jump(int entity); - void stopJumping(int entity); - void drop(int entity, bool start); - - std::queue> actions; +public: + + ControllingSystem(Game& game) : System(game) + { + } + + void tick(double dt); + void input(int key, int action); + +private: + + void walkLeft(id_type entity); + void walkRight(id_type entity); + void stopWalking(id_type entity); + void jump(id_type entity); + void stopJumping(id_type entity); + void drop(id_type entity, bool start); + + std::queue> actions_; }; #endif /* end of include guard: CONTROLLING_H_80B1BB8D */ diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 50a8bc8..e40db1d 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -5,12 +5,14 @@ void PonderingSystem::tick(double dt) { - auto entities = game.getEntityManager().getEntitiesWithComponents(); + auto entities = game_.getEntityManager().getEntitiesWithComponents< + PonderableComponent, + TransformableComponent>(); - for (auto entity : entities) + for (id_type entity : entities) { - auto& transformable = game.getEntityManager().getComponent(entity); - auto& ponderable = game.getEntityManager().getComponent(entity); + auto& transformable = game_.getEntityManager().getComponent(entity); + auto& ponderable = game_.getEntityManager().getComponent(entity); // Accelerate ponderable.setVelocityX(ponderable.getVelocityX() + ponderable.getAccelX() * dt); diff --git a/src/systems/pondering.h b/src/systems/pondering.h index 3fe5473..44e7600 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -4,11 +4,13 @@ #include "system.h" class PonderingSystem : public System { - public: - PonderingSystem(Game& game) - : System(game) {} +public: - void tick(double dt); + PonderingSystem(Game& game) : System(game) + { + } + + void tick(double dt); }; #endif /* end of include guard: PONDERING_H_F2530E0E */ diff --git a/src/systems/rendering.cpp b/src/systems/rendering.cpp index 251c2bc..8219732 100644 --- a/src/systems/rendering.cpp +++ b/src/systems/rendering.cpp @@ -3,19 +3,35 @@ #include "components/animatable.h" #include "components/transformable.h" -void RenderingSystem::tick(double dt) +void RenderingSystem::tick(double) { - texture.fill(texture.entirety(), 0, 0, 0); - - std::set spriteEntities = game.getEntityManager().getEntitiesWithComponents(); - for (int entity : spriteEntities) + texture_.fill(texture_.entirety(), 0, 0, 0); + + std::set spriteEntities = + game_.getEntityManager().getEntitiesWithComponents< + AnimatableComponent, + TransformableComponent>(); + + for (id_type entity : spriteEntities) { - auto& sprite = game.getEntityManager().getComponent(entity); - auto& transform = game.getEntityManager().getComponent(entity); - Rectangle dstrect {(int) transform.getX(), (int) transform.getY(), transform.getW(), transform.getH()}; - - texture.blit(sprite.getTexture(), sprite.getFrameRect(), dstrect); + auto& sprite = game_.getEntityManager(). + getComponent(entity); + + auto& transform = game_.getEntityManager(). + getComponent(entity); + + Rectangle dstrect { + static_cast(transform.getX()), + static_cast(transform.getY()), + transform.getW(), + transform.getH()}; + + const AnimationSet& aset = sprite.getAnimationSet(); + texture_.blit( + aset.getTexture(), + aset.getFrameRect(sprite.getFrame()), + dstrect); } - - texture.renderScreen(); + + texture_.renderScreen(); } diff --git a/src/systems/rendering.h b/src/systems/rendering.h index cec72e2..a53ee64 100644 --- a/src/systems/rendering.h +++ b/src/systems/rendering.h @@ -6,14 +6,17 @@ #include "consts.h" class RenderingSystem : public System { - public: - RenderingSystem(Game& game) - : System(game) {} +public: - void tick(double dt); + RenderingSystem(Game& game) : System(game) + { + } - private: - Texture texture {GAME_WIDTH, GAME_HEIGHT}; + void tick(double dt); + +private: + + Texture texture_ {GAME_WIDTH, GAME_HEIGHT}; }; #endif /* end of include guard: RENDERING_H_76ABC02A */ -- cgit 1.4.1 From 1400ade977e13e3b535d3c2fddb6e15de3c9b5a5 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Thu, 8 Feb 2018 13:43:10 -0500 Subject: Moved sprite rendering into AnimatingSystem Refactored how systems work slightly. Now, rendering can be done by a number of systems working together. Since the AnimatingSystem handles the animation of sprites, it should also handle the rendering of them. Because of this, the RenderingSystem has been removed. --- CMakeLists.txt | 1 - src/game.cpp | 16 +++++++++------- src/system.h | 31 ++++++++++++++++++++++++++++++- src/system_manager.h | 24 ++++++++++++++++++++++++ src/systems/animating.cpp | 30 ++++++++++++++++++++++++++++++ src/systems/animating.h | 3 +++ src/systems/rendering.cpp | 37 ------------------------------------- src/systems/rendering.h | 22 ---------------------- 8 files changed, 96 insertions(+), 68 deletions(-) delete mode 100644 src/systems/rendering.cpp delete mode 100644 src/systems/rendering.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ac3a38..1da4432 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,6 @@ add_executable(Aromatherapy src/entity_manager.cpp src/game.cpp src/animation.cpp - src/systems/rendering.cpp src/systems/controlling.cpp src/systems/pondering.cpp src/systems/animating.cpp diff --git a/src/game.cpp b/src/game.cpp index 492e4d0..dfe700e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -5,11 +5,12 @@ #include "components/droppable.h" #include "components/ponderable.h" #include "components/orientable.h" -#include "systems/rendering.h" #include "systems/controlling.h" #include "systems/pondering.h" #include "systems/animating.h" #include "animation.h" +#include "renderer.h" +#include "consts.h" void key_callback(GLFWwindow* window, int key, int, int action, int) { @@ -22,14 +23,13 @@ void key_callback(GLFWwindow* window, int key, int, int action, int) return; } - game.systemManager_.getSystem().input(key, action); + game.systemManager_.input(key, action); } Game::Game(GLFWwindow* window) : window_(window) { systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); - systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); int player = entityManager_.emplaceEntity(); @@ -64,6 +64,7 @@ void Game::execute() double lastTime = glfwGetTime(); const double dt = 0.01; double accumulator = 0.0; + Texture texture(GAME_WIDTH, GAME_HEIGHT); while (!(shouldQuit_ || glfwWindowShouldClose(window_))) { @@ -76,13 +77,14 @@ void Game::execute() accumulator += frameTime; while (accumulator >= dt) { - systemManager_.getSystem().tick(dt); - systemManager_.getSystem().tick(dt); - systemManager_.getSystem().tick(dt); + systemManager_.tick(dt); accumulator -= dt; } - systemManager_.getSystem().tick(frameTime); + // Render + texture.fill(texture.entirety(), 0, 0, 0); + systemManager_.render(texture); + texture.renderScreen(); } } diff --git a/src/system.h b/src/system.h index 6a3cd14..e630c48 100644 --- a/src/system.h +++ b/src/system.h @@ -4,6 +4,7 @@ #include "entity_manager.h" class Game; +class Texture; class System { public: @@ -16,7 +17,35 @@ public: virtual ~System() = default; - virtual void tick(double dt) = 0; + /** + * Updates the state of a system. + * + * @param dt - The amount of time in seconds that have passed since the last + * update. + */ + virtual void tick(double) + { + } + + /** + * Renders to a texture. + * + * @param texture - The surface to render to. + */ + virtual void render(Texture&) + { + } + + /** + * Processes keyboard input. + * + * @param key - The relevant key. + * + * @param action - The action performed (press, released, etc). + */ + virtual void input(int, int) + { + } protected: diff --git a/src/system_manager.h b/src/system_manager.h index e2c98cb..b03c3f2 100644 --- a/src/system_manager.h +++ b/src/system_manager.h @@ -39,6 +39,30 @@ public: return *dynamic_cast(systems[systemType]); } + void tick(double dt) + { + for (std::unique_ptr& sys : loop) + { + sys->tick(dt); + } + } + + virtual void render(Texture& texture) + { + for (std::unique_ptr& sys : loop) + { + sys->render(texture); + } + } + + virtual void input(int key, int action) + { + for (std::unique_ptr& sys : loop) + { + sys->input(key, action); + } + } + }; #endif /* end of include guard: SYSTEM_MANAGER_H_544E6056 */ diff --git a/src/systems/animating.cpp b/src/systems/animating.cpp index fcbfca5..91fe925 100644 --- a/src/systems/animating.cpp +++ b/src/systems/animating.cpp @@ -1,6 +1,7 @@ #include "animating.h" #include "game.h" #include "components/animatable.h" +#include "components/transformable.h" void AnimatingSystem::tick(double) { @@ -28,6 +29,35 @@ void AnimatingSystem::tick(double) } } +void AnimatingSystem::render(Texture& texture) +{ + std::set spriteEntities = + game_.getEntityManager().getEntitiesWithComponents< + AnimatableComponent, + TransformableComponent>(); + + for (id_type entity : spriteEntities) + { + auto& sprite = game_.getEntityManager(). + getComponent(entity); + + auto& transform = game_.getEntityManager(). + getComponent(entity); + + Rectangle dstrect { + static_cast(transform.getX()), + static_cast(transform.getY()), + transform.getW(), + transform.getH()}; + + const AnimationSet& aset = sprite.getAnimationSet(); + texture.blit( + aset.getTexture(), + aset.getFrameRect(sprite.getFrame()), + dstrect); + } +} + void AnimatingSystem::startAnimation(id_type entity, std::string animation) { auto& sprite = game_.getEntityManager(). diff --git a/src/systems/animating.h b/src/systems/animating.h index 150a74a..d6a89a5 100644 --- a/src/systems/animating.h +++ b/src/systems/animating.h @@ -3,6 +3,7 @@ #include "system.h" #include +#include "renderer.h" class AnimatingSystem : public System { public: @@ -13,6 +14,8 @@ public: void tick(double dt); + void render(Texture& texture); + void startAnimation(id_type entity, std::string animation); }; diff --git a/src/systems/rendering.cpp b/src/systems/rendering.cpp deleted file mode 100644 index 8219732..0000000 --- a/src/systems/rendering.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "rendering.h" -#include "game.h" -#include "components/animatable.h" -#include "components/transformable.h" - -void RenderingSystem::tick(double) -{ - texture_.fill(texture_.entirety(), 0, 0, 0); - - std::set spriteEntities = - game_.getEntityManager().getEntitiesWithComponents< - AnimatableComponent, - TransformableComponent>(); - - for (id_type entity : spriteEntities) - { - auto& sprite = game_.getEntityManager(). - getComponent(entity); - - auto& transform = game_.getEntityManager(). - getComponent(entity); - - Rectangle dstrect { - static_cast(transform.getX()), - static_cast(transform.getY()), - transform.getW(), - transform.getH()}; - - const AnimationSet& aset = sprite.getAnimationSet(); - texture_.blit( - aset.getTexture(), - aset.getFrameRect(sprite.getFrame()), - dstrect); - } - - texture_.renderScreen(); -} diff --git a/src/systems/rendering.h b/src/systems/rendering.h deleted file mode 100644 index a53ee64..0000000 --- a/src/systems/rendering.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef RENDERING_H_76ABC02A -#define RENDERING_H_76ABC02A - -#include "system.h" -#include "renderer.h" -#include "consts.h" - -class RenderingSystem : public System { -public: - - RenderingSystem(Game& game) : System(game) - { - } - - void tick(double dt); - -private: - - Texture texture_ {GAME_WIDTH, GAME_HEIGHT}; -}; - -#endif /* end of include guard: RENDERING_H_76ABC02A */ -- cgit 1.4.1 From 77be863f4f15d2481a64e4e8dadb4060a6e4e590 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sun, 11 Feb 2018 12:34:52 -0500 Subject: Implemented map rendering and basic collision Only wall and platform collision currently works, and map edges are not currently implemented. --- CMakeLists.txt | 2 + res/monitor-old.obj | 26685 ++++++++++++++++++++++++++++++++++++++++++ src/components/mappable.h | 146 + src/components/ponderable.h | 23 +- src/consts.h | 3 + src/direction.h | 8 +- src/entity_manager.h | 20 +- src/game.cpp | 14 +- src/game.h | 9 +- src/map.h | 45 + src/systems/controlling.cpp | 22 +- src/systems/mapping.cpp | 143 + src/systems/mapping.h | 19 + src/systems/pondering.cpp | 248 +- src/systems/pondering.h | 16 + src/world.cpp | 99 + src/world.h | 41 + 17 files changed, 27512 insertions(+), 31 deletions(-) create mode 100644 res/monitor-old.obj create mode 100644 src/components/mappable.h create mode 100644 src/map.h create mode 100644 src/systems/mapping.cpp create mode 100644 src/systems/mapping.h create mode 100644 src/world.cpp create mode 100644 src/world.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 1da4432..f918156 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,9 +61,11 @@ add_executable(Aromatherapy src/entity_manager.cpp src/game.cpp src/animation.cpp + src/world.cpp src/systems/controlling.cpp src/systems/pondering.cpp src/systems/animating.cpp + src/systems/mapping.cpp ) target_link_libraries(Aromatherapy ${ALL_LIBS}) install(TARGETS Aromatherapy RUNTIME DESTINATION ${BIN_DIR}) diff --git a/res/monitor-old.obj b/res/monitor-old.obj new file mode 100644 index 0000000..0a28458 --- /dev/null +++ b/res/monitor-old.obj @@ -0,0 +1,26685 @@ +# Blender v2.73 (sub 0) OBJ File: 'monitor-fef.blend' +# www.blender.org +o Cube +v -1.735285 0.489114 -0.799344 +v -1.735285 0.431237 -0.857221 +v -1.793162 0.431237 -0.799344 +v -1.793162 0.431237 0.786032 +v -1.735285 0.431237 0.843909 +v -1.735285 0.489113 0.786032 +v -0.892681 0.431237 0.843909 +v -0.892681 0.489113 0.786032 +v -0.892681 0.431237 -0.857221 +v -0.892681 0.489114 -0.799344 +v -1.793162 -0.731632 -0.799344 +v -1.735285 -0.731632 -0.857221 +v -1.735285 -0.789509 -0.799344 +v -1.793162 -0.731632 0.786032 +v -1.735285 -0.789509 0.786032 +v -1.735285 -0.731632 0.843909 +v -0.892681 -0.731632 0.843909 +v -0.892681 -0.789509 0.786032 +v -0.892681 -0.789509 -0.799344 +v -0.892681 -0.731632 -0.857221 +v -0.032689 -0.468750 -0.718750 +v -0.069807 -0.468750 -0.968750 +v 0.038213 -0.218750 -0.218750 +v -0.016837 -0.718750 -0.218750 +v 0.015876 -0.468750 -0.218750 +v -0.003246 -0.468750 -0.468750 +v -0.053111 -0.218750 -0.968750 +v 0.045546 -0.218750 0.031250 +v 0.047426 0.031250 -0.218750 +v -0.010869 -0.718750 0.031250 +v -0.031368 -0.718750 0.531250 +v 0.025942 0.031250 -0.468750 +v 0.050894 0.281250 0.031250 +v 0.025515 0.281250 0.531250 +v 0.020758 -0.218750 0.531250 +v -0.049380 0.281250 -0.968750 +v 0.022228 0.281250 -0.468750 +v 0.017528 -0.218750 -0.468750 +v -0.095012 -0.718750 -0.968750 +v -0.034092 -0.718750 -0.468750 +v -0.060927 -0.718750 -0.718750 +v 0.005862 0.531250 -0.468750 +v 0.025622 0.531250 -0.218750 +v 0.043340 0.281250 -0.218750 +v -0.062451 0.531250 -0.968750 +v -0.024411 0.531250 -0.718750 +v -0.009643 0.281250 -0.718750 +v 0.029277 0.031250 0.531250 +v -0.001795 0.031250 0.781250 +v -0.009454 -0.218750 0.781250 +v 0.008961 0.531250 0.531250 +v -0.020144 0.531250 0.781250 +v -0.005170 0.281250 0.781250 +v 0.032547 0.531250 0.031250 +v 0.027228 0.531250 0.281250 +v 0.045079 0.281250 0.281250 +v -0.000241 -0.468750 0.531250 +v -0.028532 -0.468750 0.781250 +v -0.057124 -0.718750 0.781250 +v 0.022545 -0.468750 0.031250 +v 0.017425 -0.468750 0.281250 +v -0.015448 -0.718750 0.281250 +v 0.055227 0.031250 0.031250 +v 0.049209 0.031250 0.281250 +v 0.039908 -0.218750 0.281250 +v -0.046447 0.031250 -0.968750 +v -0.006318 0.031250 -0.718750 +v -0.013867 -0.218750 -0.718750 +v -0.008602 -0.093750 -0.718750 +v 0.008559 -0.093750 -0.593750 +v 0.002992 -0.218750 -0.593750 +v -0.006605 0.156250 -0.718750 +v 0.010674 0.156250 -0.593750 +v 0.010977 0.031250 -0.593750 +v -0.046700 0.156250 -0.968750 +v -0.025850 0.156250 -0.843750 +v -0.025581 0.031250 -0.843750 +v 0.046366 -0.093750 0.281250 +v 0.038100 -0.093750 0.406250 +v 0.031889 -0.218750 0.406250 +v 0.048851 0.156250 0.281250 +v 0.040475 0.156250 0.406250 +v 0.040817 0.031250 0.406250 +v 0.054844 0.156250 0.031250 +v 0.053715 0.156250 0.156250 +v 0.054089 0.031250 0.156250 +v 0.002107 -0.593750 0.281250 +v -0.004882 -0.593750 0.406250 +v -0.022057 -0.718750 0.406250 +v 0.030144 -0.343750 0.281250 +v 0.022439 -0.343750 0.406250 +v 0.010068 -0.468750 0.406250 +v 0.035529 -0.343750 0.031250 +v 0.034530 -0.343750 0.156250 +v 0.021597 -0.468750 0.156250 +v -0.041784 -0.593750 0.781250 +v -0.058423 -0.593750 0.906250 +v -0.072996 -0.718750 0.906250 +v -0.017666 -0.343750 0.781250 +v -0.035575 -0.343750 0.906250 +v -0.045857 -0.468750 0.906250 +v 0.011687 -0.343750 0.531250 +v -0.001795 -0.343750 0.656250 +v -0.013214 -0.468750 0.656250 +v 0.037763 0.406250 0.281250 +v 0.029819 0.406250 0.406250 +v 0.036867 0.281250 0.406250 +v 0.013825 0.656250 0.281250 +v 0.006559 0.656250 0.406250 +v 0.019607 0.531250 0.406250 +v 0.018878 0.656250 0.031250 +v 0.017943 0.656250 0.156250 +v 0.031561 0.531250 0.156250 +v -0.011246 0.406250 0.781250 +v -0.029509 0.406250 0.906250 +v -0.023779 0.281250 0.906250 +v -0.031632 0.656250 0.781250 +v -0.048795 0.656250 0.906250 +v -0.037918 0.531250 0.906250 +v -0.003632 0.656250 0.531250 +v -0.016467 0.656250 0.656250 +v -0.004402 0.531250 0.656250 +v -0.004113 -0.093750 0.781250 +v -0.022783 -0.093750 0.906250 +v -0.027819 -0.218750 0.906250 +v -0.002086 0.156250 0.781250 +v -0.020874 0.156250 0.906250 +v -0.020600 0.031250 0.906250 +v 0.028952 0.156250 0.531250 +v 0.014644 0.156250 0.656250 +v 0.014951 0.031250 0.656250 +v -0.015634 0.406250 -0.718750 +v 0.001126 0.406250 -0.593750 +v 0.007457 0.281250 -0.593750 +v -0.035749 0.656250 -0.718750 +v -0.020052 0.656250 -0.593750 +v -0.008128 0.531250 -0.593750 +v -0.072531 0.656250 -0.968750 +v -0.053358 0.656250 -0.843750 +v -0.042637 0.531250 -0.843750 +v 0.036085 0.406250 -0.218750 +v 0.041502 0.406250 -0.093750 +v 0.048970 0.281250 -0.093750 +v 0.012296 0.656250 -0.218750 +v 0.017218 0.656250 -0.093750 +v 0.030797 0.531250 -0.093750 +v -0.006605 0.656250 -0.468750 +v 0.004275 0.656250 -0.343750 +v 0.017218 0.531250 -0.343750 +v -0.045773 -0.593750 -0.718750 +v -0.030573 -0.593750 -0.593750 +v -0.046447 -0.718750 -0.593750 +v -0.017575 -0.593750 -0.468750 +v -0.007081 -0.593750 -0.343750 +v -0.024140 -0.718750 -0.343750 +v -0.081468 -0.593750 -0.968750 +v -0.062851 -0.593750 -0.843750 +v -0.077223 -0.718750 -0.843750 +v 0.023390 -0.093750 -0.468750 +v 0.035529 -0.093750 -0.343750 +v 0.029385 -0.218750 -0.343750 +v 0.015568 0.406250 -0.468750 +v 0.027335 0.406250 -0.343750 +v 0.034309 0.281250 -0.343750 +v -0.054673 0.406250 -0.968750 +v -0.034354 0.406250 -0.843750 +v -0.028710 0.281250 -0.843750 +v 0.026691 -0.093750 0.531250 +v 0.012499 -0.093750 0.656250 +v 0.006858 -0.218750 0.656250 +v 0.018774 0.406250 0.531250 +v 0.004968 0.406250 0.656250 +v 0.011382 0.281250 0.656250 +v 0.043340 0.406250 0.031250 +v 0.042304 0.406250 0.156250 +v 0.049808 0.281250 0.156250 +v 0.025622 0.156250 -0.468750 +v 0.037876 0.156250 -0.343750 +v 0.038213 0.031250 -0.343750 +v -0.014705 -0.593750 0.531250 +v -0.027104 -0.593750 0.656250 +v -0.043147 -0.718750 0.656250 +v 0.006958 -0.593750 0.031250 +v 0.006061 -0.593750 0.156250 +v -0.011715 -0.718750 0.156250 +v 0.047072 0.156250 -0.218750 +v 0.052848 0.156250 -0.093750 +v 0.053218 0.031250 -0.093750 +v 0.052233 -0.093750 0.031250 +v 0.051136 -0.093750 0.156250 +v 0.044498 -0.218750 0.156250 +v -0.048461 -0.093750 -0.968750 +v -0.027730 -0.093750 -0.843750 +v -0.032689 -0.218750 -0.843750 +v 0.008559 -0.343750 -0.468750 +v 0.020025 -0.343750 -0.343750 +v 0.007757 -0.468750 -0.343750 +v 0.028520 -0.343750 -0.218750 +v 0.033757 -0.343750 -0.093750 +v 0.020862 -0.468750 -0.093750 +v 0.000637 -0.593750 -0.218750 +v 0.005365 -0.593750 -0.093750 +v -0.012372 -0.718750 -0.093750 +v 0.044614 -0.093750 -0.218750 +v 0.050289 -0.093750 -0.093750 +v 0.043686 -0.218750 -0.093750 +v -0.060283 -0.343750 -0.968750 +v -0.040329 -0.343750 -0.843750 +v -0.050462 -0.468750 -0.843750 +v -0.021967 -0.343750 -0.718750 +v -0.005553 -0.343750 -0.593750 +v -0.016837 -0.468750 -0.593750 +v -0.010870 -0.406250 -0.593750 +v -0.003632 -0.406250 -0.531250 +v -0.009738 -0.468750 -0.531250 +v -0.000922 -0.281250 -0.593750 +v 0.006558 -0.281250 -0.531250 +v 0.001812 -0.343750 -0.531250 +v -0.017575 -0.281250 -0.718750 +v -0.008981 -0.281250 -0.656250 +v -0.013494 -0.343750 -0.656250 +v -0.045098 -0.406250 -0.843750 +v -0.035836 -0.406250 -0.781250 +v -0.041357 -0.468750 -0.781250 +v -0.036184 -0.281250 -0.843750 +v -0.026657 -0.281250 -0.781250 +v -0.030927 -0.343750 -0.781250 +v -0.056391 -0.281250 -0.968750 +v -0.046111 -0.281250 -0.906250 +v -0.050129 -0.343750 -0.906250 +v 0.047426 -0.156250 -0.093750 +v 0.048851 -0.156250 -0.031250 +v 0.045079 -0.218750 -0.031250 +v 0.052233 -0.031250 -0.093750 +v 0.053715 -0.031250 -0.031250 +v 0.051744 -0.093750 -0.031250 +v 0.046483 -0.031250 -0.218750 +v 0.049808 -0.031250 -0.156250 +v 0.047899 -0.093750 -0.156250 +v -0.003246 -0.656250 -0.093750 +v -0.002086 -0.656250 -0.031250 +v -0.011246 -0.718750 -0.031250 +v 0.013416 -0.531250 -0.093750 +v 0.014644 -0.531250 -0.031250 +v 0.006559 -0.593750 -0.031250 +v 0.008559 -0.531250 -0.218750 +v 0.011382 -0.531250 -0.156250 +v 0.003386 -0.593750 -0.156250 +v 0.027658 -0.406250 -0.093750 +v 0.028952 -0.406250 -0.031250 +v 0.022123 -0.468750 -0.031250 +v 0.039115 -0.281250 -0.093750 +v 0.040475 -0.281250 -0.031250 +v 0.035084 -0.343750 -0.031250 +v 0.033757 -0.281250 -0.218750 +v 0.036867 -0.281250 -0.156250 +v 0.031561 -0.343750 -0.156250 +v 0.014234 -0.406250 -0.343750 +v 0.018774 -0.406250 -0.281250 +v 0.012194 -0.468750 -0.281250 +v 0.025088 -0.281250 -0.343750 +v 0.029819 -0.281250 -0.281250 +v 0.024663 -0.343750 -0.281250 +v 0.013416 -0.281250 -0.468750 +v 0.019607 -0.281250 -0.406250 +v 0.014643 -0.343750 -0.406250 +v -0.029865 -0.156250 -0.843750 +v -0.020144 -0.156250 -0.781250 +v -0.023055 -0.218750 -0.781250 +v -0.026299 -0.031250 -0.843750 +v -0.016467 -0.031250 -0.781250 +v -0.017943 -0.093750 -0.781250 +v -0.047120 -0.031250 -0.968750 +v -0.036532 -0.031250 -0.906250 +v -0.037918 -0.093750 -0.906250 +v 0.048255 -0.156250 0.156250 +v 0.046366 -0.156250 0.218750 +v 0.042648 -0.218750 0.218750 +v 0.053094 -0.031250 0.156250 +v 0.051136 -0.031250 0.218750 +v 0.049209 -0.093750 0.218750 +v 0.054214 -0.031250 0.031250 +v 0.054089 -0.031250 0.093750 +v 0.052111 -0.093750 0.093750 +v 0.053342 0.093750 -0.093750 +v 0.054844 0.093750 -0.031250 +v 0.054718 0.031250 -0.031250 +v 0.051379 0.218750 -0.093750 +v 0.052848 0.218750 -0.031250 +v 0.054340 0.156250 -0.031250 +v 0.045663 0.218750 -0.218750 +v 0.048970 0.218750 -0.156250 +v 0.050410 0.156250 -0.156250 +v -0.002570 -0.656250 0.156250 +v -0.004113 -0.656250 0.218750 +v -0.013214 -0.718750 0.218750 +v 0.014132 -0.531250 0.156250 +v 0.012499 -0.531250 0.218750 +v 0.004473 -0.593750 0.218750 +v 0.015054 -0.531250 0.031250 +v 0.014951 -0.531250 0.093750 +v 0.006858 -0.593750 0.093750 +v -0.034877 -0.656250 0.656250 +v -0.041784 -0.656250 0.718750 +v -0.049879 -0.718750 0.718750 +v -0.019869 -0.531250 0.656250 +v -0.027104 -0.531250 0.718750 +v -0.034178 -0.593750 0.718750 +v -0.007176 -0.531250 0.531250 +v -0.013214 -0.531250 0.593750 +v -0.020600 -0.593750 0.593750 +v 0.038325 0.093750 -0.343750 +v 0.043340 0.093750 -0.281250 +v 0.043224 0.031250 -0.281250 +v 0.036531 0.218750 -0.343750 +v 0.041502 0.218750 -0.281250 +v 0.042879 0.156250 -0.281250 +v 0.024344 0.218750 -0.468750 +v 0.030797 0.218750 -0.406250 +v 0.032108 0.156250 -0.406250 +v 0.046483 0.343750 0.156250 +v 0.044614 0.343750 0.218750 +v 0.047899 0.281250 0.218750 +v 0.037315 0.468750 0.156250 +v 0.035529 0.468750 0.218750 +v 0.040475 0.406250 0.218750 +v 0.038325 0.468750 0.031250 +v 0.038213 0.468750 0.093750 +v 0.043224 0.406250 0.093750 +v 0.008559 0.343750 0.656250 +v 0.000638 0.343750 0.718750 +v 0.003386 0.281250 0.718750 +v 0.000638 0.468750 0.656250 +v -0.007081 0.468750 0.718750 +v -0.002860 0.406250 0.718750 +v 0.014234 0.468750 0.531250 +v 0.007757 0.468750 0.593750 +v 0.012194 0.406250 0.593750 +v 0.010068 -0.156250 0.656250 +v 0.002107 -0.156250 0.718750 +v -0.001019 -0.218750 0.718750 +v 0.014132 -0.031250 0.656250 +v 0.006061 -0.031250 0.718750 +v 0.004473 -0.093750 0.718750 +v 0.028412 -0.031250 0.531250 +v 0.021597 -0.031250 0.593750 +v 0.019921 -0.093750 0.593750 +v -0.031191 0.343750 -0.843750 +v -0.021512 0.343750 -0.781250 +v -0.018954 0.281250 -0.781250 +v -0.038177 0.468750 -0.843750 +v -0.028710 0.468750 -0.781250 +v -0.024771 0.406250 -0.781250 +v -0.058261 0.468750 -0.968750 +v -0.048042 0.468750 -0.906250 +v -0.044336 0.406250 -0.906250 +v 0.031233 0.343750 -0.343750 +v 0.036085 0.343750 -0.281250 +v 0.039228 0.281250 -0.281250 +v 0.022650 0.468750 -0.343750 +v 0.027335 0.468750 -0.281250 +v 0.032108 0.406250 -0.281250 +v 0.011079 0.468750 -0.468750 +v 0.017218 0.468750 -0.406250 +v 0.021807 0.406250 -0.406250 +v 0.032876 -0.156250 -0.343750 +v 0.037763 -0.156250 -0.281250 +v 0.034198 -0.218750 -0.281250 +v 0.037314 -0.031250 -0.343750 +v 0.042304 -0.031250 -0.281250 +v 0.040475 -0.093750 -0.281250 +v 0.025088 -0.031250 -0.468750 +v 0.031561 -0.031250 -0.406250 +v 0.029818 -0.093750 -0.406250 +v -0.069807 -0.656250 -0.843750 +v -0.061248 -0.656250 -0.781250 +v -0.068868 -0.718750 -0.781250 +v -0.056391 -0.531250 -0.843750 +v -0.047456 -0.531250 -0.781250 +v -0.054098 -0.593750 -0.781250 +v -0.075386 -0.531250 -0.968750 +v -0.065716 -0.531250 -0.906250 +v -0.071989 -0.593750 -0.906250 +v -0.015355 -0.656250 -0.343750 +v -0.011246 -0.656250 -0.281250 +v -0.020144 -0.718750 -0.281250 +v 0.000637 -0.531250 -0.343750 +v 0.004968 -0.531250 -0.281250 +v -0.002860 -0.593750 -0.281250 +v -0.010116 -0.531250 -0.468750 +v -0.004402 -0.531250 -0.406250 +v -0.011997 -0.593750 -0.406250 +v -0.038263 -0.656250 -0.593750 +v -0.031633 -0.656250 -0.531250 +v -0.039986 -0.718750 -0.531250 +v -0.023417 -0.531250 -0.593750 +v -0.016467 -0.531250 -0.531250 +v -0.023779 -0.593750 -0.531250 +v -0.038953 -0.531250 -0.718750 +v -0.030927 -0.531250 -0.656250 +v -0.037918 -0.593750 -0.656250 +v 0.011079 0.593750 -0.343750 +v 0.015568 0.593750 -0.281250 +v 0.021807 0.531250 -0.281250 +v -0.003150 0.718750 -0.343750 +v 0.001126 0.718750 -0.281250 +v 0.008659 0.656250 -0.281250 +v -0.013774 0.718750 -0.468750 +v -0.008128 0.718750 -0.406250 +v -0.000825 0.656250 -0.406250 +v 0.024344 0.593750 -0.093750 +v 0.025622 0.593750 -0.031250 +v 0.032108 0.531250 -0.031250 +v 0.009463 0.718750 -0.093750 +v 0.010674 0.718750 -0.031250 +v 0.018462 0.656250 -0.031250 +v 0.004671 0.718750 -0.218750 +v 0.007457 0.718750 -0.156250 +v 0.015157 0.656250 -0.156250 +v 0.045663 0.343750 -0.093750 +v 0.047072 0.343750 -0.031250 +v 0.050410 0.281250 -0.031250 +v 0.036532 0.468750 -0.093750 +v 0.037876 0.468750 -0.031250 +v 0.042879 0.406250 -0.031250 +v 0.031233 0.468750 -0.218750 +v 0.034309 0.468750 -0.156250 +v 0.039228 0.406250 -0.156250 +v -0.047707 0.593750 -0.843750 +v -0.038522 0.593750 -0.781250 +v -0.033303 0.531250 -0.781250 +v -0.059556 0.718750 -0.843750 +v -0.050711 0.718750 -0.781250 +v -0.044336 0.656250 -0.781250 +v -0.078366 0.718750 -0.968750 +v -0.068789 0.718750 -0.906250 +v -0.062771 0.656250 -0.906250 +v -0.013774 0.593750 -0.593750 +v -0.006605 0.593750 -0.531250 +v -0.000825 0.531250 -0.531250 +v -0.026925 0.718750 -0.593750 +v -0.020052 0.718750 -0.531250 +v -0.013027 0.656250 -0.531250 +v -0.042296 0.718750 -0.718750 +v -0.034354 0.718750 -0.656250 +v -0.027641 0.656250 -0.656250 +v 0.004671 0.343750 -0.593750 +v 0.012296 0.343750 -0.531250 +v 0.015156 0.281250 -0.531250 +v -0.003150 0.468750 -0.593750 +v 0.004275 0.468750 -0.531250 +v 0.008659 0.406250 -0.531250 +v -0.019687 0.468750 -0.718750 +v -0.011152 0.468750 -0.656250 +v -0.006986 0.406250 -0.656250 +v 0.015054 0.093750 0.656250 +v 0.006958 0.093750 0.718750 +v 0.006858 0.031250 0.718750 +v 0.013416 0.218750 0.656250 +v 0.005365 0.218750 0.718750 +v 0.006559 0.156250 0.718750 +v 0.027658 0.218750 0.531250 +v 0.020862 0.218750 0.593750 +v 0.022123 0.156250 0.593750 +v -0.020509 0.093750 0.906250 +v -0.030573 0.093750 0.968750 +v -0.030661 0.031250 0.968750 +v -0.021966 0.218750 0.906250 +v -0.031985 0.218750 0.968750 +v -0.030926 0.156250 0.968750 +v -0.003246 0.218750 0.781250 +v -0.012372 0.218750 0.843750 +v -0.011246 0.156250 0.843750 +v -0.024951 -0.156250 0.906250 +v -0.034877 -0.156250 0.968750 +v -0.037658 -0.218750 0.968750 +v -0.021330 -0.031250 0.906250 +v -0.031368 -0.031250 0.968750 +v -0.032776 -0.093750 0.968750 +v -0.002570 -0.031250 0.781250 +v -0.011715 -0.031250 0.843750 +v -0.013214 -0.093750 0.843750 +v -0.010115 0.593750 0.656250 +v -0.017574 0.593750 0.718750 +v -0.011997 0.531250 0.718750 +v -0.023417 0.718750 0.656250 +v -0.030573 0.718750 0.718750 +v -0.023779 0.656250 0.718750 +v -0.010869 0.718750 0.531250 +v -0.016836 0.718750 0.593750 +v -0.009738 0.656250 0.593750 +v -0.043062 0.593750 0.906250 +v -0.052450 0.593750 0.968750 +v -0.047455 0.531250 0.968750 +v -0.055083 0.718750 0.906250 +v -0.064127 0.718750 0.968750 +v -0.058018 0.656250 0.968750 +v -0.038263 0.718750 0.781250 +v -0.046447 0.718750 0.843750 +v -0.039985 0.656250 0.843750 +v -0.026299 0.343750 0.906250 +v -0.036184 0.343750 0.968750 +v -0.033741 0.281250 0.968750 +v -0.033391 0.468750 0.906250 +v -0.043062 0.468750 0.968750 +v -0.039298 0.406250 0.968750 +v -0.015355 0.468750 0.781250 +v -0.024140 0.468750 0.843750 +v -0.020144 0.406250 0.843750 +v 0.025089 0.593750 0.156250 +v 0.023390 0.593750 0.218750 +v 0.029819 0.531250 0.218750 +v 0.010169 0.718750 0.156250 +v 0.008559 0.718750 0.218750 +v 0.016288 0.656250 0.218750 +v 0.011079 0.718750 0.031250 +v 0.010977 0.718750 0.093750 +v 0.018774 0.656250 0.093750 +v 0.013416 0.593750 0.406250 +v 0.008559 0.593750 0.468750 +v 0.014644 0.531250 0.468750 +v -0.000922 0.718750 0.406250 +v -0.005553 0.718750 0.468750 +v 0.001812 0.656250 0.468750 +v 0.006160 0.718750 0.281250 +v 0.002992 0.718750 0.343750 +v 0.010573 0.656250 0.343750 +v 0.033757 0.343750 0.406250 +v 0.028520 0.343750 0.468750 +v 0.031561 0.281250 0.468750 +v 0.025089 0.468750 0.406250 +v 0.020025 0.468750 0.468750 +v 0.024663 0.406250 0.468750 +v 0.032876 0.468750 0.281250 +v 0.029385 0.468750 0.343750 +v 0.034199 0.406250 0.343750 +v -0.007176 -0.406250 0.656250 +v -0.014705 -0.406250 0.718750 +v -0.020600 -0.468750 0.718750 +v 0.002894 -0.281250 0.656250 +v -0.004882 -0.281250 0.718750 +v -0.009454 -0.343750 0.718750 +v 0.016598 -0.281250 0.531250 +v 0.010068 -0.281250 0.593750 +v 0.005266 -0.343750 0.593750 +v -0.040414 -0.406250 0.906250 +v -0.049879 -0.406250 0.968750 +v -0.055164 -0.468750 0.968750 +v -0.031368 -0.281250 0.906250 +v -0.041100 -0.281250 0.968750 +v -0.045182 -0.343750 0.968750 +v -0.013214 -0.281250 0.781250 +v -0.022057 -0.281250 0.843750 +v -0.026388 -0.343750 0.843750 +v -0.065477 -0.656250 0.906250 +v -0.074231 -0.656250 0.968750 +v -0.081543 -0.718750 0.968750 +v -0.051871 -0.531250 0.906250 +v -0.061007 -0.531250 0.968750 +v -0.067374 -0.593750 0.968750 +v -0.034877 -0.531250 0.781250 +v -0.043147 -0.531250 0.843750 +v -0.049879 -0.593750 0.843750 +v 0.028412 -0.406250 0.156250 +v 0.026691 -0.406250 0.218750 +v 0.019920 -0.468750 0.218750 +v 0.039907 -0.281250 0.156250 +v 0.038100 -0.281250 0.218750 +v 0.032766 -0.343750 0.218750 +v 0.040931 -0.281250 0.031250 +v 0.040817 -0.281250 0.093750 +v 0.035418 -0.343750 0.093750 +v 0.016598 -0.406250 0.406250 +v 0.011687 -0.406250 0.468750 +v 0.005266 -0.468750 0.468750 +v 0.027550 -0.281250 0.406250 +v 0.022439 -0.281250 0.468750 +v 0.017425 -0.343750 0.468750 +v 0.035418 -0.281250 0.281250 +v 0.031889 -0.281250 0.343750 +v 0.026691 -0.343750 0.343750 +v -0.013214 -0.656250 0.406250 +v -0.017666 -0.656250 0.468750 +v -0.026388 -0.718750 0.468750 +v 0.002894 -0.531250 0.406250 +v -0.001795 -0.531250 0.468750 +v -0.009454 -0.593750 0.468750 +v 0.010068 -0.531250 0.281250 +v 0.006858 -0.531250 0.343750 +v -0.001019 -0.593750 0.343750 +v 0.054214 0.093750 0.156250 +v 0.052233 0.093750 0.218750 +v 0.052111 0.031250 0.218750 +v 0.052233 0.218750 0.156250 +v 0.050289 0.218750 0.218750 +v 0.051744 0.156250 0.218750 +v 0.053342 0.218750 0.031250 +v 0.053218 0.218750 0.093750 +v 0.054718 0.156250 0.093750 +v 0.040931 0.093750 0.406250 +v 0.035529 0.093750 0.468750 +v 0.035418 0.031250 0.468750 +v 0.039115 0.218750 0.406250 +v 0.033757 0.218750 0.468750 +v 0.035085 0.156250 0.468750 +v 0.047426 0.218750 0.281250 +v 0.043686 0.218750 0.343750 +v 0.045079 0.156250 0.343750 +v 0.035418 -0.156250 0.406250 +v 0.030144 -0.156250 0.468750 +v 0.026691 -0.218750 0.468750 +v 0.039908 -0.031250 0.406250 +v 0.034531 -0.031250 0.468750 +v 0.032766 -0.093750 0.468750 +v 0.048255 -0.031250 0.281250 +v 0.044498 -0.031250 0.343750 +v 0.042649 -0.093750 0.343750 +v -0.025491 0.093750 -0.843750 +v -0.015634 0.093750 -0.781250 +v -0.015726 0.031250 -0.781250 +v -0.026926 0.218750 -0.843750 +v -0.017114 0.218750 -0.781250 +v -0.016004 0.156250 -0.781250 +v -0.047707 0.218750 -0.968750 +v -0.037139 0.218750 -0.906250 +v -0.036097 0.156250 -0.906250 +v 0.011078 0.093750 -0.593750 +v 0.018878 0.093750 -0.531250 +v 0.018774 0.031250 -0.531250 +v 0.009463 0.218750 -0.593750 +v 0.017218 0.218750 -0.531250 +v 0.018462 0.156250 -0.531250 +v -0.007748 0.218750 -0.718750 +v 0.001126 0.218750 -0.656250 +v 0.002303 0.156250 -0.656250 +v 0.006160 -0.156250 -0.593750 +v 0.013825 -0.156250 -0.531250 +v 0.010573 -0.218750 -0.531250 +v 0.010169 -0.031250 -0.593750 +v 0.017943 -0.031250 -0.531250 +v 0.016288 -0.093750 -0.531250 +v -0.007081 -0.031250 -0.718750 +v 0.001812 -0.031250 -0.656250 +v 0.000247 -0.093750 -0.656250 +v -0.010870 -0.156250 -0.718750 +v -0.002086 -0.156250 -0.656250 +v -0.005170 -0.218750 -0.656250 +v -0.006223 0.093750 -0.718750 +v 0.002696 0.093750 -0.656250 +v 0.002598 0.031250 -0.656250 +v -0.046363 0.093750 -0.968750 +v -0.035749 0.093750 -0.906250 +v -0.035836 0.031250 -0.906250 +v 0.043571 -0.156250 0.281250 +v 0.039908 -0.156250 0.343750 +v 0.036308 -0.218750 0.343750 +v 0.049329 0.093750 0.281250 +v 0.045546 0.093750 0.343750 +v 0.045429 0.031250 0.343750 +v 0.055355 0.093750 0.031250 +v 0.055227 0.093750 0.093750 +v 0.055099 0.031250 0.093750 +v -0.006414 -0.656250 0.281250 +v -0.009454 -0.656250 0.343750 +v -0.018402 -0.718750 0.343750 +v 0.024132 -0.406250 0.281250 +v 0.020758 -0.406250 0.343750 +v 0.014132 -0.468750 0.343750 +v 0.029385 -0.406250 0.031250 +v 0.029277 -0.406250 0.093750 +v 0.022439 -0.468750 0.093750 +v -0.049212 -0.656250 0.781250 +v -0.057124 -0.656250 0.843750 +v -0.064842 -0.718750 0.843750 +v -0.022783 -0.406250 0.781250 +v -0.031368 -0.406250 0.843750 +v -0.036965 -0.468750 0.843750 +v 0.006061 -0.406250 0.531250 +v -0.000240 -0.406250 0.593750 +v -0.006413 -0.468750 0.593750 +v 0.041845 0.343750 0.281250 +v 0.038213 0.343750 0.343750 +v 0.041387 0.281250 0.343750 +v 0.020862 0.593750 0.281250 +v 0.017528 0.593750 0.343750 +v 0.023814 0.531250 0.343750 +v 0.026049 0.593750 0.031250 +v 0.025942 0.593750 0.093750 +v 0.032437 0.531250 0.093750 +v -0.007843 0.343750 0.781250 +v -0.016836 0.343750 0.843750 +v -0.014240 0.281250 0.843750 +v -0.025581 0.593750 0.781250 +v -0.034091 0.593750 0.843750 +v -0.028799 0.531250 0.843750 +v 0.002992 0.593750 0.531250 +v -0.003246 0.593750 0.593750 +v 0.002598 0.531250 0.593750 +v -0.006413 -0.156250 0.781250 +v -0.015448 -0.156250 0.843750 +v -0.018402 -0.218750 0.843750 +v -0.001699 0.093750 0.781250 +v -0.010869 0.093750 0.843750 +v -0.010963 0.031250 0.843750 +v 0.029385 0.093750 0.531250 +v 0.022545 0.093750 0.593750 +v 0.022439 0.031250 0.593750 +v -0.012278 0.343750 -0.718750 +v -0.003536 0.343750 -0.656250 +v -0.000825 0.281250 -0.656250 +v -0.029776 0.593750 -0.718750 +v -0.021512 0.593750 -0.656250 +v -0.016004 0.531250 -0.656250 +v -0.067217 0.593750 -0.968750 +v -0.057287 0.593750 -0.906250 +v -0.052368 0.531250 -0.906250 +v 0.040134 0.343750 -0.218750 +v 0.043340 0.343750 -0.156250 +v 0.046601 0.281250 -0.156250 +v 0.019294 0.593750 -0.218750 +v 0.022228 0.593750 -0.156250 +v 0.028628 0.531250 -0.156250 +v -0.000046 0.593750 -0.468750 +v 0.005862 0.593750 -0.406250 +v 0.011889 0.531250 -0.406250 +v -0.053111 -0.656250 -0.718750 +v -0.045436 -0.656250 -0.656250 +v -0.053440 -0.718750 -0.656250 +v -0.025581 -0.656250 -0.468750 +v -0.020144 -0.656250 -0.406250 +v -0.028799 -0.718750 -0.406250 +v -0.088022 -0.656250 -0.968750 +v -0.078746 -0.656250 -0.906250 +v -0.085952 -0.718750 -0.906250 +v 0.020862 -0.156250 -0.468750 +v 0.027228 -0.156250 -0.406250 +v 0.023813 -0.218750 -0.406250 +v 0.019294 0.343750 -0.468750 +v 0.025622 0.343750 -0.406250 +v 0.028628 0.281250 -0.406250 +v -0.051706 0.343750 -0.968750 +v -0.041271 0.343750 -0.906250 +v -0.038867 0.281250 -0.906250 +v 0.024132 -0.156250 0.531250 +v 0.017425 -0.156250 0.593750 +v 0.014132 -0.218750 0.593750 +v 0.022545 0.343750 0.531250 +v 0.015876 0.343750 0.593750 +v 0.018774 0.281250 0.593750 +v 0.047544 0.343750 0.031250 +v 0.047426 0.343750 0.093750 +v 0.050772 0.281250 0.093750 +v 0.026049 0.093750 -0.468750 +v 0.032547 0.093750 -0.406250 +v 0.032437 0.031250 -0.406250 +v -0.022783 -0.656250 0.531250 +v -0.028532 -0.656250 0.593750 +v -0.036965 -0.718750 0.593750 +v -0.001699 -0.656250 0.031250 +v -0.001796 -0.656250 0.093750 +v -0.010964 -0.718750 0.093750 +v 0.047544 0.093750 -0.218750 +v 0.050893 0.093750 -0.156250 +v 0.050772 0.031250 -0.156250 +v 0.049329 -0.156250 0.031250 +v 0.049209 -0.156250 0.093750 +v 0.045429 -0.218750 0.093750 +v -0.050462 -0.156250 -0.968750 +v -0.039986 -0.156250 -0.906250 +v -0.042722 -0.218750 -0.906250 +v 0.002992 -0.406250 -0.468750 +v 0.008960 -0.406250 -0.406250 +v 0.002598 -0.468750 -0.406250 +v 0.022545 -0.406250 -0.218750 +v 0.025515 -0.406250 -0.156250 +v 0.018774 -0.468750 -0.156250 +v -0.007843 -0.656250 -0.218750 +v -0.005170 -0.656250 -0.156250 +v -0.014240 -0.718750 -0.156250 +v 0.041845 -0.156250 -0.218750 +v 0.045079 -0.156250 -0.156250 +v 0.041387 -0.218750 -0.156250 +v -0.064764 -0.406250 -0.968750 +v -0.054755 -0.406250 -0.906250 +v -0.059960 -0.468750 -0.906250 +v -0.027015 -0.406250 -0.718750 +v -0.018678 -0.406250 -0.656250 +v -0.024501 -0.468750 -0.656250 +v -0.081468 0.750000 -0.968750 +v -0.067610 0.531250 -1.000000 +v -0.052368 0.531250 1.000000 +v -0.041784 0.750000 0.781250 +v -0.074848 -0.468750 -1.000000 +v -0.059960 -0.468750 1.000000 +v 0.000638 0.750000 -0.218750 +v 0.014951 -0.531250 -0.000000 +v 0.038213 0.468750 0.000000 +v 0.037763 -0.250000 0.281250 +v -0.015634 -0.250000 -0.718750 +v -0.051872 0.031250 -1.000000 +v 0.006958 0.750000 0.031250 +v -0.042722 -0.218750 1.000000 +v -0.058424 -0.218750 -1.000000 +v -0.035836 0.031250 1.000000 +v -0.054673 -0.250000 -0.968750 +v 0.043340 -0.250000 0.031250 +v 0.010977 0.718750 0.000000 +v 0.040817 -0.281250 -0.000000 +v -0.017574 0.750000 -0.468750 +v -0.085951 -0.718750 1.000000 +v -0.099654 -0.718750 -1.000000 +v 0.002107 0.750000 0.281250 +v -0.014705 0.750000 0.531250 +v -0.038867 0.281250 1.000000 +v -0.054755 0.281250 -1.000000 +v -0.045773 0.750000 -0.718750 +v 0.015567 -0.250000 -0.468750 +v 0.018774 -0.250000 0.531250 +v 0.053218 0.218750 -0.000000 +v 0.054089 -0.031250 -0.000000 +v -0.015634 -0.750000 0.031250 +v -0.035836 -0.750000 0.531250 +v 0.019607 -0.281250 0.500000 +v -0.011246 -0.250000 0.781250 +v 0.052233 0.250000 0.031250 +v 0.026691 0.250000 0.531250 +v -0.008128 0.718750 0.500000 +v 0.030797 0.218750 0.500000 +v -0.048461 0.250000 -0.968750 +v 0.023390 0.250000 -0.468750 +v -0.016836 0.718750 -0.500000 +v 0.020862 0.218750 -0.500000 +v -0.098660 -0.750000 -0.968750 +v -0.038522 -0.750000 -0.468750 +v 0.010068 -0.281250 -0.500000 +v 0.036085 -0.250000 -0.218750 +v -0.020144 -0.750000 0.281250 +v -0.061248 -0.750000 0.781250 +v -0.004402 -0.531250 0.500000 +v 0.046366 0.250000 0.281250 +v -0.004113 0.250000 0.781250 +v 0.017218 0.468750 0.500000 +v 0.031561 -0.031250 0.500000 +v -0.008602 0.250000 -0.718750 +v 0.044614 0.250000 -0.218750 +v 0.007757 0.468750 -0.500000 +v 0.021597 -0.031250 -0.500000 +v -0.065002 -0.750000 -0.718750 +v -0.021512 -0.750000 -0.218750 +v -0.013214 -0.531250 -0.500000 +v -0.006605 -0.500000 -0.468750 +v 0.012296 -0.500000 -0.218750 +v 0.031889 -0.281250 -0.250000 +v 0.006858 -0.531250 -0.250000 +v -0.072532 -0.500000 -0.968750 +v -0.035749 -0.500000 -0.718750 +v -0.022058 -0.281250 -0.750000 +v -0.043148 -0.531250 -0.750000 +v 0.025622 0.000000 -0.468750 +v 0.047072 0.000000 -0.218750 +v 0.043686 0.218750 -0.250000 +v 0.044497 -0.031250 -0.250000 +v 0.008559 0.500000 -0.468750 +v 0.028520 0.500000 -0.218750 +v 0.002992 0.718750 -0.250000 +v 0.029385 0.468750 -0.250000 +v -0.060283 0.500000 -0.968750 +v -0.021967 0.500000 -0.718750 +v -0.046447 0.718750 -0.750000 +v -0.024140 0.468750 -0.750000 +v 0.028952 -0.000000 0.531250 +v -0.002086 -0.000000 0.781250 +v 0.001127 0.218750 0.750000 +v 0.001813 -0.031250 0.750000 +v 0.011687 0.500000 0.531250 +v -0.017666 0.500000 0.781250 +v -0.034354 0.718750 0.750000 +v -0.011152 0.468750 0.750000 +v 0.035529 0.500000 0.031250 +v 0.030144 0.500000 0.281250 +v 0.007457 0.718750 0.250000 +v 0.034309 0.468750 0.250000 +v -0.003632 -0.500000 0.531250 +v -0.031632 -0.500000 0.781250 +v -0.008981 -0.281250 0.750000 +v -0.030926 -0.531250 0.750000 +v 0.018878 -0.500000 0.031250 +v 0.013825 -0.500000 0.281250 +v 0.036867 -0.281250 0.250000 +v 0.011382 -0.531250 0.250000 +v 0.054844 -0.000000 0.031250 +v 0.048851 -0.000000 0.281250 +v 0.048970 0.218750 0.250000 +v 0.049808 -0.031250 0.250000 +v -0.046700 0.000000 -0.968750 +v -0.006605 0.000000 -0.718750 +v -0.012372 0.218750 -0.750000 +v -0.011716 -0.031250 -0.750000 +v -0.062851 0.750000 -0.843750 +v -0.077528 0.656250 -1.000000 +v -0.062771 0.656250 1.000000 +v -0.058424 0.750000 0.906250 +v -0.065478 -0.343750 -1.000000 +v -0.050129 -0.343750 1.000000 +v 0.005365 0.750000 -0.093750 +v -0.001796 -0.656250 -0.000000 +v 0.047426 0.343750 0.000000 +v 0.029819 -0.250000 0.406250 +v 0.001126 -0.250000 -0.593750 +v -0.052120 0.156250 -1.000000 +v 0.006061 0.750000 0.156250 +v -0.037917 -0.093750 1.000000 +v -0.053852 -0.093750 -1.000000 +v -0.036097 0.156250 1.000000 +v -0.034354 -0.250000 -0.843750 +v 0.042304 -0.250000 0.156250 +v 0.025942 0.593750 0.000000 +v 0.029277 -0.406250 -0.000000 +v -0.007081 0.750000 -0.343750 +v -0.071988 -0.593750 1.000000 +v -0.086323 -0.593750 -1.000000 +v -0.004882 0.750000 0.406250 +v -0.027104 0.750000 0.656250 +v -0.044336 0.406250 1.000000 +v -0.059960 0.406250 -1.000000 +v -0.030573 0.750000 -0.593750 +v 0.027335 -0.250000 -0.343750 +v 0.004968 -0.250000 0.656250 +v 0.055227 0.093750 -0.000000 +v 0.049209 -0.156250 -0.000000 +v -0.016467 -0.750000 0.156250 +v -0.047455 -0.750000 0.656250 +v 0.008961 -0.406250 0.500000 +v -0.029509 -0.250000 0.906250 +v 0.051136 0.250000 0.156250 +v 0.012499 0.250000 0.656250 +v 0.005862 0.593750 0.500000 +v 0.032547 0.093750 0.500000 +v -0.027730 0.250000 -0.843750 +v 0.035529 0.250000 -0.343750 +v -0.003246 0.593750 -0.500000 +v 0.022545 0.093750 -0.500000 +v -0.081092 -0.750000 -0.843750 +v -0.028710 -0.750000 -0.343750 +v -0.000241 -0.406250 -0.500000 +v 0.041502 -0.250000 -0.093750 +v -0.026657 -0.750000 0.406250 +v -0.076917 -0.750000 0.906250 +v -0.020144 -0.656250 0.500000 +v 0.038100 0.250000 0.406250 +v -0.022783 0.250000 0.906250 +v 0.025622 0.343750 0.500000 +v 0.027228 -0.156250 0.500000 +v 0.008559 0.250000 -0.593750 +v 0.050289 0.250000 -0.093750 +v 0.015876 0.343750 -0.500000 +v 0.017425 -0.156250 -0.500000 +v -0.050711 -0.750000 -0.593750 +v -0.017113 -0.750000 -0.093750 +v -0.028532 -0.656250 -0.500000 +v 0.004275 -0.500000 -0.343750 +v 0.017218 -0.500000 -0.093750 +v 0.020757 -0.406250 -0.250000 +v -0.009454 -0.656250 -0.250000 +v -0.053358 -0.500000 -0.843750 +v -0.020053 -0.500000 -0.593750 +v -0.031368 -0.406250 -0.750000 +v -0.057124 -0.656250 -0.750000 +v 0.037875 0.000000 -0.343750 +v 0.052848 0.000000 -0.093750 +v 0.045546 0.093750 -0.250000 +v 0.039907 -0.156250 -0.250000 +v 0.020025 0.500000 -0.343750 +v 0.033757 0.500000 -0.093750 +v 0.017528 0.593750 -0.250000 +v 0.038213 0.343750 -0.250000 +v -0.040329 0.500000 -0.843750 +v -0.005553 0.500000 -0.593750 +v -0.034091 0.593750 -0.750000 +v -0.016837 0.343750 -0.750000 +v 0.014644 -0.000000 0.656250 +v -0.020874 -0.000000 0.906250 +v 0.002697 0.093750 0.750000 +v -0.002086 -0.156250 0.750000 +v -0.001796 0.500000 0.656250 +v -0.035575 0.500000 0.906250 +v -0.021512 0.593750 0.750000 +v -0.003535 0.343750 0.750000 +v 0.034530 0.500000 0.156250 +v 0.022439 0.500000 0.406250 +v 0.022228 0.593750 0.250000 +v 0.043340 0.343750 0.250000 +v -0.016467 -0.500000 0.656250 +v -0.048795 -0.500000 0.906250 +v -0.018678 -0.406250 0.750000 +v -0.045435 -0.656250 0.750000 +v 0.017943 -0.500000 0.156250 +v 0.006559 -0.500000 0.406250 +v 0.025515 -0.406250 0.250000 +v -0.005170 -0.656250 0.250000 +v 0.053715 -0.000000 0.156250 +v 0.040475 -0.000000 0.406250 +v 0.050894 0.093750 0.250000 +v 0.045079 -0.156250 0.250000 +v -0.025850 0.000000 -0.843750 +v 0.010674 0.000000 -0.593750 +v -0.010870 0.093750 -0.750000 +v -0.015448 -0.156250 -0.750000 +v -0.009643 -0.125000 -0.718750 +v 0.007457 -0.125000 -0.593750 +v 0.006061 -0.031250 -0.625000 +v 0.002107 -0.156250 -0.625000 +v -0.006318 0.125000 -0.718750 +v 0.010977 0.125000 -0.593750 +v 0.005365 0.218750 -0.625000 +v 0.006957 0.093750 -0.625000 +v -0.046447 0.125000 -0.968750 +v -0.025581 0.125000 -0.843750 +v -0.031985 0.218750 -0.875000 +v -0.030573 0.093750 -0.875000 +v 0.045079 -0.125000 0.281250 +v 0.036867 -0.125000 0.406250 +v 0.042304 -0.031250 0.375000 +v 0.037763 -0.156250 0.375000 +v 0.049209 0.125000 0.281250 +v 0.040817 0.125000 0.406250 +v 0.041502 0.218750 0.375000 +v 0.043340 0.093750 0.375000 +v 0.055227 0.125000 0.031250 +v 0.054089 0.125000 0.156250 +v 0.052848 0.218750 0.125000 +v 0.054845 0.093750 0.125000 +v -0.002086 -0.625000 0.281250 +v -0.008981 -0.625000 0.406250 +v 0.004968 -0.531250 0.375000 +v -0.011246 -0.656250 0.375000 +v 0.027228 -0.375000 0.281250 +v 0.019607 -0.375000 0.406250 +v 0.029819 -0.281250 0.375000 +v 0.018774 -0.406250 0.375000 +v 0.032547 -0.375000 0.031250 +v 0.031561 -0.375000 0.156250 +v 0.040475 -0.281250 0.125000 +v 0.028952 -0.406250 0.125000 +v -0.045435 -0.625000 0.781250 +v -0.061890 -0.625000 0.906250 +v -0.047455 -0.531250 0.875000 +v -0.061248 -0.656250 0.875000 +v -0.020144 -0.375000 0.781250 +v -0.037917 -0.375000 0.906250 +v -0.026657 -0.281250 0.875000 +v -0.035836 -0.406250 0.875000 +v 0.008961 -0.375000 0.531250 +v -0.004402 -0.375000 0.656250 +v 0.006559 -0.281250 0.625000 +v -0.003632 -0.406250 0.625000 +v 0.039907 0.375000 0.281250 +v 0.031889 0.375000 0.406250 +v 0.027335 0.468750 0.375000 +v 0.036085 0.343750 0.375000 +v 0.017425 0.625000 0.281250 +v 0.010068 0.625000 0.406250 +v 0.001126 0.718750 0.375000 +v 0.015568 0.593750 0.375000 +v 0.022545 0.625000 0.031250 +v 0.021597 0.625000 0.156250 +v 0.010674 0.718750 0.125000 +v 0.025622 0.593750 0.125000 +v -0.009454 0.375000 0.781250 +v -0.027819 0.375000 0.906250 +v -0.028710 0.468750 0.875000 +v -0.021512 0.343750 0.875000 +v -0.028532 0.625000 0.781250 +v -0.045857 0.625000 0.906250 +v -0.050711 0.718750 0.875000 +v -0.038522 0.593750 0.875000 +v -0.000241 0.625000 0.531250 +v -0.013214 0.625000 0.656250 +v -0.020052 0.718750 0.625000 +v -0.006605 0.593750 0.625000 +v -0.005170 -0.125000 0.781250 +v -0.023779 -0.125000 0.906250 +v -0.016467 -0.031250 0.875000 +v -0.020144 -0.156250 0.875000 +v -0.001795 0.125000 0.781250 +v -0.020600 0.125000 0.906250 +v -0.017113 0.218750 0.875000 +v -0.015633 0.093750 0.875000 +v 0.029277 0.125000 0.531250 +v 0.014951 0.125000 0.656250 +v 0.017218 0.218750 0.625000 +v 0.018878 0.093750 0.625000 +v -0.013867 0.375000 -0.718750 +v 0.002992 0.375000 -0.593750 +v -0.007081 0.468750 -0.625000 +v 0.000638 0.343750 -0.625000 +v -0.032688 0.625000 -0.718750 +v -0.016836 0.625000 -0.593750 +v -0.030573 0.718750 -0.625000 +v -0.017574 0.593750 -0.625000 +v -0.069807 0.625000 -0.968750 +v -0.050462 0.625000 -0.843750 +v -0.064127 0.718750 -0.875000 +v -0.052450 0.593750 -0.875000 +v 0.038213 0.375000 -0.218750 +v 0.043686 0.375000 -0.093750 +v 0.035529 0.468750 -0.125000 +v 0.044614 0.343750 -0.125000 +v 0.015876 0.625000 -0.218750 +v 0.020862 0.625000 -0.093750 +v 0.008559 0.718750 -0.125000 +v 0.023390 0.593750 -0.125000 +v -0.003246 0.625000 -0.468750 +v 0.007757 0.625000 -0.343750 +v -0.005553 0.718750 -0.375000 +v 0.008559 0.593750 -0.375000 +v -0.049380 -0.625000 -0.718750 +v -0.034354 -0.625000 -0.593750 +v -0.027105 -0.531250 -0.625000 +v -0.041784 -0.656250 -0.625000 +v -0.021512 -0.625000 -0.468750 +v -0.011152 -0.625000 -0.343750 +v -0.001796 -0.531250 -0.375000 +v -0.017667 -0.656250 -0.375000 +v -0.084688 -0.625000 -0.968750 +v -0.066270 -0.625000 -0.843750 +v -0.061007 -0.531250 -0.875000 +v -0.074232 -0.656250 -0.875000 +v 0.022228 -0.125000 -0.468750 +v 0.034309 -0.125000 -0.343750 +v 0.034530 -0.031250 -0.375000 +v 0.030144 -0.156250 -0.375000 +v 0.017528 0.375000 -0.468750 +v 0.029385 0.375000 -0.343750 +v 0.020025 0.468750 -0.375000 +v 0.028520 0.343750 -0.375000 +v -0.053111 0.375000 -0.968750 +v -0.032689 0.375000 -0.843750 +v -0.043063 0.468750 -0.875000 +v -0.036184 0.343750 -0.875000 +v 0.025515 -0.125000 0.531250 +v 0.011383 -0.125000 0.656250 +v 0.017943 -0.031250 0.625000 +v 0.013825 -0.156250 0.625000 +v 0.020758 0.375000 0.531250 +v 0.006858 0.375000 0.656250 +v 0.004275 0.468750 0.625000 +v 0.012296 0.343750 0.625000 +v 0.045546 0.375000 0.031250 +v 0.044498 0.375000 0.156250 +v 0.037876 0.468750 0.125000 +v 0.047072 0.343750 0.125000 +v 0.025942 0.125000 -0.468750 +v 0.038213 0.125000 -0.343750 +v 0.033757 0.218750 -0.375000 +v 0.035529 0.093750 -0.375000 +v -0.018678 -0.625000 0.531250 +v -0.030926 -0.625000 0.656250 +v -0.016467 -0.531250 0.625000 +v -0.031632 -0.656250 0.625000 +v 0.002697 -0.625000 0.031250 +v 0.001812 -0.625000 0.156250 +v 0.014644 -0.531250 0.125000 +v -0.002086 -0.656250 0.125000 +v 0.047426 0.125000 -0.218750 +v 0.053218 0.125000 -0.093750 +v 0.050289 0.218750 -0.125000 +v 0.052233 0.093750 -0.125000 +v 0.050893 -0.125000 0.031250 +v 0.049808 -0.125000 0.156250 +v 0.053715 -0.031250 0.125000 +v 0.048851 -0.156250 0.125000 +v -0.049380 -0.125000 -0.968750 +v -0.028710 -0.125000 -0.843750 +v -0.031368 -0.031250 -0.875000 +v -0.034878 -0.156250 -0.875000 +v 0.005862 -0.375000 -0.468750 +v 0.017218 -0.375000 -0.343750 +v 0.022439 -0.281250 -0.375000 +v 0.011686 -0.406250 -0.375000 +v 0.025622 -0.375000 -0.218750 +v 0.030797 -0.375000 -0.093750 +v 0.038100 -0.281250 -0.125000 +v 0.026691 -0.406250 -0.125000 +v -0.003536 -0.625000 -0.218750 +v 0.001126 -0.625000 -0.093750 +v 0.012499 -0.531250 -0.125000 +v -0.004113 -0.656250 -0.125000 +v 0.043340 -0.125000 -0.218750 +v 0.048970 -0.125000 -0.093750 +v 0.051136 -0.031250 -0.125000 +v 0.046366 -0.156250 -0.125000 +v -0.062451 -0.375000 -0.968750 +v -0.042637 -0.375000 -0.843750 +v -0.041100 -0.281250 -0.875000 +v -0.049880 -0.406250 -0.875000 +v -0.024411 -0.375000 -0.718750 +v -0.008128 -0.375000 -0.593750 +v -0.004882 -0.281250 -0.625000 +v -0.014705 -0.406250 -0.625000 +v -0.071988 0.750000 -0.906250 +v -0.072299 0.593750 -1.000000 +v -0.057287 0.593750 1.000000 +v -0.049879 0.750000 0.843750 +v -0.069886 -0.406250 -1.000000 +v -0.054754 -0.406250 1.000000 +v 0.003386 0.750000 -0.156250 +v 0.006858 -0.593750 -0.000000 +v 0.043224 0.406250 0.000000 +v 0.034199 -0.250000 0.343750 +v -0.006986 -0.250000 -0.656250 +v -0.051789 0.093750 -1.000000 +v 0.006858 0.750000 0.093750 +v -0.039985 -0.156250 1.000000 +v -0.055819 -0.156250 -1.000000 +v -0.035749 0.093750 1.000000 +v -0.044336 -0.250000 -0.906250 +v 0.043224 -0.250000 0.093750 +v 0.018774 0.656250 0.000000 +v 0.035418 -0.343750 -0.000000 +v -0.011997 0.750000 -0.406250 +v -0.078745 -0.656250 1.000000 +v -0.092773 -0.656250 -1.000000 +v -0.001019 0.750000 0.343750 +v -0.020601 0.750000 0.593750 +v -0.041271 0.343750 1.000000 +v -0.057043 0.343750 -1.000000 +v -0.037917 0.750000 -0.656250 +v 0.021807 -0.250000 -0.406250 +v 0.012194 -0.250000 0.593750 +v 0.054718 0.156250 -0.000000 +v 0.052111 -0.093750 -0.000000 +v -0.015726 -0.750000 0.093750 +v -0.041356 -0.750000 0.593750 +v 0.014644 -0.343750 0.500000 +v -0.020144 -0.250000 0.843750 +v 0.052111 0.250000 0.093750 +v 0.019921 0.250000 0.593750 +v -0.000825 0.656250 0.500000 +v 0.032108 0.156250 0.500000 +v -0.037918 0.250000 -0.906250 +v 0.029819 0.250000 -0.406250 +v -0.009738 0.656250 -0.500000 +v 0.022123 0.156250 -0.500000 +v -0.089712 -0.750000 -0.906250 +v -0.033303 -0.750000 -0.406250 +v 0.005265 -0.343750 -0.500000 +v 0.039228 -0.250000 -0.156250 +v -0.023055 -0.750000 0.343750 +v -0.068867 -0.750000 0.843750 +v -0.011997 -0.593750 0.500000 +v 0.042648 0.250000 0.343750 +v -0.013214 0.250000 0.843750 +v 0.021807 0.406250 0.500000 +v 0.029819 -0.093750 0.500000 +v 0.000247 0.250000 -0.656250 +v 0.047899 0.250000 -0.156250 +v 0.012194 0.406250 -0.500000 +v 0.019920 -0.093750 -0.500000 +v -0.057612 -0.750000 -0.656250 +v -0.018954 -0.750000 -0.156250 +v -0.020601 -0.593750 -0.500000 +v -0.000825 -0.500000 -0.406250 +v 0.015156 -0.500000 -0.156250 +v 0.026691 -0.343750 -0.250000 +v -0.001019 -0.593750 -0.250000 +v -0.062771 -0.500000 -0.906250 +v -0.027641 -0.500000 -0.656250 +v -0.026389 -0.343750 -0.750000 +v -0.049880 -0.593750 -0.750000 +v 0.032108 0.000000 -0.406250 +v 0.050410 0.000000 -0.156250 +v 0.045079 0.156250 -0.250000 +v 0.042648 -0.093750 -0.250000 +v 0.014644 0.500000 -0.406250 +v 0.031561 0.500000 -0.156250 +v 0.010573 0.656250 -0.250000 +v 0.034199 0.406250 -0.250000 +v -0.050129 0.500000 -0.906250 +v -0.013494 0.500000 -0.656250 +v -0.039985 0.656250 -0.750000 +v -0.020144 0.406250 -0.750000 +v 0.022123 -0.000000 0.593750 +v -0.011246 -0.000000 0.843750 +v 0.002303 0.156250 0.750000 +v 0.000247 -0.093750 0.750000 +v 0.005266 0.500000 0.593750 +v -0.026388 0.500000 0.843750 +v -0.027640 0.656250 0.750000 +v -0.006986 0.406250 0.750000 +v 0.035418 0.500000 0.093750 +v 0.026691 0.500000 0.343750 +v 0.015157 0.656250 0.250000 +v 0.039228 0.406250 0.250000 +v -0.009738 -0.500000 0.593750 +v -0.039985 -0.500000 0.843750 +v -0.013494 -0.343750 0.750000 +v -0.037917 -0.593750 0.750000 +v 0.018774 -0.500000 0.093750 +v 0.010573 -0.500000 0.343750 +v 0.031561 -0.343750 0.250000 +v 0.003386 -0.593750 0.250000 +v 0.054718 -0.000000 0.093750 +v 0.045079 -0.000000 0.343750 +v 0.050410 0.156250 0.250000 +v 0.047899 -0.093750 0.250000 +v -0.036097 0.000000 -0.906250 +v 0.002303 0.000000 -0.656250 +v -0.011246 0.156250 -0.750000 +v -0.013214 -0.093750 -0.750000 +v -0.054098 0.750000 -0.781250 +v -0.083269 0.718750 -1.000000 +v -0.068789 0.718750 1.000000 +v -0.067374 0.750000 0.968750 +v -0.061650 -0.281250 -1.000000 +v -0.046110 -0.281250 1.000000 +v 0.006559 0.750000 -0.031250 +v -0.010964 -0.718750 -0.000000 +v 0.050772 0.281250 0.000000 +v 0.024663 -0.250000 0.468750 +v 0.008659 -0.250000 -0.531250 +v -0.053111 0.218750 -1.000000 +v 0.004473 0.750000 0.218750 +v -0.036531 -0.031250 1.000000 +v -0.052533 -0.031250 -1.000000 +v -0.037138 0.218750 1.000000 +v -0.024771 -0.250000 -0.781250 +v 0.040475 -0.250000 0.218750 +v 0.032437 0.531250 0.000000 +v 0.022439 -0.468750 -0.000000 +v -0.002860 0.750000 -0.281250 +v -0.065715 -0.531250 1.000000 +v -0.080337 -0.531250 -1.000000 +v -0.009454 0.750000 0.468750 +v -0.034179 0.750000 0.718750 +v -0.048042 0.468750 1.000000 +v -0.063490 0.468750 -1.000000 +v -0.023779 0.750000 -0.531250 +v 0.032108 -0.250000 -0.281250 +v -0.002860 -0.250000 0.718750 +v 0.055099 0.031250 -0.000000 +v 0.045429 -0.218750 -0.000000 +v -0.017943 -0.750000 0.218750 +v -0.054098 -0.750000 0.718750 +v 0.002598 -0.468750 0.500000 +v -0.039297 -0.250000 0.968750 +v 0.049209 0.250000 0.218750 +v 0.004473 0.250000 0.718750 +v 0.011890 0.531250 0.500000 +v 0.032437 0.031250 0.500000 +v -0.017943 0.250000 -0.781250 +v 0.040475 0.250000 -0.281250 +v 0.002598 0.531250 -0.500000 +v 0.022439 0.031250 -0.500000 +v -0.072841 -0.750000 -0.781250 +v -0.024771 -0.750000 -0.281250 +v -0.006414 -0.468750 -0.500000 +v 0.042879 -0.250000 -0.031250 +v -0.030926 -0.750000 0.468750 +v -0.085357 -0.750000 0.968750 +v -0.028799 -0.718750 0.500000 +v 0.032766 0.250000 0.468750 +v -0.032776 0.250000 0.968750 +v 0.028628 0.281250 0.500000 +v 0.023814 -0.218750 0.500000 +v 0.016288 0.250000 -0.531250 +v 0.051744 0.250000 -0.031250 +v 0.018774 0.281250 -0.500000 +v 0.014131 -0.218750 -0.500000 +v -0.044336 -0.750000 -0.531250 +v -0.016004 -0.750000 -0.031250 +v -0.036966 -0.718750 -0.500000 +v 0.008659 -0.500000 -0.281250 +v 0.018462 -0.500000 -0.031250 +v 0.014131 -0.468750 -0.250000 +v -0.018403 -0.718750 -0.250000 +v -0.044336 -0.500000 -0.781250 +v -0.013027 -0.500000 -0.531250 +v -0.036966 -0.468750 -0.750000 +v -0.064843 -0.718750 -0.750000 +v 0.042879 0.000000 -0.281250 +v 0.054340 0.000000 -0.031250 +v 0.045429 0.031250 -0.250000 +v 0.036308 -0.218750 -0.250000 +v 0.024663 0.500000 -0.281250 +v 0.035085 0.500000 -0.031250 +v 0.023814 0.531250 -0.250000 +v 0.041387 0.281250 -0.250000 +v -0.030926 0.500000 -0.781250 +v 0.001812 0.500000 -0.531250 +v -0.028799 0.531250 -0.750000 +v -0.014240 0.281250 -0.750000 +v 0.006559 -0.000000 0.718750 +v -0.030926 -0.000000 0.968750 +v 0.002598 0.031250 0.750000 +v -0.005170 -0.218750 0.750000 +v -0.009454 0.500000 0.718750 +v -0.045182 0.500000 0.968750 +v -0.016004 0.531250 0.750000 +v -0.000825 0.281250 0.750000 +v 0.032766 0.500000 0.218750 +v 0.017425 0.500000 0.468750 +v 0.028628 0.531250 0.250000 +v 0.046601 0.281250 0.250000 +v -0.023779 -0.500000 0.718750 +v -0.058018 -0.500000 0.968750 +v -0.024501 -0.468750 0.750000 +v -0.053440 -0.718750 0.750000 +v 0.016288 -0.500000 0.218750 +v 0.001813 -0.500000 0.468750 +v 0.018774 -0.468750 0.250000 +v -0.014240 -0.718750 0.250000 +v 0.051744 -0.000000 0.218750 +v 0.035085 -0.000000 0.468750 +v 0.050772 0.031250 0.250000 +v 0.041387 -0.218750 0.250000 +v -0.016004 0.000000 -0.781250 +v 0.018462 0.000000 -0.531250 +v -0.010964 0.031250 -0.750000 +v -0.018403 -0.218750 -0.750000 +v -0.000825 -0.125000 -0.656250 +v 0.015156 -0.125000 -0.531250 +v 0.004473 -0.093750 -0.625000 +v -0.001019 -0.218750 -0.625000 +v 0.002598 0.125000 -0.656250 +v 0.018774 0.125000 -0.531250 +v 0.006559 0.156250 -0.625000 +v 0.006858 0.031250 -0.625000 +v -0.035836 0.125000 -0.906250 +v -0.015726 0.125000 -0.781250 +v -0.030926 0.156250 -0.875000 +v -0.030661 0.031250 -0.875000 +v 0.041388 -0.125000 0.343750 +v 0.031561 -0.125000 0.468750 +v 0.040475 -0.093750 0.375000 +v 0.034199 -0.218750 0.375000 +v 0.045429 0.125000 0.343750 +v 0.035418 0.125000 0.468750 +v 0.042879 0.156250 0.375000 +v 0.043224 0.031250 0.375000 +v 0.055099 0.125000 0.093750 +v 0.052111 0.125000 0.218750 +v 0.054340 0.156250 0.125000 +v 0.054718 0.031250 0.125000 +v -0.005170 -0.625000 0.343750 +v -0.013494 -0.625000 0.468750 +v -0.002860 -0.593750 0.375000 +v -0.020144 -0.718750 0.375000 +v 0.023814 -0.375000 0.343750 +v 0.014644 -0.375000 0.468750 +v 0.024663 -0.343750 0.375000 +v 0.012194 -0.468750 0.375000 +v 0.032437 -0.375000 0.093750 +v 0.029819 -0.375000 0.218750 +v 0.035085 -0.343750 0.125000 +v 0.022123 -0.468750 0.125000 +v -0.053440 -0.625000 0.843750 +v -0.070743 -0.625000 0.968750 +v -0.054098 -0.593750 0.875000 +v -0.068867 -0.718750 0.875000 +v -0.028799 -0.375000 0.843750 +v -0.047455 -0.375000 0.968750 +v -0.030926 -0.343750 0.875000 +v -0.041356 -0.468750 0.875000 +v 0.002598 -0.375000 0.593750 +v -0.011997 -0.375000 0.718750 +v 0.001813 -0.343750 0.625000 +v -0.009738 -0.468750 0.625000 +v 0.036308 0.375000 0.343750 +v 0.026691 0.375000 0.468750 +v 0.032108 0.406250 0.375000 +v 0.039228 0.281250 0.375000 +v 0.014132 0.625000 0.343750 +v 0.005266 0.625000 0.468750 +v 0.008659 0.656250 0.375000 +v 0.021807 0.531250 0.375000 +v 0.022439 0.625000 0.093750 +v 0.019920 0.625000 0.218750 +v 0.018462 0.656250 0.125000 +v 0.032108 0.531250 0.125000 +v -0.018403 0.375000 0.843750 +v -0.037658 0.375000 0.968750 +v -0.024771 0.406250 0.875000 +v -0.018953 0.281250 0.875000 +v -0.036965 0.625000 0.843750 +v -0.055164 0.625000 0.968750 +v -0.044336 0.656250 0.875000 +v -0.033303 0.531250 0.875000 +v -0.006414 0.625000 0.593750 +v -0.020601 0.625000 0.718750 +v -0.013027 0.656250 0.625000 +v -0.000825 0.531250 0.625000 +v -0.014240 -0.125000 0.843750 +v -0.033741 -0.125000 0.968750 +v -0.017943 -0.093750 0.875000 +v -0.023055 -0.218750 0.875000 +v -0.010963 0.125000 0.843750 +v -0.030661 0.125000 0.968750 +v -0.016004 0.156250 0.875000 +v -0.015726 0.031250 0.875000 +v 0.022439 0.125000 0.593750 +v 0.006858 0.125000 0.718750 +v 0.018462 0.156250 0.625000 +v 0.018774 0.031250 0.625000 +v -0.005170 0.375000 -0.656250 +v 0.010573 0.375000 -0.531250 +v -0.002860 0.406250 -0.625000 +v 0.003386 0.281250 -0.625000 +v -0.024501 0.625000 -0.656250 +v -0.009738 0.625000 -0.531250 +v -0.023779 0.656250 -0.625000 +v -0.011997 0.531250 -0.625000 +v -0.059960 0.625000 -0.906250 +v -0.041357 0.625000 -0.781250 +v -0.058018 0.656250 -0.875000 +v -0.047456 0.531250 -0.875000 +v 0.041387 0.375000 -0.156250 +v 0.045079 0.375000 -0.031250 +v 0.040475 0.406250 -0.125000 +v 0.047899 0.281250 -0.125000 +v 0.018774 0.625000 -0.156250 +v 0.022123 0.625000 -0.031250 +v 0.016288 0.656250 -0.125000 +v 0.029819 0.531250 -0.125000 +v 0.002598 0.625000 -0.406250 +v 0.012194 0.625000 -0.281250 +v 0.001812 0.656250 -0.375000 +v 0.014644 0.531250 -0.375000 +v -0.041613 -0.625000 -0.656250 +v -0.027641 -0.625000 -0.531250 +v -0.034179 -0.593750 -0.625000 +v -0.049880 -0.718750 -0.625000 +v -0.016004 -0.625000 -0.406250 +v -0.006986 -0.625000 -0.281250 +v -0.009454 -0.593750 -0.375000 +v -0.026388 -0.718750 -0.375000 +v -0.075309 -0.625000 -0.906250 +v -0.057612 -0.625000 -0.781250 +v -0.067375 -0.593750 -0.875000 +v -0.081544 -0.718750 -0.875000 +v 0.028628 -0.125000 -0.406250 +v 0.039228 -0.125000 -0.281250 +v 0.032766 -0.093750 -0.375000 +v 0.026691 -0.218750 -0.375000 +v 0.023814 0.375000 -0.406250 +v 0.034199 0.375000 -0.281250 +v 0.024663 0.406250 -0.375000 +v 0.031561 0.281250 -0.375000 +v -0.042722 0.375000 -0.906250 +v -0.023055 0.375000 -0.781250 +v -0.039298 0.406250 -0.875000 +v -0.033741 0.281250 -0.875000 +v 0.018774 -0.125000 0.593750 +v 0.003386 -0.125000 0.718750 +v 0.016288 -0.093750 0.625000 +v 0.010573 -0.218750 0.625000 +v 0.014132 0.375000 0.593750 +v -0.001019 0.375000 0.718750 +v 0.008659 0.406250 0.625000 +v 0.015157 0.281250 0.625000 +v 0.045429 0.375000 0.093750 +v 0.042648 0.375000 0.218750 +v 0.042879 0.406250 0.125000 +v 0.050410 0.281250 0.125000 +v 0.032437 0.125000 -0.406250 +v 0.043224 0.125000 -0.281250 +v 0.035084 0.156250 -0.375000 +v 0.035417 0.031250 -0.375000 +v -0.024501 -0.625000 0.593750 +v -0.037917 -0.625000 0.718750 +v -0.023779 -0.593750 0.625000 +v -0.039985 -0.718750 0.625000 +v 0.002598 -0.625000 0.093750 +v 0.000247 -0.625000 0.218750 +v 0.006559 -0.593750 0.125000 +v -0.011246 -0.718750 0.125000 +v 0.050772 0.125000 -0.156250 +v 0.054718 0.125000 -0.031250 +v 0.051744 0.156250 -0.125000 +v 0.052111 0.031250 -0.125000 +v 0.050772 -0.125000 0.093750 +v 0.047899 -0.125000 0.218750 +v 0.051744 -0.093750 0.125000 +v 0.045079 -0.218750 0.125000 +v -0.038867 -0.125000 -0.906250 +v -0.018954 -0.125000 -0.781250 +v -0.032777 -0.093750 -0.875000 +v -0.037658 -0.218750 -0.875000 +v 0.011889 -0.375000 -0.406250 +v 0.021807 -0.375000 -0.281250 +v 0.017425 -0.343750 -0.375000 +v 0.005266 -0.468750 -0.375000 +v 0.028628 -0.375000 -0.156250 +v 0.032108 -0.375000 -0.031250 +v 0.032766 -0.343750 -0.125000 +v 0.019920 -0.468750 -0.125000 +v -0.000825 -0.625000 -0.156250 +v 0.002303 -0.625000 -0.031250 +v 0.004473 -0.593750 -0.125000 +v -0.013214 -0.718750 -0.125000 +v 0.046601 -0.125000 -0.156250 +v 0.050410 -0.125000 -0.031250 +v 0.049209 -0.093750 -0.125000 +v 0.042648 -0.218750 -0.125000 +v -0.052368 -0.375000 -0.906250 +v -0.033303 -0.375000 -0.781250 +v -0.045182 -0.343750 -0.875000 +v -0.055165 -0.468750 -0.875000 +v -0.016004 -0.375000 -0.656250 +v -0.000825 -0.375000 -0.531250 +v -0.009455 -0.343750 -0.625000 +v -0.020601 -0.468750 -0.625000 +v -0.013774 -0.437500 -0.593750 +v -0.006605 -0.437500 -0.531250 +v -0.007177 -0.406250 -0.562500 +v -0.013214 -0.468750 -0.562500 +v -0.003150 -0.312500 -0.593750 +v 0.004275 -0.312500 -0.531250 +v 0.002893 -0.281250 -0.562500 +v -0.001796 -0.343750 -0.562500 +v -0.019687 -0.312500 -0.718750 +v -0.011152 -0.312500 -0.656250 +v -0.013214 -0.281250 -0.687500 +v -0.017667 -0.343750 -0.687500 +v -0.047707 -0.437500 -0.843750 +v -0.038522 -0.437500 -0.781250 +v -0.040415 -0.406250 -0.812500 +v -0.045858 -0.468750 -0.812500 +v -0.038177 -0.312500 -0.843750 +v -0.028710 -0.312500 -0.781250 +v -0.031368 -0.281250 -0.812500 +v -0.035575 -0.343750 -0.812500 +v -0.058262 -0.312500 -0.968750 +v -0.048043 -0.312500 -0.906250 +v -0.051209 -0.281250 -0.937500 +v -0.055165 -0.343750 -0.937500 +v 0.045663 -0.187500 -0.093750 +v 0.047072 -0.187500 -0.031250 +v 0.048255 -0.156250 -0.062500 +v 0.044497 -0.218750 -0.062500 +v 0.051379 -0.062500 -0.093750 +v 0.052848 -0.062500 -0.031250 +v 0.053094 -0.031250 -0.062500 +v 0.051136 -0.093750 -0.062500 +v 0.045663 -0.062500 -0.218750 +v 0.048970 -0.062500 -0.156250 +v 0.048255 -0.031250 -0.187500 +v 0.046366 -0.093750 -0.187500 +v -0.007748 -0.687500 -0.093750 +v -0.006605 -0.687500 -0.031250 +v -0.002570 -0.656250 -0.062500 +v -0.011716 -0.718750 -0.062500 +v 0.009463 -0.562500 -0.093750 +v 0.010674 -0.562500 -0.031250 +v 0.014131 -0.531250 -0.062500 +v 0.006061 -0.593750 -0.062500 +v 0.004671 -0.562500 -0.218750 +v 0.007457 -0.562500 -0.156250 +v 0.010068 -0.531250 -0.187500 +v 0.002107 -0.593750 -0.187500 +v 0.024344 -0.437500 -0.093750 +v 0.025622 -0.437500 -0.031250 +v 0.028412 -0.406250 -0.062500 +v 0.021597 -0.468750 -0.062500 +v 0.036531 -0.312500 -0.093750 +v 0.037876 -0.312500 -0.031250 +v 0.039907 -0.281250 -0.062500 +v 0.034530 -0.343750 -0.062500 +v 0.031233 -0.312500 -0.218750 +v 0.034309 -0.312500 -0.156250 +v 0.035417 -0.281250 -0.187500 +v 0.030144 -0.343750 -0.187500 +v 0.011078 -0.437500 -0.343750 +v 0.015567 -0.437500 -0.281250 +v 0.016598 -0.406250 -0.312500 +v 0.010068 -0.468750 -0.312500 +v 0.022650 -0.312500 -0.343750 +v 0.027335 -0.312500 -0.281250 +v 0.027550 -0.281250 -0.312500 +v 0.022439 -0.343750 -0.312500 +v 0.011078 -0.312500 -0.468750 +v 0.017218 -0.312500 -0.406250 +v 0.016598 -0.281250 -0.437500 +v 0.011686 -0.343750 -0.437500 +v -0.031191 -0.187500 -0.843750 +v -0.021512 -0.187500 -0.781250 +v -0.024951 -0.156250 -0.812500 +v -0.027819 -0.218750 -0.812500 +v -0.026926 -0.062500 -0.843750 +v -0.017114 -0.062500 -0.781250 +v -0.021330 -0.031250 -0.812500 +v -0.022783 -0.093750 -0.812500 +v -0.047707 -0.062500 -0.968750 +v -0.037139 -0.062500 -0.906250 +v -0.041784 -0.031250 -0.937500 +v -0.043148 -0.093750 -0.937500 +v 0.046483 -0.187500 0.156250 +v 0.044614 -0.187500 0.218750 +v 0.047426 -0.156250 0.187500 +v 0.043686 -0.218750 0.187500 +v 0.052233 -0.062500 0.156250 +v 0.050289 -0.062500 0.218750 +v 0.052233 -0.031250 0.187500 +v 0.050289 -0.093750 0.187500 +v 0.053342 -0.062500 0.031250 +v 0.053218 -0.062500 0.093750 +v 0.054214 -0.031250 0.062500 +v 0.052233 -0.093750 0.062500 +v 0.053342 0.062500 -0.093750 +v 0.054844 0.062500 -0.031250 +v 0.054214 0.093750 -0.062500 +v 0.054089 0.031250 -0.062500 +v 0.052233 0.187500 -0.093750 +v 0.053715 0.187500 -0.031250 +v 0.052233 0.218750 -0.062500 +v 0.053715 0.156250 -0.062500 +v 0.046483 0.187500 -0.218750 +v 0.049808 0.187500 -0.156250 +v 0.047426 0.218750 -0.187500 +v 0.048851 0.156250 -0.187500 +v -0.007081 -0.687500 0.156250 +v -0.008602 -0.687500 0.218750 +v -0.003246 -0.656250 0.187500 +v -0.012372 -0.718750 0.187500 +v 0.010169 -0.562500 0.156250 +v 0.008559 -0.562500 0.218750 +v 0.013416 -0.531250 0.187500 +v 0.005365 -0.593750 0.187500 +v 0.011079 -0.562500 0.031250 +v 0.010977 -0.562500 0.093750 +v 0.015054 -0.531250 0.062500 +v 0.006958 -0.593750 0.062500 +v -0.038953 -0.687500 0.656250 +v -0.045773 -0.687500 0.718750 +v -0.038263 -0.656250 0.687500 +v -0.046447 -0.718750 0.687500 +v -0.023417 -0.562500 0.656250 +v -0.030572 -0.562500 0.718750 +v -0.023417 -0.531250 0.687500 +v -0.030572 -0.593750 0.687500 +v -0.010869 -0.562500 0.531250 +v -0.016836 -0.562500 0.593750 +v -0.010115 -0.531250 0.562500 +v -0.017574 -0.593750 0.562500 +v 0.038325 0.062500 -0.343750 +v 0.043340 0.062500 -0.281250 +v 0.040931 0.093750 -0.312500 +v 0.040817 0.031250 -0.312500 +v 0.037314 0.187500 -0.343750 +v 0.042304 0.187500 -0.281250 +v 0.039115 0.218750 -0.312500 +v 0.040475 0.156250 -0.312500 +v 0.025089 0.187500 -0.468750 +v 0.031561 0.187500 -0.406250 +v 0.027658 0.218750 -0.437500 +v 0.028952 0.156250 -0.437500 +v 0.048255 0.312500 0.156250 +v 0.046366 0.312500 0.218750 +v 0.045663 0.343750 0.187500 +v 0.048970 0.281250 0.187500 +v 0.039907 0.437500 0.156250 +v 0.038100 0.437500 0.218750 +v 0.036532 0.468750 0.187500 +v 0.041502 0.406250 0.187500 +v 0.040931 0.437500 0.031250 +v 0.040817 0.437500 0.093750 +v 0.038325 0.468750 0.062500 +v 0.043340 0.406250 0.062500 +v 0.010068 0.312500 0.656250 +v 0.002107 0.312500 0.718750 +v 0.004671 0.343750 0.687500 +v 0.007457 0.281250 0.687500 +v 0.002893 0.437500 0.656250 +v -0.004882 0.437500 0.718750 +v -0.003150 0.468750 0.687500 +v 0.001127 0.406250 0.687500 +v 0.016598 0.437500 0.531250 +v 0.010068 0.437500 0.593750 +v 0.011079 0.468750 0.562500 +v 0.015568 0.406250 0.562500 +v 0.008559 -0.187500 0.656250 +v 0.000638 -0.187500 0.718750 +v 0.006160 -0.156250 0.687500 +v 0.002992 -0.218750 0.687500 +v 0.013416 -0.062500 0.656250 +v 0.005365 -0.062500 0.718750 +v 0.010169 -0.031250 0.687500 +v 0.008559 -0.093750 0.687500 +v 0.027658 -0.062500 0.531250 +v 0.020862 -0.062500 0.593750 +v 0.025089 -0.031250 0.562500 +v 0.023390 -0.093750 0.562500 +v -0.029864 0.312500 -0.843750 +v -0.020144 0.312500 -0.781250 +v -0.026299 0.343750 -0.812500 +v -0.023779 0.281250 -0.812500 +v -0.036184 0.437500 -0.843750 +v -0.026657 0.437500 -0.781250 +v -0.033391 0.468750 -0.812500 +v -0.029510 0.406250 -0.812500 +v -0.056391 0.437500 -0.968750 +v -0.046110 0.437500 -0.906250 +v -0.053111 0.468750 -0.937500 +v -0.049463 0.406250 -0.937500 +v 0.032876 0.312500 -0.343750 +v 0.037763 0.312500 -0.281250 +v 0.033757 0.343750 -0.312500 +v 0.036867 0.281250 -0.312500 +v 0.025089 0.437500 -0.343750 +v 0.029819 0.437500 -0.281250 +v 0.025089 0.468750 -0.312500 +v 0.029819 0.406250 -0.312500 +v 0.013416 0.437500 -0.468750 +v 0.019607 0.437500 -0.406250 +v 0.014234 0.468750 -0.437500 +v 0.018774 0.406250 -0.437500 +v 0.031233 -0.187500 -0.343750 +v 0.036085 -0.187500 -0.281250 +v 0.035417 -0.156250 -0.312500 +v 0.031889 -0.218750 -0.312500 +v 0.036531 -0.062500 -0.343750 +v 0.041502 -0.062500 -0.281250 +v 0.039907 -0.031250 -0.312500 +v 0.038100 -0.093750 -0.312500 +v 0.024344 -0.062500 -0.468750 +v 0.030797 -0.062500 -0.406250 +v 0.028412 -0.031250 -0.437500 +v 0.026691 -0.093750 -0.437500 +v -0.073460 -0.687500 -0.843750 +v -0.065002 -0.687500 -0.781250 +v -0.065478 -0.656250 -0.812500 +v -0.072996 -0.718750 -0.812500 +v -0.059557 -0.562500 -0.843750 +v -0.050711 -0.562500 -0.781250 +v -0.051872 -0.531250 -0.812500 +v -0.058424 -0.593750 -0.812500 +v -0.078366 -0.562500 -0.968750 +v -0.068790 -0.562500 -0.906250 +v -0.070510 -0.531250 -0.937500 +v -0.076689 -0.593750 -0.937500 +v -0.019687 -0.687500 -0.343750 +v -0.015634 -0.687500 -0.281250 +v -0.013214 -0.656250 -0.312500 +v -0.022058 -0.718750 -0.312500 +v -0.003150 -0.562500 -0.343750 +v 0.001126 -0.562500 -0.281250 +v 0.002893 -0.531250 -0.312500 +v -0.004882 -0.593750 -0.312500 +v -0.013774 -0.562500 -0.468750 +v -0.008128 -0.562500 -0.406250 +v -0.007177 -0.531250 -0.437500 +v -0.014705 -0.593750 -0.437500 +v -0.042296 -0.687500 -0.593750 +v -0.035749 -0.687500 -0.531250 +v -0.034878 -0.656250 -0.562500 +v -0.043148 -0.718750 -0.562500 +v -0.026926 -0.562500 -0.593750 +v -0.020053 -0.562500 -0.531250 +v -0.019870 -0.531250 -0.562500 +v -0.027105 -0.593750 -0.562500 +v -0.042296 -0.562500 -0.718750 +v -0.034354 -0.562500 -0.656250 +v -0.034878 -0.531250 -0.687500 +v -0.041784 -0.593750 -0.687500 +v 0.014234 0.562500 -0.343750 +v 0.018774 0.562500 -0.281250 +v 0.013416 0.593750 -0.312500 +v 0.019607 0.531250 -0.312500 +v 0.000638 0.687500 -0.343750 +v 0.004968 0.687500 -0.281250 +v -0.000922 0.718750 -0.312500 +v 0.006559 0.656250 -0.312500 +v -0.010115 0.687500 -0.468750 +v -0.004402 0.687500 -0.406250 +v -0.010869 0.718750 -0.437500 +v -0.003632 0.656250 -0.437500 +v 0.027658 0.562500 -0.093750 +v 0.028952 0.562500 -0.031250 +v 0.025089 0.593750 -0.062500 +v 0.031561 0.531250 -0.062500 +v 0.013416 0.687500 -0.093750 +v 0.014644 0.687500 -0.031250 +v 0.010169 0.718750 -0.062500 +v 0.017943 0.656250 -0.062500 +v 0.008559 0.687500 -0.218750 +v 0.011382 0.687500 -0.156250 +v 0.006160 0.718750 -0.187500 +v 0.013825 0.656250 -0.187500 +v 0.047426 0.312500 -0.093750 +v 0.048851 0.312500 -0.031250 +v 0.046483 0.343750 -0.062500 +v 0.049808 0.281250 -0.062500 +v 0.039115 0.437500 -0.093750 +v 0.040475 0.437500 -0.031250 +v 0.037314 0.468750 -0.062500 +v 0.042304 0.406250 -0.062500 +v 0.033757 0.437500 -0.218750 +v 0.036867 0.437500 -0.156250 +v 0.032876 0.468750 -0.187500 +v 0.037763 0.406250 -0.187500 +v -0.045098 0.562500 -0.843750 +v -0.035836 0.562500 -0.781250 +v -0.043062 0.593750 -0.812500 +v -0.037918 0.531250 -0.812500 +v -0.056391 0.687500 -0.843750 +v -0.047455 0.687500 -0.781250 +v -0.055083 0.718750 -0.812500 +v -0.048795 0.656250 -0.812500 +v -0.075385 0.687500 -0.968750 +v -0.065715 0.687500 -0.906250 +v -0.073537 0.718750 -0.937500 +v -0.067610 0.656250 -0.937500 +v -0.010869 0.562500 -0.593750 +v -0.003632 0.562500 -0.531250 +v -0.010115 0.593750 -0.562500 +v -0.004402 0.531250 -0.562500 +v -0.023417 0.687500 -0.593750 +v -0.016467 0.687500 -0.531250 +v -0.023417 0.718750 -0.562500 +v -0.016467 0.656250 -0.562500 +v -0.038953 0.687500 -0.718750 +v -0.030926 0.687500 -0.656250 +v -0.038263 0.718750 -0.687500 +v -0.031632 0.656250 -0.687500 +v 0.006160 0.312500 -0.593750 +v 0.013825 0.312500 -0.531250 +v 0.008559 0.343750 -0.562500 +v 0.011382 0.281250 -0.562500 +v -0.000922 0.437500 -0.593750 +v 0.006559 0.437500 -0.531250 +v 0.000638 0.468750 -0.562500 +v 0.004968 0.406250 -0.562500 +v -0.017574 0.437500 -0.718750 +v -0.008981 0.437500 -0.656250 +v -0.015355 0.468750 -0.687500 +v -0.011246 0.406250 -0.687500 +v 0.015054 0.062500 0.656250 +v 0.006958 0.062500 0.718750 +v 0.011079 0.093750 0.687500 +v 0.010977 0.031250 0.687500 +v 0.014132 0.187500 0.656250 +v 0.006061 0.187500 0.718750 +v 0.009464 0.218750 0.687500 +v 0.010674 0.156250 0.687500 +v 0.028412 0.187500 0.531250 +v 0.021597 0.187500 0.593750 +v 0.024344 0.218750 0.562500 +v 0.025622 0.156250 0.562500 +v -0.020509 0.062500 0.906250 +v -0.030573 0.062500 0.968750 +v -0.025491 0.093750 0.937500 +v -0.025581 0.031250 0.937500 +v -0.021330 0.187500 0.906250 +v -0.031368 0.187500 0.968750 +v -0.026925 0.218750 0.937500 +v -0.025850 0.156250 0.937500 +v -0.002570 0.187500 0.781250 +v -0.011715 0.187500 0.843750 +v -0.007748 0.218750 0.812500 +v -0.006604 0.156250 0.812500 +v -0.026298 -0.187500 0.906250 +v -0.036184 -0.187500 0.968750 +v -0.029864 -0.156250 0.937500 +v -0.032688 -0.218750 0.937500 +v -0.021966 -0.062500 0.906250 +v -0.031985 -0.062500 0.968750 +v -0.026298 -0.031250 0.937500 +v -0.027730 -0.093750 0.937500 +v -0.003246 -0.062500 0.781250 +v -0.012372 -0.062500 0.843750 +v -0.007081 -0.031250 0.812500 +v -0.008602 -0.093750 0.812500 +v -0.007177 0.562500 0.656250 +v -0.014705 0.562500 0.718750 +v -0.013774 0.593750 0.687500 +v -0.008128 0.531250 0.687500 +v -0.019870 0.687500 0.656250 +v -0.027104 0.687500 0.718750 +v -0.026926 0.718750 0.687500 +v -0.020052 0.656250 0.687500 +v -0.007177 0.687500 0.531250 +v -0.013214 0.687500 0.593750 +v -0.013774 0.718750 0.562500 +v -0.006605 0.656250 0.562500 +v -0.040415 0.562500 0.906250 +v -0.049879 0.562500 0.968750 +v -0.047707 0.593750 0.937500 +v -0.042637 0.531250 0.937500 +v -0.051872 0.687500 0.906250 +v -0.061007 0.687500 0.968750 +v -0.059556 0.718750 0.937500 +v -0.053358 0.656250 0.937500 +v -0.034878 0.687500 0.781250 +v -0.043148 0.687500 0.843750 +v -0.042296 0.718750 0.812500 +v -0.035749 0.656250 0.812500 +v -0.024951 0.312500 0.906250 +v -0.034878 0.312500 0.968750 +v -0.031191 0.343750 0.937500 +v -0.028710 0.281250 0.937500 +v -0.031368 0.437500 0.906250 +v -0.041100 0.437500 0.968750 +v -0.038177 0.468750 0.937500 +v -0.034354 0.406250 0.937500 +v -0.013214 0.437500 0.781250 +v -0.022057 0.437500 0.843750 +v -0.019687 0.468750 0.812500 +v -0.015633 0.406250 0.812500 +v 0.028412 0.562500 0.156250 +v 0.026691 0.562500 0.218750 +v 0.024344 0.593750 0.187500 +v 0.030797 0.531250 0.187500 +v 0.014132 0.687500 0.156250 +v 0.012499 0.687500 0.218750 +v 0.009463 0.718750 0.187500 +v 0.017218 0.656250 0.187500 +v 0.015054 0.687500 0.031250 +v 0.014951 0.687500 0.093750 +v 0.011079 0.718750 0.062500 +v 0.018878 0.656250 0.062500 +v 0.016598 0.562500 0.406250 +v 0.011687 0.562500 0.468750 +v 0.011079 0.593750 0.437500 +v 0.017218 0.531250 0.437500 +v 0.002893 0.687500 0.406250 +v -0.001796 0.687500 0.468750 +v -0.003150 0.718750 0.437500 +v 0.004275 0.656250 0.437500 +v 0.010068 0.687500 0.281250 +v 0.006858 0.687500 0.343750 +v 0.004671 0.718750 0.312500 +v 0.012296 0.656250 0.312500 +v 0.035418 0.312500 0.406250 +v 0.030144 0.312500 0.468750 +v 0.031233 0.343750 0.437500 +v 0.034309 0.281250 0.437500 +v 0.027550 0.437500 0.406250 +v 0.022439 0.437500 0.468750 +v 0.022650 0.468750 0.437500 +v 0.027335 0.406250 0.437500 +v 0.035418 0.437500 0.281250 +v 0.031889 0.437500 0.343750 +v 0.031233 0.468750 0.312500 +v 0.036085 0.406250 0.312500 +v -0.010115 -0.437500 0.656250 +v -0.017574 -0.437500 0.718750 +v -0.010869 -0.406250 0.687500 +v -0.016836 -0.468750 0.687500 +v 0.000638 -0.312500 0.656250 +v -0.007081 -0.312500 0.718750 +v -0.000922 -0.281250 0.687500 +v -0.005553 -0.343750 0.687500 +v 0.014234 -0.312500 0.531250 +v 0.007757 -0.312500 0.593750 +v 0.013416 -0.281250 0.562500 +v 0.008559 -0.343750 0.562500 +v -0.043062 -0.437500 0.906250 +v -0.052450 -0.437500 0.968750 +v -0.045097 -0.406250 0.937500 +v -0.050462 -0.468750 0.937500 +v -0.033390 -0.312500 0.906250 +v -0.043062 -0.312500 0.968750 +v -0.036184 -0.281250 0.937500 +v -0.040329 -0.343750 0.937500 +v -0.015355 -0.312500 0.781250 +v -0.024140 -0.312500 0.843750 +v -0.017574 -0.281250 0.812500 +v -0.021966 -0.343750 0.812500 +v -0.069181 -0.687500 0.906250 +v -0.077833 -0.687500 0.968750 +v -0.069807 -0.656250 0.937500 +v -0.077222 -0.718750 0.937500 +v -0.055082 -0.562500 0.906250 +v -0.064127 -0.562500 0.968750 +v -0.056390 -0.531250 0.937500 +v -0.062850 -0.593750 0.937500 +v -0.038263 -0.562500 0.781250 +v -0.046447 -0.562500 0.843750 +v -0.038953 -0.531250 0.812500 +v -0.045773 -0.593750 0.812500 +v 0.025089 -0.437500 0.156250 +v 0.023390 -0.437500 0.218750 +v 0.027658 -0.406250 0.187500 +v 0.020862 -0.468750 0.187500 +v 0.037315 -0.312500 0.156250 +v 0.035529 -0.312500 0.218750 +v 0.039115 -0.281250 0.187500 +v 0.033757 -0.343750 0.187500 +v 0.038325 -0.312500 0.031250 +v 0.038213 -0.312500 0.093750 +v 0.040931 -0.281250 0.062500 +v 0.035529 -0.343750 0.062500 +v 0.013416 -0.437500 0.406250 +v 0.008559 -0.437500 0.468750 +v 0.014234 -0.406250 0.437500 +v 0.007757 -0.468750 0.437500 +v 0.025089 -0.312500 0.406250 +v 0.020025 -0.312500 0.468750 +v 0.025089 -0.281250 0.437500 +v 0.020025 -0.343750 0.437500 +v 0.032876 -0.312500 0.281250 +v 0.029385 -0.312500 0.343750 +v 0.033757 -0.281250 0.312500 +v 0.028520 -0.343750 0.312500 +v -0.017574 -0.687500 0.406250 +v -0.021966 -0.687500 0.468750 +v -0.015355 -0.656250 0.437500 +v -0.024140 -0.718750 0.437500 +v -0.000922 -0.562500 0.406250 +v -0.005553 -0.562500 0.468750 +v 0.000638 -0.531250 0.437500 +v -0.007081 -0.593750 0.437500 +v 0.006160 -0.562500 0.281250 +v 0.002992 -0.562500 0.343750 +v 0.008559 -0.531250 0.312500 +v 0.000638 -0.593750 0.312500 +v 0.054214 0.062500 0.156250 +v 0.052233 0.062500 0.218750 +v 0.053342 0.093750 0.187500 +v 0.053218 0.031250 0.187500 +v 0.053094 0.187500 0.156250 +v 0.051136 0.187500 0.218750 +v 0.051379 0.218750 0.187500 +v 0.052848 0.156250 0.187500 +v 0.054214 0.187500 0.031250 +v 0.054089 0.187500 0.093750 +v 0.053342 0.218750 0.062500 +v 0.054845 0.156250 0.062500 +v 0.040931 0.062500 0.406250 +v 0.035529 0.062500 0.468750 +v 0.038325 0.093750 0.437500 +v 0.038213 0.031250 0.437500 +v 0.039908 0.187500 0.406250 +v 0.034531 0.187500 0.468750 +v 0.036532 0.218750 0.437500 +v 0.037876 0.156250 0.437500 +v 0.048255 0.187500 0.281250 +v 0.044498 0.187500 0.343750 +v 0.045663 0.218750 0.312500 +v 0.047072 0.156250 0.312500 +v 0.033757 -0.187500 0.406250 +v 0.028520 -0.187500 0.468750 +v 0.032876 -0.156250 0.437500 +v 0.029385 -0.218750 0.437500 +v 0.039115 -0.062500 0.406250 +v 0.033757 -0.062500 0.468750 +v 0.037315 -0.031250 0.437500 +v 0.035529 -0.093750 0.437500 +v 0.047426 -0.062500 0.281250 +v 0.043686 -0.062500 0.343750 +v 0.046483 -0.031250 0.312500 +v 0.044614 -0.093750 0.312500 +v -0.025491 0.062500 -0.843750 +v -0.015634 0.062500 -0.781250 +v -0.020509 0.093750 -0.812500 +v -0.020601 0.031250 -0.812500 +v -0.026299 0.187500 -0.843750 +v -0.016467 0.187500 -0.781250 +v -0.021967 0.218750 -0.812500 +v -0.020874 0.156250 -0.812500 +v -0.047120 0.187500 -0.968750 +v -0.036532 0.187500 -0.906250 +v -0.042381 0.218750 -0.937500 +v -0.041357 0.156250 -0.937500 +v 0.011078 0.062500 -0.593750 +v 0.018878 0.062500 -0.531250 +v 0.015054 0.093750 -0.562500 +v 0.014951 0.031250 -0.562500 +v 0.010169 0.187500 -0.593750 +v 0.017943 0.187500 -0.531250 +v 0.013416 0.218750 -0.562500 +v 0.014643 0.156250 -0.562500 +v -0.007081 0.187500 -0.718750 +v 0.001812 0.187500 -0.656250 +v -0.003246 0.218750 -0.687500 +v -0.002086 0.156250 -0.687500 +v 0.004671 -0.187500 -0.593750 +v 0.012296 -0.187500 -0.531250 +v 0.010068 -0.156250 -0.562500 +v 0.006858 -0.218750 -0.562500 +v 0.009463 -0.062500 -0.593750 +v 0.017218 -0.062500 -0.531250 +v 0.014131 -0.031250 -0.562500 +v 0.012499 -0.093750 -0.562500 +v -0.007748 -0.062500 -0.718750 +v 0.001126 -0.062500 -0.656250 +v -0.002570 -0.031250 -0.687500 +v -0.004113 -0.093750 -0.687500 +v -0.012278 -0.187500 -0.718750 +v -0.003536 -0.187500 -0.656250 +v -0.006414 -0.156250 -0.687500 +v -0.009455 -0.218750 -0.687500 +v -0.006223 0.062500 -0.718750 +v 0.002696 0.062500 -0.656250 +v -0.001699 0.093750 -0.687500 +v -0.001796 0.031250 -0.687500 +v -0.046363 0.062500 -0.968750 +v -0.035749 0.062500 -0.906250 +v -0.041015 0.093750 -0.937500 +v -0.041100 0.031250 -0.937500 +v 0.041845 -0.187500 0.281250 +v 0.038213 -0.187500 0.343750 +v 0.041845 -0.156250 0.312500 +v 0.038213 -0.218750 0.312500 +v 0.049329 0.062500 0.281250 +v 0.045546 0.062500 0.343750 +v 0.047544 0.093750 0.312500 +v 0.047426 0.031250 0.312500 +v 0.055355 0.062500 0.031250 +v 0.055227 0.062500 0.093750 +v 0.055355 0.093750 0.062500 +v 0.055227 0.031250 0.062500 +v -0.010869 -0.687500 0.281250 +v -0.013867 -0.687500 0.343750 +v -0.007843 -0.656250 0.312500 +v -0.016836 -0.718750 0.312500 +v 0.020862 -0.437500 0.281250 +v 0.017528 -0.437500 0.343750 +v 0.022545 -0.406250 0.312500 +v 0.015876 -0.468750 0.312500 +v 0.026049 -0.437500 0.031250 +v 0.025942 -0.437500 0.093750 +v 0.029385 -0.406250 0.062500 +v 0.022545 -0.468750 0.062500 +v -0.053110 -0.687500 0.781250 +v -0.060926 -0.687500 0.843750 +v -0.053110 -0.656250 0.812500 +v -0.060926 -0.718750 0.812500 +v -0.025580 -0.437500 0.781250 +v -0.034091 -0.437500 0.843750 +v -0.027015 -0.406250 0.812500 +v -0.032688 -0.468750 0.812500 +v 0.002992 -0.437500 0.531250 +v -0.003246 -0.437500 0.593750 +v 0.002992 -0.406250 0.562500 +v -0.003246 -0.468750 0.562500 +v 0.043571 0.312500 0.281250 +v 0.039908 0.312500 0.343750 +v 0.040134 0.343750 0.312500 +v 0.043340 0.281250 0.312500 +v 0.024132 0.562500 0.281250 +v 0.020757 0.562500 0.343750 +v 0.019294 0.593750 0.312500 +v 0.025622 0.531250 0.312500 +v 0.029385 0.562500 0.031250 +v 0.029277 0.562500 0.093750 +v 0.026049 0.593750 0.062500 +v 0.032547 0.531250 0.062500 +v -0.006413 0.312500 0.781250 +v -0.015448 0.312500 0.843750 +v -0.012278 0.343750 0.812500 +v -0.009643 0.281250 0.812500 +v -0.022783 0.562500 0.781250 +v -0.031368 0.562500 0.843750 +v -0.029776 0.593750 0.812500 +v -0.024411 0.531250 0.812500 +v 0.006061 0.562500 0.531250 +v -0.000241 0.562500 0.593750 +v -0.000046 0.593750 0.562500 +v 0.005862 0.531250 0.562500 +v -0.007842 -0.187500 0.781250 +v -0.016836 -0.187500 0.843750 +v -0.010869 -0.156250 0.812500 +v -0.013867 -0.218750 0.812500 +v -0.001699 0.062500 0.781250 +v -0.010869 0.062500 0.843750 +v -0.006222 0.093750 0.812500 +v -0.006318 0.031250 0.812500 +v 0.029385 0.062500 0.531250 +v 0.022545 0.062500 0.593750 +v 0.026049 0.093750 0.562500 +v 0.025942 0.031250 0.562500 +v -0.010870 0.312500 -0.718750 +v -0.002086 0.312500 -0.656250 +v -0.007843 0.343750 -0.687500 +v -0.005170 0.281250 -0.687500 +v -0.027015 0.562500 -0.718750 +v -0.018678 0.562500 -0.656250 +v -0.025581 0.593750 -0.687500 +v -0.020144 0.531250 -0.687500 +v -0.064763 0.562500 -0.968750 +v -0.054755 0.562500 -0.906250 +v -0.062211 0.593750 -0.937500 +v -0.057368 0.531250 -0.937500 +v 0.041845 0.312500 -0.218750 +v 0.045079 0.312500 -0.156250 +v 0.041845 0.343750 -0.187500 +v 0.045079 0.281250 -0.187500 +v 0.022545 0.562500 -0.218750 +v 0.025515 0.562500 -0.156250 +v 0.020862 0.593750 -0.187500 +v 0.027228 0.531250 -0.187500 +v 0.002992 0.562500 -0.468750 +v 0.008961 0.562500 -0.406250 +v 0.002992 0.593750 -0.437500 +v 0.008961 0.531250 -0.437500 +v -0.056962 -0.687500 -0.718750 +v -0.049380 -0.687500 -0.656250 +v -0.049213 -0.656250 -0.687500 +v -0.057124 -0.718750 -0.687500 +v -0.029776 -0.687500 -0.468750 +v -0.024411 -0.687500 -0.406250 +v -0.022784 -0.656250 -0.437500 +v -0.031368 -0.718750 -0.437500 +v -0.091465 -0.687500 -0.968750 +v -0.082295 -0.687500 -0.906250 +v -0.083345 -0.656250 -0.937500 +v -0.090443 -0.718750 -0.937500 +v 0.019294 -0.187500 -0.468750 +v 0.025622 -0.187500 -0.406250 +v 0.024132 -0.156250 -0.437500 +v 0.020757 -0.218750 -0.437500 +v 0.020862 0.312500 -0.468750 +v 0.027228 0.312500 -0.406250 +v 0.022545 0.343750 -0.437500 +v 0.025515 0.281250 -0.437500 +v -0.050462 0.312500 -0.968750 +v -0.039986 0.312500 -0.906250 +v -0.046447 0.343750 -0.937500 +v -0.044082 0.281250 -0.937500 +v 0.022545 -0.187500 0.531250 +v 0.015876 -0.187500 0.593750 +v 0.020862 -0.156250 0.562500 +v 0.017528 -0.218750 0.562500 +v 0.024132 0.312500 0.531250 +v 0.017425 0.312500 0.593750 +v 0.019295 0.343750 0.562500 +v 0.022229 0.281250 0.562500 +v 0.049329 0.312500 0.031250 +v 0.049209 0.312500 0.093750 +v 0.047544 0.343750 0.062500 +v 0.050894 0.281250 0.062500 +v 0.026049 0.062500 -0.468750 +v 0.032547 0.062500 -0.406250 +v 0.029385 0.093750 -0.437500 +v 0.029277 0.031250 -0.437500 +v -0.027015 -0.687500 0.531250 +v -0.032688 -0.687500 0.593750 +v -0.025581 -0.656250 0.562500 +v -0.034091 -0.718750 0.562500 +v -0.006223 -0.687500 0.031250 +v -0.006318 -0.687500 0.093750 +v -0.001699 -0.656250 0.062500 +v -0.010869 -0.718750 0.062500 +v 0.047544 0.062500 -0.218750 +v 0.050893 0.062500 -0.156250 +v 0.049329 0.093750 -0.187500 +v 0.049209 0.031250 -0.187500 +v 0.047544 -0.187500 0.031250 +v 0.047426 -0.187500 0.093750 +v 0.049329 -0.156250 0.062500 +v 0.045546 -0.218750 0.062500 +v -0.051706 -0.187500 -0.968750 +v -0.041271 -0.187500 -0.906250 +v -0.045182 -0.156250 -0.937500 +v -0.047875 -0.218750 -0.937500 +v -0.000046 -0.437500 -0.468750 +v 0.005862 -0.437500 -0.406250 +v 0.006060 -0.406250 -0.437500 +v -0.000241 -0.468750 -0.437500 +v 0.019294 -0.437500 -0.218750 +v 0.022228 -0.437500 -0.156250 +v 0.024132 -0.406250 -0.187500 +v 0.017425 -0.468750 -0.187500 +v -0.012278 -0.687500 -0.218750 +v -0.009643 -0.687500 -0.156250 +v -0.006414 -0.656250 -0.187500 +v -0.015448 -0.718750 -0.187500 +v 0.040134 -0.187500 -0.218750 +v 0.043340 -0.187500 -0.156250 +v 0.043571 -0.156250 -0.187500 +v 0.039907 -0.218750 -0.187500 +v -0.067217 -0.437500 -0.968750 +v -0.057287 -0.437500 -0.906250 +v -0.059718 -0.406250 -0.937500 +v -0.064843 -0.468750 -0.937500 +v -0.029776 -0.437500 -0.718750 +v -0.021512 -0.437500 -0.656250 +v -0.022784 -0.406250 -0.687500 +v -0.028532 -0.468750 -0.687500 +v -0.070012 0.742187 0.992188 +v -0.084324 0.742188 -0.992187 +v -0.001019 0.750000 -0.250000 +v 0.018774 -0.500000 -0.000000 +v 0.035418 0.500000 0.000000 +v 0.039228 -0.250000 0.250000 +v -0.020144 -0.250000 -0.750000 +v -0.052120 0.000000 -1.000000 +v 0.006858 0.750000 0.000000 +v -0.044336 -0.250000 1.000000 +v -0.059960 -0.250000 -1.000000 +v -0.036097 -0.000000 1.000000 +v 0.043224 -0.250000 -0.000000 +v -0.020600 0.750000 -0.500000 +v -0.087662 -0.742188 0.992187 +v -0.101182 -0.742187 -0.992188 +v 0.003386 0.750000 0.250000 +v -0.011997 0.750000 0.500000 +v -0.037917 0.250000 1.000000 +v -0.053852 0.250000 -1.000000 +v -0.049879 0.750000 -0.750000 +v 0.012194 -0.250000 -0.500000 +v 0.021807 -0.250000 0.500000 +v 0.052111 0.250000 0.000000 +v -0.015726 -0.750000 -0.000000 +v -0.033303 -0.750000 0.500000 +v 0.029819 0.250000 0.500000 +v 0.019920 0.250000 -0.500000 +v -0.041357 -0.750000 -0.500000 +v -0.062770 -0.500000 1.000000 +v -0.077528 -0.500000 -1.000000 +v -0.037918 0.750000 0.750000 +v -0.050129 0.500000 1.000000 +v -0.065477 0.500000 -1.000000 +v 0.034198 -0.250000 -0.250000 +v -0.006986 -0.250000 0.750000 +v 0.054718 0.000000 -0.000000 +v -0.018954 -0.750000 0.250000 +v -0.057612 -0.750000 0.750000 +v -0.000825 -0.500000 0.500000 +v 0.047899 0.250000 0.250000 +v 0.000247 0.250000 0.750000 +v 0.014644 0.500000 0.500000 +v 0.032108 -0.000000 0.500000 +v -0.013214 0.250000 -0.750000 +v 0.042648 0.250000 -0.250000 +v 0.005266 0.500000 -0.500000 +v 0.022123 0.000000 -0.500000 +v -0.068868 -0.750000 -0.750000 +v -0.023055 -0.750000 -0.250000 +v -0.009738 -0.500000 -0.500000 +v 0.010573 -0.500000 -0.250000 +v -0.039986 -0.500000 -0.750000 +v 0.045079 0.000000 -0.250000 +v 0.026691 0.500000 -0.250000 +v -0.026388 0.500000 -0.750000 +v 0.002303 -0.000000 0.750000 +v -0.013494 0.500000 0.750000 +v 0.031561 0.500000 0.250000 +v -0.027640 -0.500000 0.750000 +v 0.015157 -0.500000 0.250000 +v 0.050410 -0.000000 0.250000 +v -0.011246 0.000000 -0.750000 +v -0.067374 0.750000 -0.875000 +v -0.074848 0.625000 -1.000000 +v -0.059960 0.625000 1.000000 +v -0.054098 0.750000 0.875000 +v -0.067611 -0.375000 -1.000000 +v -0.052367 -0.375000 1.000000 +v 0.004473 0.750000 -0.125000 +v 0.002598 -0.625000 -0.000000 +v 0.045429 0.375000 0.000000 +v 0.032108 -0.250000 0.375000 +v -0.002860 -0.250000 -0.625000 +v -0.051872 0.125000 -1.000000 +v 0.006559 0.750000 0.125000 +v -0.038867 -0.125000 1.000000 +v -0.054755 -0.125000 -1.000000 +v -0.035836 0.125000 1.000000 +v -0.039298 -0.250000 -0.875000 +v 0.042879 -0.250000 0.125000 +v 0.022439 0.625000 0.000000 +v 0.032437 -0.375000 -0.000000 +v -0.009454 0.750000 -0.375000 +v -0.075308 -0.625000 1.000000 +v -0.089492 -0.625000 -1.000000 +v -0.002860 0.750000 0.375000 +v -0.023779 0.750000 0.625000 +v -0.042722 0.375000 1.000000 +v -0.058424 0.375000 -1.000000 +v -0.034179 0.750000 -0.625000 +v 0.024663 -0.250000 -0.375000 +v 0.008659 -0.250000 0.625000 +v 0.055099 0.125000 -0.000000 +v 0.050772 -0.125000 -0.000000 +v -0.016004 -0.750000 0.125000 +v -0.044336 -0.750000 0.625000 +v 0.011890 -0.375000 0.500000 +v -0.024771 -0.250000 0.875000 +v 0.051744 0.250000 0.125000 +v 0.016288 0.250000 0.625000 +v 0.002598 0.625000 0.500000 +v 0.032437 0.125000 0.500000 +v -0.032776 0.250000 -0.875000 +v 0.032766 0.250000 -0.375000 +v -0.006414 0.625000 -0.500000 +v 0.022439 0.125000 -0.500000 +v -0.085358 -0.750000 -0.875000 +v -0.030927 -0.750000 -0.375000 +v 0.002598 -0.375000 -0.500000 +v 0.040475 -0.250000 -0.125000 +v -0.024771 -0.750000 0.375000 +v -0.072841 -0.750000 0.875000 +v -0.016004 -0.625000 0.500000 +v 0.040475 0.250000 0.375000 +v -0.017943 0.250000 0.875000 +v 0.023814 0.375000 0.500000 +v 0.028628 -0.125000 0.500000 +v 0.004473 0.250000 -0.625000 +v 0.049209 0.250000 -0.125000 +v 0.014131 0.375000 -0.500000 +v 0.018774 -0.125000 -0.500000 +v -0.054098 -0.750000 -0.625000 +v -0.017943 -0.750000 -0.125000 +v -0.024501 -0.625000 -0.500000 +v 0.001812 -0.500000 -0.375000 +v 0.016288 -0.500000 -0.125000 +v 0.023814 -0.375000 -0.250000 +v -0.005170 -0.625000 -0.250000 +v -0.058018 -0.500000 -0.875000 +v -0.023779 -0.500000 -0.625000 +v -0.028799 -0.375000 -0.750000 +v -0.053440 -0.625000 -0.750000 +v 0.035084 0.000000 -0.375000 +v 0.051744 0.000000 -0.125000 +v 0.045429 0.125000 -0.250000 +v 0.041387 -0.125000 -0.250000 +v 0.017425 0.500000 -0.375000 +v 0.032766 0.500000 -0.125000 +v 0.014132 0.625000 -0.250000 +v 0.036308 0.375000 -0.250000 +v -0.045182 0.500000 -0.875000 +v -0.009454 0.500000 -0.625000 +v -0.036965 0.625000 -0.750000 +v -0.018403 0.375000 -0.750000 +v 0.018462 -0.000000 0.625000 +v -0.016004 -0.000000 0.875000 +v 0.002598 0.125000 0.750000 +v -0.000824 -0.125000 0.750000 +v 0.001812 0.500000 0.625000 +v -0.030926 0.500000 0.875000 +v -0.024501 0.625000 0.750000 +v -0.005170 0.375000 0.750000 +v 0.035085 0.500000 0.125000 +v 0.024663 0.500000 0.375000 +v 0.018774 0.625000 0.250000 +v 0.041388 0.375000 0.250000 +v -0.013027 -0.500000 0.625000 +v -0.044336 -0.500000 0.875000 +v -0.016004 -0.375000 0.750000 +v -0.041613 -0.625000 0.750000 +v 0.018462 -0.500000 0.125000 +v 0.008659 -0.500000 0.375000 +v 0.028628 -0.375000 0.250000 +v -0.000825 -0.625000 0.250000 +v 0.054340 -0.000000 0.125000 +v 0.042879 -0.000000 0.375000 +v 0.050772 0.125000 0.250000 +v 0.046601 -0.125000 0.250000 +v -0.030927 0.000000 -0.875000 +v 0.006558 0.000000 -0.625000 +v -0.010964 0.125000 -0.750000 +v -0.014240 -0.125000 -0.750000 +v 0.003386 -0.125000 -0.625000 +v 0.006858 0.125000 -0.625000 +v -0.030661 0.125000 -0.875000 +v 0.039228 -0.125000 0.375000 +v 0.043224 0.125000 0.375000 +v 0.054718 0.125000 0.125000 +v -0.006986 -0.625000 0.375000 +v 0.021807 -0.375000 0.375000 +v 0.032108 -0.375000 0.125000 +v -0.057612 -0.625000 0.875000 +v -0.033303 -0.375000 0.875000 +v -0.000824 -0.375000 0.625000 +v 0.034199 0.375000 0.375000 +v 0.012194 0.625000 0.375000 +v 0.022123 0.625000 0.125000 +v -0.023055 0.375000 0.875000 +v -0.041357 0.625000 0.875000 +v -0.009738 0.625000 0.625000 +v -0.018953 -0.125000 0.875000 +v -0.015726 0.125000 0.875000 +v 0.018774 0.125000 0.625000 +v -0.001019 0.375000 -0.625000 +v -0.020600 0.625000 -0.625000 +v -0.055165 0.625000 -0.875000 +v 0.042648 0.375000 -0.125000 +v 0.019920 0.625000 -0.125000 +v 0.005266 0.625000 -0.375000 +v -0.037918 -0.625000 -0.625000 +v -0.013494 -0.625000 -0.375000 +v -0.070744 -0.625000 -0.875000 +v 0.031561 -0.125000 -0.375000 +v 0.026691 0.375000 -0.375000 +v -0.037658 0.375000 -0.875000 +v 0.015157 -0.125000 0.625000 +v 0.010573 0.375000 0.625000 +v 0.045079 0.375000 0.125000 +v 0.035417 0.125000 -0.375000 +v -0.027640 -0.625000 0.625000 +v 0.002303 -0.625000 0.125000 +v 0.052111 0.125000 -0.125000 +v 0.050410 -0.125000 0.125000 +v -0.033741 -0.125000 -0.875000 +v 0.014643 -0.375000 -0.375000 +v 0.029819 -0.375000 -0.125000 +v 0.000247 -0.625000 -0.125000 +v 0.047899 -0.125000 -0.125000 +v -0.047456 -0.375000 -0.875000 +v -0.011997 -0.375000 -0.625000 +v -0.076688 0.750000 -0.937500 +v -0.069885 0.562500 -1.000000 +v -0.054755 0.562500 1.000000 +v -0.045773 0.750000 0.812500 +v -0.072299 -0.437500 -1.000000 +v -0.057286 -0.437500 1.000000 +v 0.002107 0.750000 -0.187500 +v 0.010977 -0.562500 -0.000000 +v 0.040817 0.437500 0.000000 +v 0.036085 -0.250000 0.312500 +v -0.011246 -0.250000 -0.687500 +v -0.051789 0.062500 -1.000000 +v 0.006958 0.750000 0.062500 +v -0.041271 -0.187500 1.000000 +v -0.057043 -0.187500 -1.000000 +v -0.035749 0.062500 1.000000 +v -0.049463 -0.250000 -0.937500 +v 0.043340 -0.250000 0.062500 +v 0.014951 0.687500 0.000000 +v 0.038213 -0.312500 -0.000000 +v -0.014705 0.750000 -0.437500 +v -0.082294 -0.687500 1.000000 +v -0.096162 -0.687500 -1.000000 +v 0.000638 0.750000 0.312500 +v -0.017574 0.750000 0.562500 +v -0.039985 0.312500 1.000000 +v -0.055819 0.312500 -1.000000 +v -0.041784 0.750000 -0.687500 +v 0.018774 -0.250000 -0.437500 +v 0.015568 -0.250000 0.562500 +v 0.054089 0.187500 -0.000000 +v 0.053218 -0.062500 -0.000000 +v -0.015634 -0.750000 0.062500 +v -0.038522 -0.750000 0.562500 +v 0.017218 -0.312500 0.500000 +v -0.015633 -0.250000 0.812500 +v 0.052233 0.250000 0.062500 +v 0.023390 0.250000 0.562500 +v -0.004402 0.687500 0.500000 +v 0.031561 0.187500 0.500000 +v -0.043148 0.250000 -0.937500 +v 0.026691 0.250000 -0.437500 +v -0.013214 0.687500 -0.500000 +v 0.021597 0.187500 -0.500000 +v -0.094147 -0.750000 -0.937500 +v -0.035836 -0.750000 -0.437500 +v 0.007757 -0.312500 -0.500000 +v 0.037763 -0.250000 -0.187500 +v -0.021512 -0.750000 0.312500 +v -0.065001 -0.750000 0.812500 +v -0.008128 -0.562500 0.500000 +v 0.044614 0.250000 0.312500 +v -0.008602 0.250000 0.812500 +v 0.019607 0.437500 0.500000 +v 0.030797 -0.062500 0.500000 +v -0.004113 0.250000 -0.687500 +v 0.046366 0.250000 -0.187500 +v 0.010068 0.437500 -0.500000 +v 0.020862 -0.062500 -0.500000 +v -0.061248 -0.750000 -0.687500 +v -0.020144 -0.750000 -0.187500 +v -0.016837 -0.562500 -0.500000 +v -0.003632 -0.500000 -0.437500 +v 0.013825 -0.500000 -0.187500 +v 0.029385 -0.312500 -0.250000 +v 0.002992 -0.562500 -0.250000 +v -0.067611 -0.500000 -0.937500 +v -0.031633 -0.500000 -0.687500 +v -0.024140 -0.312500 -0.750000 +v -0.046447 -0.562500 -0.750000 +v 0.028952 0.000000 -0.437500 +v 0.048851 0.000000 -0.187500 +v 0.044497 0.187500 -0.250000 +v 0.043686 -0.062500 -0.250000 +v 0.011687 0.500000 -0.437500 +v 0.030144 0.500000 -0.187500 +v 0.006858 0.687500 -0.250000 +v 0.031889 0.437500 -0.250000 +v -0.055165 0.500000 -0.937500 +v -0.017667 0.500000 -0.687500 +v -0.043147 0.687500 -0.750000 +v -0.022057 0.437500 -0.750000 +v 0.025622 -0.000000 0.562500 +v -0.006604 -0.000000 0.812500 +v 0.001812 0.187500 0.750000 +v 0.001127 -0.062500 0.750000 +v 0.008559 0.500000 0.562500 +v -0.021966 0.500000 0.812500 +v -0.030926 0.687500 0.750000 +v -0.008981 0.437500 0.750000 +v 0.035529 0.500000 0.062500 +v 0.028520 0.500000 0.312500 +v 0.011382 0.687500 0.250000 +v 0.036867 0.437500 0.250000 +v -0.006604 -0.500000 0.562500 +v -0.035749 -0.500000 0.812500 +v -0.011151 -0.312500 0.750000 +v -0.034353 -0.562500 0.750000 +v 0.018878 -0.500000 0.062500 +v 0.012296 -0.500000 0.312500 +v 0.034309 -0.312500 0.250000 +v 0.007457 -0.562500 0.250000 +v 0.054844 -0.000000 0.062500 +v 0.047072 -0.000000 0.312500 +v 0.049808 0.187500 0.250000 +v 0.048970 -0.062500 0.250000 +v -0.041357 0.000000 -0.937500 +v -0.002086 0.000000 -0.687500 +v -0.011716 0.187500 -0.750000 +v -0.012372 -0.062500 -0.750000 +v -0.058424 0.750000 -0.812500 +v -0.080336 0.687500 -1.000000 +v -0.065715 0.687500 1.000000 +v -0.062851 0.750000 0.937500 +v -0.063490 -0.312500 -1.000000 +v -0.048042 -0.312500 1.000000 +v 0.006061 0.750000 -0.062500 +v -0.006318 -0.687500 -0.000000 +v 0.049209 0.312500 0.000000 +v 0.027335 -0.250000 0.437500 +v 0.004968 -0.250000 -0.562500 +v -0.052533 0.187500 -1.000000 +v 0.005365 0.750000 0.187500 +v -0.037138 -0.062500 1.000000 +v -0.053111 -0.062500 -1.000000 +v -0.036531 0.187500 1.000000 +v -0.029510 -0.250000 -0.812500 +v 0.041502 -0.250000 0.187500 +v 0.029277 0.562500 0.000000 +v 0.025942 -0.437500 -0.000000 +v -0.004882 0.750000 -0.312500 +v -0.068789 -0.562500 1.000000 +v -0.083270 -0.562500 -1.000000 +v -0.007081 0.750000 0.437500 +v -0.030573 0.750000 0.687500 +v -0.046110 0.437500 1.000000 +v -0.061650 0.437500 -1.000000 +v -0.027104 0.750000 -0.562500 +v 0.029819 -0.250000 -0.312500 +v 0.001127 -0.250000 0.687500 +v 0.055227 0.062500 -0.000000 +v 0.047426 -0.187500 -0.000000 +v -0.017113 -0.750000 0.187500 +v -0.050711 -0.750000 0.687500 +v 0.005862 -0.437500 0.500000 +v -0.034353 -0.250000 0.937500 +v 0.050289 0.250000 0.187500 +v 0.008559 0.250000 0.687500 +v 0.008961 0.562500 0.500000 +v 0.032547 0.062500 0.500000 +v -0.022783 0.250000 -0.812500 +v 0.038100 0.250000 -0.312500 +v -0.000241 0.562500 -0.500000 +v 0.022545 0.062500 -0.500000 +v -0.076918 -0.750000 -0.812500 +v -0.026657 -0.750000 -0.312500 +v -0.003246 -0.437500 -0.500000 +v 0.042304 -0.250000 -0.062500 +v -0.028710 -0.750000 0.437500 +v -0.081091 -0.750000 0.937500 +v -0.024410 -0.687500 0.500000 +v 0.035529 0.250000 0.437500 +v -0.027730 0.250000 0.937500 +v 0.027228 0.312500 0.500000 +v 0.025622 -0.187500 0.500000 +v 0.012499 0.250000 -0.562500 +v 0.051136 0.250000 -0.062500 +v 0.017425 0.312500 -0.500000 +v 0.015876 -0.187500 -0.500000 +v -0.047456 -0.750000 -0.562500 +v -0.016467 -0.750000 -0.062500 +v -0.032689 -0.687500 -0.500000 +v 0.006558 -0.500000 -0.312500 +v 0.017943 -0.500000 -0.062500 +v 0.017528 -0.437500 -0.250000 +v -0.013867 -0.687500 -0.250000 +v -0.048795 -0.500000 -0.812500 +v -0.016467 -0.500000 -0.562500 +v -0.034092 -0.437500 -0.750000 +v -0.060927 -0.687500 -0.750000 +v 0.040475 0.000000 -0.312500 +v 0.053715 0.000000 -0.062500 +v 0.045546 0.062500 -0.250000 +v 0.038213 -0.187500 -0.250000 +v 0.022439 0.500000 -0.312500 +v 0.034530 0.500000 -0.062500 +v 0.020757 0.562500 -0.250000 +v 0.039907 0.312500 -0.250000 +v -0.035575 0.500000 -0.812500 +v -0.001796 0.500000 -0.562500 +v -0.031368 0.562500 -0.750000 +v -0.015448 0.312500 -0.750000 +v 0.010674 -0.000000 0.687500 +v -0.025850 -0.000000 0.937500 +v 0.002697 0.062500 0.750000 +v -0.003535 -0.187500 0.750000 +v -0.005553 0.500000 0.687500 +v -0.040329 0.500000 0.937500 +v -0.018678 0.562500 0.750000 +v -0.002086 0.312500 0.750000 +v 0.033757 0.500000 0.187500 +v 0.020025 0.500000 0.437500 +v 0.025515 0.562500 0.250000 +v 0.045079 0.312500 0.250000 +v -0.020052 -0.500000 0.687500 +v -0.053357 -0.500000 0.937500 +v -0.021512 -0.437500 0.750000 +v -0.049379 -0.687500 0.750000 +v 0.017218 -0.500000 0.187500 +v 0.004275 -0.500000 0.437500 +v 0.022229 -0.437500 0.250000 +v -0.009643 -0.687500 0.250000 +v 0.052848 -0.000000 0.187500 +v 0.037876 -0.000000 0.437500 +v 0.050894 0.062500 0.250000 +v 0.043340 -0.187500 0.250000 +v -0.020874 0.000000 -0.812500 +v 0.014643 0.000000 -0.562500 +v -0.010870 0.062500 -0.750000 +v -0.016837 -0.187500 -0.750000 +v -0.005170 -0.125000 -0.687500 +v 0.011382 -0.125000 -0.562500 +v 0.005365 -0.062500 -0.625000 +v 0.000637 -0.187500 -0.625000 +v -0.001796 0.125000 -0.687500 +v 0.014951 0.125000 -0.562500 +v 0.006061 0.187500 -0.625000 +v 0.006957 0.062500 -0.625000 +v -0.041100 0.125000 -0.937500 +v -0.020601 0.125000 -0.812500 +v -0.031368 0.187500 -0.875000 +v -0.030573 0.062500 -0.875000 +v 0.043340 -0.125000 0.312500 +v 0.034309 -0.125000 0.437500 +v 0.041502 -0.062500 0.375000 +v 0.036085 -0.187500 0.375000 +v 0.047426 0.125000 0.312500 +v 0.038213 0.125000 0.437500 +v 0.042304 0.187500 0.375000 +v 0.043340 0.062500 0.375000 +v 0.055227 0.125000 0.062500 +v 0.053218 0.125000 0.187500 +v 0.053715 0.187500 0.125000 +v 0.054845 0.062500 0.125000 +v -0.003535 -0.625000 0.312500 +v -0.011151 -0.625000 0.437500 +v 0.001127 -0.562500 0.375000 +v -0.015633 -0.687500 0.375000 +v 0.025622 -0.375000 0.312500 +v 0.017218 -0.375000 0.437500 +v 0.027335 -0.312500 0.375000 +v 0.015568 -0.437500 0.375000 +v 0.032547 -0.375000 0.062500 +v 0.030797 -0.375000 0.187500 +v 0.037876 -0.312500 0.125000 +v 0.025622 -0.437500 0.125000 +v -0.049379 -0.625000 0.812500 +v -0.066269 -0.625000 0.937500 +v -0.050711 -0.562500 0.875000 +v -0.065001 -0.687500 0.875000 +v -0.024410 -0.375000 0.812500 +v -0.042637 -0.375000 0.937500 +v -0.028710 -0.312500 0.875000 +v -0.038522 -0.437500 0.875000 +v 0.005862 -0.375000 0.562500 +v -0.008127 -0.375000 0.687500 +v 0.004275 -0.312500 0.625000 +v -0.006604 -0.437500 0.625000 +v 0.038213 0.375000 0.312500 +v 0.029385 0.375000 0.437500 +v 0.029819 0.437500 0.375000 +v 0.037763 0.312500 0.375000 +v 0.015876 0.625000 0.312500 +v 0.007757 0.625000 0.437500 +v 0.004968 0.687500 0.375000 +v 0.018774 0.562500 0.375000 +v 0.022545 0.625000 0.062500 +v 0.020862 0.625000 0.187500 +v 0.014644 0.687500 0.125000 +v 0.028952 0.562500 0.125000 +v -0.013867 0.375000 0.812500 +v -0.032688 0.375000 0.937500 +v -0.026657 0.437500 0.875000 +v -0.020144 0.312500 0.875000 +v -0.032688 0.625000 0.812500 +v -0.050462 0.625000 0.937500 +v -0.047455 0.687500 0.875000 +v -0.035836 0.562500 0.875000 +v -0.003246 0.625000 0.562500 +v -0.016836 0.625000 0.687500 +v -0.016467 0.687500 0.625000 +v -0.003632 0.562500 0.625000 +v -0.009643 -0.125000 0.812500 +v -0.028710 -0.125000 0.937500 +v -0.017113 -0.062500 0.875000 +v -0.021512 -0.187500 0.875000 +v -0.006318 0.125000 0.812500 +v -0.025581 0.125000 0.937500 +v -0.016467 0.187500 0.875000 +v -0.015633 0.062500 0.875000 +v 0.025942 0.125000 0.562500 +v 0.010977 0.125000 0.687500 +v 0.017943 0.187500 0.625000 +v 0.018878 0.062500 0.625000 +v -0.009454 0.375000 -0.687500 +v 0.006858 0.375000 -0.562500 +v -0.004882 0.437500 -0.625000 +v 0.002107 0.312500 -0.625000 +v -0.028532 0.625000 -0.687500 +v -0.013214 0.625000 -0.562500 +v -0.027104 0.687500 -0.625000 +v -0.014705 0.562500 -0.625000 +v -0.064843 0.625000 -0.937500 +v -0.045857 0.625000 -0.812500 +v -0.061007 0.687500 -0.875000 +v -0.049879 0.562500 -0.875000 +v 0.039908 0.375000 -0.187500 +v 0.044497 0.375000 -0.062500 +v 0.038100 0.437500 -0.125000 +v 0.046366 0.312500 -0.125000 +v 0.017425 0.625000 -0.187500 +v 0.021597 0.625000 -0.062500 +v 0.012499 0.687500 -0.125000 +v 0.026691 0.562500 -0.125000 +v -0.000241 0.625000 -0.437500 +v 0.010068 0.625000 -0.312500 +v -0.001796 0.687500 -0.375000 +v 0.011687 0.562500 -0.375000 +v -0.045436 -0.625000 -0.687500 +v -0.030927 -0.625000 -0.562500 +v -0.030573 -0.562500 -0.625000 +v -0.045773 -0.687500 -0.625000 +v -0.018678 -0.625000 -0.437500 +v -0.008981 -0.625000 -0.312500 +v -0.005553 -0.562500 -0.375000 +v -0.021967 -0.687500 -0.375000 +v -0.079959 -0.625000 -0.937500 +v -0.061890 -0.625000 -0.812500 +v -0.064127 -0.562500 -0.875000 +v -0.077833 -0.687500 -0.875000 +v 0.025515 -0.125000 -0.437500 +v 0.036867 -0.125000 -0.312500 +v 0.033757 -0.062500 -0.375000 +v 0.028520 -0.187500 -0.375000 +v 0.020757 0.375000 -0.437500 +v 0.031889 0.375000 -0.312500 +v 0.022439 0.437500 -0.375000 +v 0.030144 0.312500 -0.375000 +v -0.047875 0.375000 -0.937500 +v -0.027819 0.375000 -0.812500 +v -0.041100 0.437500 -0.875000 +v -0.034878 0.312500 -0.875000 +v 0.022229 -0.125000 0.562500 +v 0.007457 -0.125000 0.687500 +v 0.017218 -0.062500 0.625000 +v 0.012296 -0.187500 0.625000 +v 0.017528 0.375000 0.562500 +v 0.002992 0.375000 0.687500 +v 0.006559 0.437500 0.625000 +v 0.013825 0.312500 0.625000 +v 0.045546 0.375000 0.062500 +v 0.043686 0.375000 0.187500 +v 0.040475 0.437500 0.125000 +v 0.048851 0.312500 0.125000 +v 0.029277 0.125000 -0.437500 +v 0.040817 0.125000 -0.312500 +v 0.034530 0.187500 -0.375000 +v 0.035529 0.062500 -0.375000 +v -0.021512 -0.625000 0.562500 +v -0.034353 -0.625000 0.687500 +v -0.020052 -0.562500 0.625000 +v -0.035749 -0.687500 0.625000 +v 0.002697 -0.625000 0.062500 +v 0.001126 -0.625000 0.187500 +v 0.010674 -0.562500 0.125000 +v -0.006605 -0.687500 0.125000 +v 0.049209 0.125000 -0.187500 +v 0.054089 0.125000 -0.062500 +v 0.051136 0.187500 -0.125000 +v 0.052233 0.062500 -0.125000 +v 0.050893 -0.125000 0.062500 +v 0.048970 -0.125000 0.187500 +v 0.052848 -0.062500 0.125000 +v 0.047072 -0.187500 0.125000 +v -0.044082 -0.125000 -0.937500 +v -0.023779 -0.125000 -0.812500 +v -0.031985 -0.062500 -0.875000 +v -0.036184 -0.187500 -0.875000 +v 0.008960 -0.375000 -0.437500 +v 0.019607 -0.375000 -0.312500 +v 0.020025 -0.312500 -0.375000 +v 0.008559 -0.437500 -0.375000 +v 0.027228 -0.375000 -0.187500 +v 0.031561 -0.375000 -0.062500 +v 0.035529 -0.312500 -0.125000 +v 0.023390 -0.437500 -0.125000 +v -0.002086 -0.625000 -0.187500 +v 0.001812 -0.625000 -0.062500 +v 0.008559 -0.562500 -0.125000 +v -0.008602 -0.687500 -0.125000 +v 0.045079 -0.125000 -0.187500 +v 0.049808 -0.125000 -0.062500 +v 0.050289 -0.062500 -0.125000 +v 0.044614 -0.187500 -0.125000 +v -0.057368 -0.375000 -0.937500 +v -0.037918 -0.375000 -0.812500 +v -0.043063 -0.312500 -0.875000 +v -0.052451 -0.437500 -0.875000 +v -0.020144 -0.375000 -0.687500 +v -0.004402 -0.375000 -0.562500 +v -0.007082 -0.312500 -0.625000 +v -0.017575 -0.437500 -0.625000 +v -0.010116 -0.437500 -0.562500 +v 0.000637 -0.312500 -0.562500 +v -0.015355 -0.312500 -0.687500 +v -0.043063 -0.437500 -0.812500 +v -0.033391 -0.312500 -0.812500 +v -0.053111 -0.312500 -0.937500 +v 0.046483 -0.187500 -0.062500 +v 0.052233 -0.062500 -0.062500 +v 0.047426 -0.062500 -0.187500 +v -0.007081 -0.687500 -0.062500 +v 0.010169 -0.562500 -0.062500 +v 0.006160 -0.562500 -0.187500 +v 0.025089 -0.437500 -0.062500 +v 0.037314 -0.312500 -0.062500 +v 0.032876 -0.312500 -0.187500 +v 0.013416 -0.437500 -0.312500 +v 0.025088 -0.312500 -0.312500 +v 0.014234 -0.312500 -0.437500 +v -0.026299 -0.187500 -0.812500 +v -0.021967 -0.062500 -0.812500 +v -0.042381 -0.062500 -0.937500 +v 0.045663 -0.187500 0.187500 +v 0.051379 -0.062500 0.187500 +v 0.053342 -0.062500 0.062500 +v 0.054214 0.062500 -0.062500 +v 0.053094 0.187500 -0.062500 +v 0.048255 0.187500 -0.187500 +v -0.007748 -0.687500 0.187500 +v 0.009463 -0.562500 0.187500 +v 0.011079 -0.562500 0.062500 +v -0.042296 -0.687500 0.687500 +v -0.026925 -0.562500 0.687500 +v -0.013774 -0.562500 0.562500 +v 0.040931 0.062500 -0.312500 +v 0.039907 0.187500 -0.312500 +v 0.028412 0.187500 -0.437500 +v 0.047426 0.312500 0.187500 +v 0.039115 0.437500 0.187500 +v 0.040931 0.437500 0.062500 +v 0.006160 0.312500 0.687500 +v -0.000922 0.437500 0.687500 +v 0.013416 0.437500 0.562500 +v 0.004671 -0.187500 0.687500 +v 0.009464 -0.062500 0.687500 +v 0.024344 -0.062500 0.562500 +v -0.024951 0.312500 -0.812500 +v -0.031368 0.437500 -0.812500 +v -0.051209 0.437500 -0.937500 +v 0.035418 0.312500 -0.312500 +v 0.027550 0.437500 -0.312500 +v 0.016598 0.437500 -0.437500 +v 0.033757 -0.187500 -0.312500 +v 0.039115 -0.062500 -0.312500 +v 0.027657 -0.062500 -0.437500 +v -0.069181 -0.687500 -0.812500 +v -0.055083 -0.562500 -0.812500 +v -0.073538 -0.562500 -0.937500 +v -0.017575 -0.687500 -0.312500 +v -0.000922 -0.562500 -0.312500 +v -0.010870 -0.562500 -0.437500 +v -0.038953 -0.687500 -0.562500 +v -0.023417 -0.562500 -0.562500 +v -0.038263 -0.562500 -0.687500 +v 0.016598 0.562500 -0.312500 +v 0.002893 0.687500 -0.312500 +v -0.007177 0.687500 -0.437500 +v 0.028412 0.562500 -0.062500 +v 0.014132 0.687500 -0.062500 +v 0.010068 0.687500 -0.187500 +v 0.048255 0.312500 -0.062500 +v 0.039907 0.437500 -0.062500 +v 0.035418 0.437500 -0.187500 +v -0.040415 0.562500 -0.812500 +v -0.051872 0.687500 -0.812500 +v -0.070510 0.687500 -0.937500 +v -0.007177 0.562500 -0.562500 +v -0.019870 0.687500 -0.562500 +v -0.034878 0.687500 -0.687500 +v 0.010068 0.312500 -0.562500 +v 0.002893 0.437500 -0.562500 +v -0.013214 0.437500 -0.687500 +v 0.011079 0.062500 0.687500 +v 0.010169 0.187500 0.687500 +v 0.025089 0.187500 0.562500 +v -0.025491 0.062500 0.937500 +v -0.026299 0.187500 0.937500 +v -0.007081 0.187500 0.812500 +v -0.031191 -0.187500 0.937500 +v -0.026925 -0.062500 0.937500 +v -0.007747 -0.062500 0.812500 +v -0.010869 0.562500 0.687500 +v -0.023417 0.687500 0.687500 +v -0.010116 0.687500 0.562500 +v -0.045098 0.562500 0.937500 +v -0.056391 0.687500 0.937500 +v -0.038953 0.687500 0.812500 +v -0.029864 0.312500 0.937500 +v -0.036184 0.437500 0.937500 +v -0.017574 0.437500 0.812500 +v 0.027658 0.562500 0.187500 +v 0.013416 0.687500 0.187500 +v 0.015054 0.687500 0.062500 +v 0.014234 0.562500 0.437500 +v 0.000638 0.687500 0.437500 +v 0.008559 0.687500 0.312500 +v 0.032876 0.312500 0.437500 +v 0.025089 0.437500 0.437500 +v 0.033757 0.437500 0.312500 +v -0.013774 -0.437500 0.687500 +v -0.003150 -0.312500 0.687500 +v 0.011079 -0.312500 0.562500 +v -0.047707 -0.437500 0.937500 +v -0.038176 -0.312500 0.937500 +v -0.019686 -0.312500 0.812500 +v -0.073460 -0.687500 0.937500 +v -0.059556 -0.562500 0.937500 +v -0.042296 -0.562500 0.812500 +v 0.024344 -0.437500 0.187500 +v 0.036532 -0.312500 0.187500 +v 0.038325 -0.312500 0.062500 +v 0.011079 -0.437500 0.437500 +v 0.022650 -0.312500 0.437500 +v 0.031233 -0.312500 0.312500 +v -0.019686 -0.687500 0.437500 +v -0.003150 -0.562500 0.437500 +v 0.004671 -0.562500 0.312500 +v 0.053342 0.062500 0.187500 +v 0.052233 0.187500 0.187500 +v 0.054214 0.187500 0.062500 +v 0.038325 0.062500 0.437500 +v 0.037315 0.187500 0.437500 +v 0.046483 0.187500 0.312500 +v 0.031233 -0.187500 0.437500 +v 0.036532 -0.062500 0.437500 +v 0.045663 -0.062500 0.312500 +v -0.020509 0.062500 -0.812500 +v -0.021330 0.187500 -0.812500 +v -0.041784 0.187500 -0.937500 +v 0.015054 0.062500 -0.562500 +v 0.014131 0.187500 -0.562500 +v -0.002570 0.187500 -0.687500 +v 0.008559 -0.187500 -0.562500 +v 0.013416 -0.062500 -0.562500 +v -0.003246 -0.062500 -0.687500 +v -0.007843 -0.187500 -0.687500 +v -0.001699 0.062500 -0.687500 +v -0.041015 0.062500 -0.937500 +v 0.040134 -0.187500 0.312500 +v 0.047544 0.062500 0.312500 +v 0.055355 0.062500 0.062500 +v -0.012278 -0.687500 0.312500 +v 0.019295 -0.437500 0.312500 +v 0.026049 -0.437500 0.062500 +v -0.056961 -0.687500 0.812500 +v -0.029775 -0.437500 0.812500 +v -0.000046 -0.437500 0.562500 +v 0.041845 0.312500 0.312500 +v 0.022545 0.562500 0.312500 +v 0.029385 0.562500 0.062500 +v -0.010869 0.312500 0.812500 +v -0.027015 0.562500 0.812500 +v 0.002992 0.562500 0.562500 +v -0.012278 -0.187500 0.812500 +v -0.006222 0.062500 0.812500 +v 0.026049 0.062500 0.562500 +v -0.006414 0.312500 -0.687500 +v -0.022783 0.562500 -0.687500 +v -0.059718 0.562500 -0.937500 +v 0.043571 0.312500 -0.187500 +v 0.024132 0.562500 -0.187500 +v 0.006061 0.562500 -0.437500 +v -0.053111 -0.687500 -0.687500 +v -0.027015 -0.687500 -0.437500 +v -0.086841 -0.687500 -0.937500 +v 0.022545 -0.187500 -0.437500 +v 0.024132 0.312500 -0.437500 +v -0.045182 0.312500 -0.937500 +v 0.019295 -0.187500 0.562500 +v 0.020862 0.312500 0.562500 +v 0.049329 0.312500 0.062500 +v 0.029385 0.062500 -0.437500 +v -0.029775 -0.687500 0.562500 +v -0.006223 -0.687500 0.062500 +v 0.049329 0.062500 -0.187500 +v 0.047544 -0.187500 0.062500 +v -0.046447 -0.187500 -0.937500 +v 0.002992 -0.437500 -0.437500 +v 0.020862 -0.437500 -0.187500 +v -0.010870 -0.687500 -0.187500 +v 0.041845 -0.187500 -0.187500 +v -0.062211 -0.437500 -0.937500 +v -0.025581 -0.437500 -0.687500 +v 0.057771 0.806906 -1.042254 +v 0.072535 0.574872 -1.082113 +v 0.089029 0.574880 1.082128 +v 0.100492 0.814405 0.848339 +v 0.064640 -0.508208 -1.084176 +v 0.080781 -0.508219 1.084199 +v 0.148042 0.839132 -0.244747 +v 0.089485 0.034154 -1.092952 +v 0.155358 0.842702 0.035113 +v 0.099482 -0.238624 1.090851 +v 0.082354 -0.238622 -1.090843 +v 0.107012 0.034154 1.092951 +v 0.127297 0.828827 -0.518017 +v 0.052964 -0.772998 1.075474 +v 0.038229 -0.772974 -1.075442 +v 0.149549 0.836932 0.313850 +v 0.130350 0.825850 0.584978 +v 0.103680 0.306428 1.089525 +v 0.086369 0.306428 -1.089522 +v 0.096156 0.817145 -0.783097 +v 0.129980 -0.842851 0.035119 +v 0.107082 -0.825887 0.585003 +v 0.039276 -0.806877 -1.042216 +v 0.104147 -0.828862 -0.518039 +v 0.124723 -0.837039 0.313889 +v 0.079357 -0.814398 0.848330 +v 0.075205 -0.817132 -0.783085 +v 0.123263 -0.839242 -0.244779 +v 0.077681 0.811777 -0.913250 +v 0.061948 0.707255 -1.077723 +v 0.077852 0.707268 1.077744 +v 0.082519 0.809289 0.977892 +v 0.074720 -0.373977 -1.087931 +v 0.091419 -0.373983 1.087947 +v 0.153527 0.842082 -0.105260 +v 0.089222 0.170606 -1.091883 +v 0.154225 0.840848 0.175177 +v 0.104734 -0.102431 1.092592 +v 0.087325 -0.102431 -1.092590 +v 0.106717 0.170606 1.091882 +v 0.139173 0.834456 -0.382459 +v 0.067858 -0.641217 1.079944 +v 0.052378 -0.641200 -1.079915 +v 0.141474 0.831686 0.450497 +v 0.116561 0.819979 0.717482 +v 0.097721 0.441252 1.086162 +v 0.080751 0.441249 -1.086152 +v 0.112823 0.822909 -0.651469 +v 0.128974 -0.840985 0.175205 +v 0.094311 -0.819990 0.717490 +v 0.057938 -0.811754 -0.913223 +v 0.115110 -0.834528 -0.382492 +v 0.117329 -0.831756 0.450534 +v 0.062564 -0.809272 0.977869 +v 0.090727 -0.822915 -0.651474 +v 0.128294 -0.842222 -0.105278 +v 0.067882 0.809277 -0.977877 +v 0.067522 0.641216 -1.079944 +v 0.083734 0.641227 1.079962 +v 0.091720 0.811785 0.913259 +v 0.069970 -0.441244 -1.086137 +v 0.086405 -0.441252 1.086157 +v 0.151228 0.840868 -0.175181 +v 0.089578 0.102430 -1.092592 +v 0.155202 0.842070 0.105259 +v 0.102472 -0.170608 1.091884 +v 0.085183 -0.170607 -1.091879 +v 0.107103 0.102430 1.092591 +v 0.133585 0.831715 -0.450512 +v 0.060636 -0.707255 1.077720 +v 0.045520 -0.707234 -1.077689 +v 0.145916 0.834426 0.382446 +v 0.123764 0.822893 0.651458 +v 0.101055 0.373982 1.087949 +v 0.083897 0.373980 -1.087943 +v 0.104739 0.819988 -0.717490 +v 0.129851 -0.842215 0.105277 +v 0.100991 -0.822916 0.651474 +v 0.048760 -0.809250 -0.977844 +v 0.109958 -0.831767 -0.450541 +v 0.121402 -0.834515 0.382485 +v 0.071169 -0.811772 0.913242 +v 0.083206 -0.819984 -0.717486 +v 0.126186 -0.840995 -0.175207 +v 0.087120 0.814403 -0.848336 +v 0.055848 0.773001 -1.075480 +v 0.071420 0.773017 1.075503 +v 0.072933 0.806922 1.042275 +v 0.078857 -0.306426 -1.089514 +v 0.095788 -0.306430 1.089526 +v 0.154910 0.842706 -0.035112 +v 0.088149 0.238623 -1.090849 +v 0.152331 0.839105 0.244740 +v 0.106252 -0.034156 1.092952 +v 0.088762 -0.034155 -1.092952 +v 0.105573 0.238623 1.090849 +v 0.144009 0.836962 -0.313860 +v 0.074586 -0.574874 1.082115 +v 0.058764 -0.574860 -1.082089 +v 0.136269 0.828802 0.518002 +v 0.108788 0.817141 0.783095 +v 0.093702 0.508221 1.084208 +v 0.076954 0.508216 -1.084195 +v 0.120359 0.825871 -0.584992 +v 0.127257 -0.839229 0.244775 +v 0.087085 -0.817142 0.783094 +v 0.066768 -0.814384 -0.848316 +v 0.119559 -0.837052 -0.313895 +v 0.112542 -0.828855 0.518034 +v 0.053586 -0.806901 1.042246 +v 0.097722 -0.825890 -0.585006 +v 0.129563 -0.842853 -0.035119 +v 0.070117 0.797881 1.066642 +v 0.054731 0.797865 -1.066619 +v 0.146128 0.838095 -0.279365 +v 0.089213 -0.000000 -1.092997 +v 0.155251 0.842783 0.000000 +v 0.097722 -0.272556 1.090223 +v 0.080687 -0.272554 -1.090213 +v 0.106727 -0.000001 1.092997 +v 0.123906 0.827353 -0.551569 +v 0.051144 -0.797860 1.066612 +v 0.036612 -0.797836 -1.066580 +v 0.151049 0.838066 0.279356 +v 0.133396 0.827330 0.551554 +v 0.104719 0.272555 1.090222 +v 0.087347 0.272555 -1.090220 +v 0.091691 0.815760 -0.815760 +v 0.129879 -0.842932 -0.000000 +v 0.109894 -0.827375 0.551583 +v 0.101009 -0.827380 -0.551587 +v 0.077753 -0.541586 1.083170 +v 0.061768 -0.541573 -1.083145 +v 0.104702 0.815759 0.815760 +v 0.091446 0.541590 1.083181 +v 0.074821 0.541583 -1.083167 +v 0.126090 -0.838182 0.279393 +v 0.083281 -0.815756 0.815755 +v 0.071039 -0.815744 -0.815744 +v 0.121507 -0.838195 -0.279399 +v 0.072823 0.810511 -0.945597 +v 0.064803 0.674273 -1.078838 +v 0.080864 0.674285 1.078858 +v 0.087170 0.810521 0.945609 +v 0.072420 -0.407647 -1.087058 +v 0.088990 -0.407654 1.087076 +v 0.152490 0.841545 -0.140257 +v 0.089490 0.136535 -1.092280 +v 0.154830 0.841529 0.140255 +v 0.103695 -0.136536 1.092280 +v 0.086341 -0.136535 -1.092277 +v 0.107006 0.136534 1.092278 +v 0.136470 0.833109 -0.416555 +v 0.064306 -0.674273 1.078836 +v 0.049006 -0.674254 -1.078807 +v 0.143793 0.833079 0.416540 +v 0.120237 0.821428 0.684524 +v 0.099475 0.407654 1.087079 +v 0.082407 0.407651 -1.087071 +v 0.108846 0.821441 -0.684534 +v 0.129519 -0.841670 0.140278 +v 0.097722 -0.821445 0.684537 +v 0.053390 -0.810486 -0.945567 +v 0.112619 -0.833171 -0.416586 +v 0.119457 -0.833159 0.416579 +v 0.066916 -0.810506 0.945589 +v 0.087029 -0.821441 -0.684534 +v 0.127343 -0.841679 -0.140280 +v 0.062863 0.808076 -1.010095 +v 0.070101 0.608083 -1.081036 +v 0.086457 0.608092 1.081054 +v 0.096163 0.813079 0.880837 +v 0.067376 -0.474764 -1.085175 +v 0.083667 -0.474774 1.085196 +v 0.149744 0.840060 -0.210015 +v 0.089577 0.068301 -1.092817 +v 0.155341 0.842463 0.070206 +v 0.101067 -0.204639 1.091406 +v 0.083853 -0.204638 -1.091400 +v 0.107105 0.068300 1.092815 +v 0.130525 0.830284 -0.484332 +v 0.056854 -0.740162 1.076598 +v 0.041926 -0.740140 -1.076567 +v 0.147837 0.835714 0.348215 +v 0.127137 0.824369 0.618278 +v 0.102458 0.340239 1.088766 +v 0.085219 0.340238 -1.088761 +v 0.100507 0.818555 -0.750342 +v 0.129971 -0.842611 0.070217 +v 0.104113 -0.824399 0.618298 +v 0.044053 -0.808047 -1.010059 +v 0.107133 -0.830328 -0.484358 +v 0.123159 -0.835812 0.348254 +v 0.075318 -0.813069 0.880824 +v 0.079263 -0.818546 -0.750334 +v 0.124825 -0.840179 -0.210045 +v 0.082448 0.813075 -0.880831 +v 0.058962 0.740164 -1.076602 +v 0.074703 0.740178 1.076625 +v 0.077771 0.808089 1.010113 +v 0.076867 -0.340235 -1.088752 +v 0.093686 -0.340240 1.088766 +v 0.154334 0.842471 -0.070206 +v 0.088775 0.204638 -1.091404 +v 0.153391 0.840036 0.210010 +v 0.105587 -0.068302 1.092816 +v 0.088132 -0.068301 -1.092816 +v 0.106239 0.204638 1.091404 +v 0.141688 0.835745 -0.348227 +v 0.071286 -0.608085 1.081038 +v 0.055633 -0.608068 -1.081010 +v 0.138964 0.830257 0.484317 +v 0.112742 0.818548 0.750337 +v 0.095795 0.474775 1.085203 +v 0.078932 0.474771 -1.085192 +v 0.116663 0.824387 -0.618290 +v 0.128219 -0.840167 0.210041 +v 0.090764 -0.818554 0.750341 +v 0.062400 -0.813053 -0.880807 +v 0.117425 -0.835826 -0.348261 +v 0.115022 -0.830318 0.484352 +v 0.058119 -0.808070 1.010086 +v 0.094293 -0.824400 -0.618300 +v 0.129034 -0.842615 -0.070218 +v 0.001375 0.863474 -1.115320 +v 0.017038 0.618236 -1.163737 +v 0.034776 0.618252 1.163768 +v 0.047111 0.878429 0.915030 +v 0.008489 -0.547430 -1.167851 +v 0.025876 -0.547452 1.167899 +v 0.099745 0.927738 -0.270590 +v 0.035188 0.037043 -1.185352 +v 0.108049 0.934859 0.038953 +v 0.046028 -0.258379 1.181164 +v 0.027481 -0.258375 -1.181147 +v 0.054196 0.037042 1.185351 +v 0.076488 0.907189 -0.566993 +v -0.003753 -0.826922 1.150500 +v -0.019514 -0.826874 -1.150435 +v 0.101292 0.923351 0.346257 +v 0.079725 0.901253 0.638387 +v 0.050567 0.331459 1.178519 +v 0.031843 0.331457 -1.178513 +v 0.042428 0.883892 -0.847062 +v 0.079900 -0.935154 0.038964 +v 0.054333 -0.901324 0.638438 +v -0.018414 -0.863414 -1.115244 +v 0.051150 -0.907256 -0.567036 +v 0.073905 -0.923562 0.346336 +v 0.024315 -0.878413 0.915013 +v 0.019767 -0.883864 -0.847038 +v 0.072353 -0.927955 -0.270654 +v 0.022568 0.873189 -0.982336 +v 0.005788 0.757958 -1.154983 +v 0.022832 0.757985 1.155025 +v 0.027816 0.868227 1.049108 +v 0.019273 -0.404023 -1.175341 +v 0.037313 -0.404034 1.175373 +v 0.105982 0.933622 -0.116703 +v 0.034911 0.184879 -1.183220 +v 0.106683 0.931161 0.193992 +v 0.051724 -0.111059 1.184635 +v 0.032848 -0.111058 -1.184630 +v 0.053869 0.184878 1.183219 +v 0.089736 0.918414 -0.420940 +v 0.012064 -0.688401 1.159413 +v -0.004554 -0.688366 -1.159355 +v 0.092139 0.912890 0.494482 +v 0.064558 0.889544 0.778351 +v 0.044123 0.476049 1.171812 +v 0.025814 0.476042 -1.171793 +v 0.060551 0.895386 -0.708846 +v 0.078724 -0.931432 0.194048 +v 0.040421 -0.889563 0.778368 +v 0.001333 -0.873139 -0.982283 +v 0.063253 -0.918555 -0.421005 +v 0.065638 -0.913029 0.494557 +v 0.006409 -0.868190 1.049063 +v 0.036508 -0.895396 -0.708856 +v 0.078010 -0.933898 -0.116738 +v 0.012114 0.868203 -1.049078 +v 0.011704 0.688401 -1.159412 +v 0.029108 0.688423 1.159449 +v 0.037669 0.873204 0.982354 +v 0.014184 -0.476028 -1.171763 +v 0.031914 -0.476045 1.171803 +v 0.103365 0.931201 -0.194000 +v 0.035291 0.111060 -1.184633 +v 0.107838 0.933598 0.116700 +v 0.049269 -0.184878 1.183224 +v 0.030533 -0.184876 -1.183213 +v 0.054293 0.111060 1.184632 +v 0.083481 0.912947 -0.494513 +v 0.004383 -0.757955 1.154979 +v -0.011816 -0.757913 -1.154917 +v 0.097155 0.918354 0.420912 +v 0.072455 0.895356 0.708823 +v 0.047724 0.404035 1.175375 +v 0.029187 0.404032 -1.175363 +v 0.051733 0.889562 -0.778366 +v 0.079737 -0.933886 0.116735 +v 0.047676 -0.895399 0.708858 +v -0.008399 -0.868147 -1.049012 +v 0.057547 -0.913050 -0.494570 +v 0.070178 -0.918529 0.420992 +v 0.015563 -0.873176 0.982322 +v 0.028374 -0.889551 -0.778358 +v 0.075636 -0.931452 -0.194053 +v 0.032689 0.878424 -0.915024 +v -0.000668 0.826930 -1.150511 +v 0.015991 0.826963 1.150557 +v 0.017600 0.863506 1.115362 +v 0.023717 -0.331452 -1.178497 +v 0.042031 -0.331459 1.178522 +v 0.107552 0.934865 -0.038953 +v 0.033757 0.258379 -1.181158 +v 0.104486 0.927686 0.270575 +v 0.053372 -0.037042 1.185352 +v 0.034404 -0.037042 -1.185351 +v 0.052622 0.258379 1.181160 +v 0.095180 0.923410 -0.346278 +v 0.019244 -0.618238 1.163743 +v 0.002229 -0.618209 -1.163690 +v 0.086307 0.907139 0.566962 +v 0.056092 0.883885 0.847057 +v 0.039794 0.547460 1.167915 +v 0.021754 0.547449 -1.167890 +v 0.068822 0.901293 -0.638415 +v 0.076768 -0.927930 0.270646 +v 0.032617 -0.883885 0.847057 +v 0.010737 -0.878384 -0.914984 +v 0.068207 -0.923589 -0.346347 +v 0.060338 -0.907242 0.567026 +v -0.003102 -0.863462 1.115305 +v 0.044118 -0.901330 -0.638443 +v 0.079438 -0.935157 -0.038965 +v 0.014607 0.853245 1.140654 +v -0.001845 0.853211 -1.140608 +v 0.097577 0.925670 -0.308556 +v 0.034893 0.000001 -1.185443 +v 0.107935 0.935020 0.000000 +v 0.044122 -0.294978 1.179911 +v 0.025686 -0.294972 -1.179890 +v 0.053887 0.000000 1.185442 +v 0.072735 0.904250 -0.602833 +v -0.005681 -0.853201 1.140595 +v -0.021219 -0.853152 -1.140530 +v 0.103010 0.925614 0.308538 +v 0.083106 0.904204 0.602803 +v 0.051694 0.294977 1.179908 +v 0.032894 0.294976 -1.179903 +v 0.037609 0.881130 -0.881129 +v 0.079791 -0.935315 -0.000001 +v 0.057421 -0.904291 0.602860 +v 0.047710 -0.904301 -0.602868 +v 0.022631 -0.582923 1.165847 +v 0.005427 -0.582898 -1.165797 +v 0.051662 0.881130 0.881129 +v 0.037369 0.582934 1.165868 +v 0.019475 0.582920 -1.165840 +v 0.075447 -0.925842 0.308614 +v 0.028525 -0.881121 0.881121 +v 0.015302 -0.881096 -0.881097 +v 0.070385 -0.925869 -0.308624 +v 0.017379 0.870664 -1.015774 +v 0.008816 0.723255 -1.157206 +v 0.026044 0.723279 1.157246 +v 0.032791 0.870684 1.015798 +v 0.016807 -0.440099 -1.173599 +v 0.034696 -0.440113 1.173635 +v 0.104802 0.932552 -0.155425 +v 0.035198 0.148002 -1.184011 +v 0.107393 0.932519 0.155420 +v 0.050596 -0.148001 1.184014 +v 0.031784 -0.148000 -1.184006 +v 0.054185 0.148001 1.184010 +v 0.086705 0.915728 -0.457864 +v 0.008283 -0.723253 1.157205 +v -0.008127 -0.723215 -1.157145 +v 0.094753 0.915669 0.457834 +v 0.068581 0.892434 0.743695 +v 0.046016 0.440115 1.173640 +v 0.027588 0.440110 -1.173625 +v 0.056206 0.892458 -0.743715 +v 0.079350 -0.932799 0.155466 +v 0.044120 -0.892465 0.743721 +v -0.003495 -0.870611 -1.015714 +v 0.060490 -0.915849 -0.457925 +v 0.068007 -0.915826 0.457912 +v 0.011033 -0.870651 1.015759 +v 0.032503 -0.892458 -0.743716 +v 0.076939 -0.932816 -0.155470 +v 0.006777 0.865807 -1.082257 +v 0.014446 0.653396 -1.161591 +v 0.032021 0.653414 1.161625 +v 0.042445 0.875786 0.948768 +v 0.011410 -0.511806 -1.169844 +v 0.028972 -0.511826 1.169887 +v 0.101677 0.929590 -0.232397 +v 0.035288 0.074068 -1.185082 +v 0.108016 0.934382 0.077865 +v 0.047745 -0.221676 1.182271 +v 0.029098 -0.221673 -1.182258 +v 0.054297 0.074068 1.185081 +v 0.080072 0.910094 -0.530888 +v 0.000369 -0.792510 1.152742 +v -0.015613 -0.792465 -1.152678 +v 0.099338 0.920923 0.383718 +v 0.076172 0.898299 0.673724 +v 0.049242 0.367814 1.177005 +v 0.030606 0.367812 -1.176996 +v 0.047138 0.886704 -0.812811 +v 0.079882 -0.934675 0.077889 +v 0.051083 -0.898356 0.673767 +v -0.013374 -0.865748 -1.082186 +v 0.054431 -0.910179 -0.530939 +v 0.072146 -0.921116 0.383798 +v 0.019992 -0.875764 0.948744 +v 0.024126 -0.886684 -0.812795 +v 0.074106 -0.929824 -0.232457 +v 0.027673 0.875776 -0.948756 +v 0.002625 0.792516 -1.152749 +v 0.019479 0.792545 1.152793 +v 0.022750 0.865835 1.082293 +v 0.021578 -0.367805 -1.176977 +v 0.039760 -0.367814 1.177006 +v 0.106900 0.934397 -0.077866 +v 0.034430 0.221675 -1.182266 +v 0.105712 0.929543 0.232386 +v 0.052650 -0.074067 1.185082 +v 0.033722 -0.074067 -1.185080 +v 0.053348 0.221675 1.182267 +v 0.092563 0.920983 -0.383743 +v 0.015720 -0.653397 1.161595 +v -0.001099 -0.653365 -1.161539 +v 0.089321 0.910040 0.530857 +v 0.060393 0.886692 0.812801 +v 0.042047 0.511831 1.169899 +v 0.023868 0.511822 -1.169878 +v 0.064758 0.898334 -0.673750 +v 0.077862 -0.929801 0.232450 +v 0.036584 -0.886701 0.812809 +v 0.006079 -0.875730 -0.948709 +v 0.065828 -0.921143 -0.383810 +v 0.063080 -0.910161 0.530927 +v 0.001695 -0.865794 1.082242 +v 0.040382 -0.898357 -0.673769 +v 0.078844 -0.934682 -0.077891 +v -0.475166 0.863474 -1.115320 +v -0.459503 0.618236 -1.163737 +v -0.441765 0.618252 1.163768 +v -0.429430 0.878429 0.915030 +v -0.468052 -0.547430 -1.167851 +v -0.450665 -0.547452 1.167899 +v -0.376796 0.929603 -0.270590 +v -0.441353 0.037043 -1.185352 +v -0.368492 0.937408 0.038953 +v -0.430513 -0.258379 1.181164 +v -0.449060 -0.258375 -1.181147 +v -0.422345 0.037042 1.185351 +v -0.400054 0.907193 -0.566993 +v -0.480294 -0.826922 1.150500 +v -0.496055 -0.826874 -1.150435 +v -0.375249 0.924043 0.346257 +v -0.396816 0.901253 0.638387 +v -0.425974 0.331459 1.178519 +v -0.444698 0.331457 -1.178513 +v -0.434113 0.883892 -0.847062 +v -0.396641 -0.935154 0.038964 +v -0.422208 -0.901324 0.638438 +v -0.494955 -0.863414 -1.115244 +v -0.425391 -0.907256 -0.567036 +v -0.402636 -0.923562 0.346336 +v -0.452226 -0.878413 0.915013 +v -0.456774 -0.883864 -0.847038 +v -0.404188 -0.927955 -0.270654 +v -0.453973 0.873189 -0.982336 +v -0.470753 0.757958 -1.154983 +v -0.453709 0.757985 1.155025 +v -0.448725 0.868227 1.049108 +v -0.457268 -0.404023 -1.175341 +v -0.439228 -0.404034 1.175373 +v -0.370559 0.936193 -0.116703 +v -0.441630 0.184879 -1.183220 +v -0.369858 0.932999 0.193992 +v -0.424817 -0.111059 1.184635 +v -0.443693 -0.111058 -1.184630 +v -0.422672 0.184878 1.183219 +v -0.386806 0.919130 -0.420940 +v -0.464477 -0.688401 1.159413 +v -0.481095 -0.688366 -1.159355 +v -0.384402 0.912893 0.494482 +v -0.411983 0.889544 0.778351 +v -0.432419 0.476049 1.171812 +v -0.450727 0.476042 -1.171793 +v -0.415990 0.895386 -0.708846 +v -0.397817 -0.931432 0.194048 +v -0.436120 -0.889563 0.778368 +v -0.475208 -0.873139 -0.982283 +v -0.413288 -0.918555 -0.421005 +v -0.410903 -0.913029 0.494557 +v -0.470132 -0.868190 1.049063 +v -0.440033 -0.895396 -0.708856 +v -0.398531 -0.933898 -0.116738 +v -0.464427 0.868203 -1.049078 +v -0.464837 0.688401 -1.159412 +v -0.447433 0.688423 1.159449 +v -0.438872 0.873204 0.982354 +v -0.462357 -0.476028 -1.171763 +v -0.444627 -0.476045 1.171803 +v -0.373176 0.933514 -0.194000 +v -0.441250 0.111060 -1.184633 +v -0.368703 0.935888 0.116700 +v -0.427272 -0.184878 1.183224 +v -0.446008 -0.184876 -1.183213 +v -0.422248 0.111060 1.184632 +v -0.393060 0.913184 -0.494513 +v -0.472158 -0.757955 1.154979 +v -0.488357 -0.757913 -1.154917 +v -0.379386 0.918576 0.420912 +v -0.404086 0.895356 0.708823 +v -0.428817 0.404035 1.175375 +v -0.447354 0.404032 -1.175363 +v -0.424808 0.889562 -0.778366 +v -0.396804 -0.933886 0.116735 +v -0.428865 -0.895399 0.708858 +v -0.484941 -0.868147 -1.049012 +v -0.418994 -0.913050 -0.494570 +v -0.406363 -0.918529 0.420992 +v -0.460978 -0.873176 0.982322 +v -0.448167 -0.889551 -0.778358 +v -0.400905 -0.931452 -0.194053 +v -0.443852 0.878424 -0.915024 +v -0.477209 0.826930 -1.150511 +v -0.460551 0.826963 1.150557 +v -0.458941 0.863506 1.115362 +v -0.452824 -0.331452 -1.178497 +v -0.434510 -0.331459 1.178522 +v -0.368989 0.937465 -0.038953 +v -0.442784 0.258379 -1.181158 +v -0.372055 0.928958 0.270575 +v -0.423169 -0.037042 1.185352 +v -0.442137 -0.037042 -1.185351 +v -0.423919 0.258379 1.181160 +v -0.381361 0.924709 -0.346278 +v -0.457297 -0.618238 1.163743 +v -0.474312 -0.618209 -1.163690 +v -0.390234 0.907139 0.566962 +v -0.420449 0.883885 0.847057 +v -0.436747 0.547460 1.167915 +v -0.454787 0.547449 -1.167890 +v -0.407719 0.901293 -0.638415 +v -0.399773 -0.927930 0.270646 +v -0.443924 -0.883885 0.847057 +v -0.465804 -0.878384 -0.914984 +v -0.408334 -0.923589 -0.346347 +v -0.416203 -0.907242 0.567026 +v -0.479643 -0.863462 1.115305 +v -0.432423 -0.901330 -0.638443 +v -0.397103 -0.935157 -0.038965 +v -0.461934 0.853245 1.140654 +v -0.478386 0.853211 -1.140608 +v -0.378964 0.927261 -0.308556 +v -0.441648 0.000001 -1.185443 +v -0.368606 0.937608 0.000000 +v -0.432419 -0.294978 1.179911 +v -0.450855 -0.294972 -1.179890 +v -0.422654 0.000000 1.185442 +v -0.403806 0.904250 -0.602833 +v -0.482222 -0.853201 1.140595 +v -0.497760 -0.853152 -1.140530 +v -0.373531 0.926590 0.308538 +v -0.393435 0.904204 0.602803 +v -0.424847 0.294977 1.179908 +v -0.443647 0.294976 -1.179903 +v -0.438932 0.881130 -0.881129 +v -0.396750 -0.935315 -0.000001 +v -0.419120 -0.904291 0.602860 +v -0.428831 -0.904301 -0.602868 +v -0.453910 -0.582923 1.165847 +v -0.471114 -0.582898 -1.165797 +v -0.424879 0.881130 0.881129 +v -0.439172 0.582934 1.165868 +v -0.457066 0.582920 -1.165840 +v -0.401094 -0.925842 0.308614 +v -0.448016 -0.881121 0.881121 +v -0.461239 -0.881096 -0.881097 +v -0.406156 -0.925869 -0.308624 +v -0.459162 0.870664 -1.015774 +v -0.467725 0.723255 -1.157206 +v -0.450498 0.723279 1.157246 +v -0.443750 0.870684 1.015798 +v -0.459734 -0.440099 -1.173599 +v -0.441845 -0.440113 1.173635 +v -0.371739 0.935020 -0.155425 +v -0.441343 0.148002 -1.184011 +v -0.369148 0.934602 0.155420 +v -0.425945 -0.148001 1.184014 +v -0.444757 -0.148000 -1.184006 +v -0.422356 0.148001 1.184010 +v -0.389836 0.916182 -0.457864 +v -0.468258 -0.723253 1.157205 +v -0.484668 -0.723215 -1.157145 +v -0.381788 0.915740 0.457834 +v -0.407960 0.892434 0.743695 +v -0.430525 0.440115 1.173640 +v -0.448953 0.440110 -1.173625 +v -0.420335 0.892458 -0.743715 +v -0.397191 -0.932799 0.155466 +v -0.432421 -0.892465 0.743721 +v -0.480036 -0.870611 -1.015714 +v -0.416051 -0.915849 -0.457925 +v -0.408535 -0.915826 0.457912 +v -0.465508 -0.870651 1.015759 +v -0.444038 -0.892458 -0.743716 +v -0.399602 -0.932816 -0.155470 +v -0.469764 0.865807 -1.082257 +v -0.462095 0.653396 -1.161591 +v -0.444520 0.653414 1.161625 +v -0.434096 0.875786 0.948768 +v -0.465131 -0.511806 -1.169844 +v -0.447569 -0.511826 1.169887 +v -0.374864 0.931698 -0.232397 +v -0.441253 0.074068 -1.185082 +v -0.368525 0.936831 0.077865 +v -0.428796 -0.221676 1.182271 +v -0.447443 -0.221673 -1.182258 +v -0.422244 0.074068 1.185081 +v -0.396469 0.910174 -0.530888 +v -0.476172 -0.792510 1.152742 +v -0.492154 -0.792465 -1.152678 +v -0.377203 0.921357 0.383718 +v -0.400369 0.898299 0.673724 +v -0.427299 0.367814 1.177005 +v -0.445935 0.367812 -1.176996 +v -0.429403 0.886704 -0.812811 +v -0.396659 -0.934675 0.077889 +v -0.425458 -0.898356 0.673767 +v -0.489915 -0.865748 -1.082186 +v -0.422110 -0.910179 -0.530939 +v -0.404395 -0.921116 0.383798 +v -0.456549 -0.875764 0.948744 +v -0.452415 -0.886684 -0.812795 +v -0.402436 -0.929824 -0.232457 +v -0.448868 0.875776 -0.948756 +v -0.473916 0.792516 -1.152749 +v -0.457062 0.792545 1.152793 +v -0.453791 0.865835 1.082293 +v -0.454963 -0.367805 -1.176977 +v -0.436782 -0.367814 1.177006 +v -0.369641 0.937012 -0.077866 +v -0.442111 0.221675 -1.182266 +v -0.370829 0.931106 0.232386 +v -0.423891 -0.074067 1.185082 +v -0.442819 -0.074067 -1.185080 +v -0.423193 0.221675 1.182267 +v -0.383978 0.921985 -0.383743 +v -0.460822 -0.653397 1.161595 +v -0.477640 -0.653365 -1.161539 +v -0.387220 0.910040 0.530857 +v -0.416149 0.886692 0.812801 +v -0.434494 0.511831 1.169899 +v -0.452673 0.511822 -1.169878 +v -0.411783 0.898334 -0.673750 +v -0.398679 -0.929801 0.232450 +v -0.439957 -0.886701 0.812809 +v -0.470462 -0.875730 -0.948709 +v -0.410713 -0.921143 -0.383810 +v -0.413461 -0.910161 0.530927 +v -0.474846 -0.865794 1.082242 +v -0.436159 -0.898357 -0.673769 +v -0.397697 -0.934682 -0.077891 +v -0.483184 0.863474 -1.115320 +v -0.467521 0.618236 -1.163737 +v -0.449783 0.618252 1.163768 +v -0.437448 0.878429 0.915030 +v -0.476069 -0.547430 -1.167851 +v -0.458683 -0.547452 1.167899 +v -0.384814 0.929857 -0.270590 +v -0.449371 0.037043 -1.185352 +v -0.376510 0.937708 0.038953 +v -0.438531 -0.258379 1.181164 +v -0.457078 -0.258375 -1.181147 +v -0.430363 0.037042 1.185351 +v -0.408071 0.907211 -0.566993 +v -0.488312 -0.826922 1.150500 +v -0.504073 -0.826874 -1.150435 +v -0.383267 0.924199 0.346257 +v -0.404834 0.901253 0.638387 +v -0.433992 0.331459 1.178519 +v -0.452716 0.331457 -1.178513 +v -0.442131 0.883892 -0.847062 +v -0.404659 -0.935154 0.038964 +v -0.430226 -0.901324 0.638438 +v -0.502973 -0.863414 -1.115244 +v -0.433409 -0.907256 -0.567036 +v -0.410654 -0.923562 0.346336 +v -0.460244 -0.878413 0.915013 +v -0.464792 -0.883864 -0.847038 +v -0.412206 -0.927955 -0.270654 +v -0.461991 0.873189 -0.982336 +v -0.478771 0.757958 -1.154983 +v -0.461727 0.757985 1.155025 +v -0.456743 0.868227 1.049108 +v -0.465286 -0.404023 -1.175341 +v -0.447246 -0.404034 1.175373 +v -0.378577 0.936494 -0.116703 +v -0.449648 0.184879 -1.183220 +v -0.377876 0.933253 0.193992 +v -0.432835 -0.111059 1.184635 +v -0.451711 -0.111058 -1.184630 +v -0.430690 0.184878 1.183219 +v -0.394823 0.919285 -0.420940 +v -0.472495 -0.688401 1.159413 +v -0.489112 -0.688366 -1.159355 +v -0.392420 0.912908 0.494482 +v -0.420001 0.889544 0.778351 +v -0.440436 0.476049 1.171812 +v -0.458745 0.476042 -1.171793 +v -0.424008 0.895386 -0.708846 +v -0.405835 -0.931432 0.194048 +v -0.444138 -0.889563 0.778368 +v -0.483226 -0.873139 -0.982283 +v -0.421306 -0.918555 -0.421005 +v -0.418921 -0.913029 0.494557 +v -0.478150 -0.868190 1.049063 +v -0.448051 -0.895396 -0.708856 +v -0.406549 -0.933898 -0.116738 +v -0.472445 0.868203 -1.049078 +v -0.472855 0.688401 -1.159412 +v -0.455451 0.688423 1.159449 +v -0.446890 0.873204 0.982354 +v -0.470375 -0.476028 -1.171763 +v -0.452645 -0.476045 1.171803 +v -0.381194 0.933798 -0.194000 +v -0.449268 0.111060 -1.184633 +v -0.376721 0.936172 0.116700 +v -0.435290 -0.184878 1.183224 +v -0.454026 -0.184876 -1.183213 +v -0.430266 0.111060 1.184632 +v -0.401078 0.913275 -0.494513 +v -0.480176 -0.757955 1.154979 +v -0.496375 -0.757913 -1.154917 +v -0.387403 0.918666 0.420912 +v -0.412104 0.895356 0.708823 +v -0.436835 0.404035 1.175375 +v -0.455372 0.404032 -1.175363 +v -0.432826 0.889562 -0.778366 +v -0.404822 -0.933886 0.116735 +v -0.436882 -0.895399 0.708858 +v -0.492958 -0.868147 -1.049012 +v -0.427011 -0.913050 -0.494570 +v -0.414381 -0.918529 0.420992 +v -0.468996 -0.873176 0.982322 +v -0.456185 -0.889551 -0.778358 +v -0.408923 -0.931452 -0.194053 +v -0.451870 0.878424 -0.915024 +v -0.485227 0.826930 -1.150511 +v -0.468568 0.826963 1.150557 +v -0.466959 0.863506 1.115362 +v -0.460842 -0.331452 -1.178497 +v -0.442528 -0.331459 1.178522 +v -0.377007 0.937769 -0.038953 +v -0.450802 0.258379 -1.181158 +v -0.380073 0.929169 0.270575 +v -0.431187 -0.037042 1.185352 +v -0.450155 -0.037042 -1.185351 +v -0.431937 0.258379 1.181160 +v -0.389379 0.924920 -0.346278 +v -0.465315 -0.618238 1.163743 +v -0.482329 -0.618209 -1.163690 +v -0.398252 0.907139 0.566962 +v -0.428467 0.883885 0.847057 +v -0.444765 0.547460 1.167915 +v -0.462805 0.547449 -1.167890 +v -0.415737 0.901293 -0.638415 +v -0.407791 -0.927930 0.270646 +v -0.451942 -0.883885 0.847057 +v -0.473822 -0.878384 -0.914984 +v -0.416352 -0.923589 -0.346347 +v -0.424221 -0.907242 0.567026 +v -0.487661 -0.863462 1.115305 +v -0.440441 -0.901330 -0.638443 +v -0.405120 -0.935157 -0.038965 +v -0.469952 0.853245 1.140654 +v -0.486404 0.853211 -1.140608 +v -0.386982 0.927495 -0.308556 +v -0.449666 0.000001 -1.185443 +v -0.376624 0.937911 0.000000 +v -0.440437 -0.294978 1.179911 +v -0.458873 -0.294972 -1.179890 +v -0.430671 0.000000 1.185442 +v -0.411824 0.904250 -0.602833 +v -0.490240 -0.853201 1.140595 +v -0.505778 -0.853152 -1.140530 +v -0.381549 0.926775 0.308538 +v -0.401453 0.904204 0.602803 +v -0.432864 0.294977 1.179908 +v -0.451665 0.294976 -1.179903 +v -0.446950 0.881130 -0.881129 +v -0.404768 -0.935315 -0.000001 +v -0.427138 -0.904291 0.602860 +v -0.436849 -0.904301 -0.602868 +v -0.461928 -0.582923 1.165847 +v -0.479132 -0.582898 -1.165797 +v -0.432896 0.881130 0.881129 +v -0.447190 0.582934 1.165868 +v -0.465083 0.582920 -1.165840 +v -0.409111 -0.925842 0.308614 +v -0.456034 -0.881121 0.881121 +v -0.469257 -0.881096 -0.881097 +v -0.414174 -0.925869 -0.308624 +v -0.467180 0.870664 -1.015774 +v -0.475743 0.723255 -1.157206 +v -0.458515 0.723279 1.157246 +v -0.451768 0.870684 1.015798 +v -0.467752 -0.440099 -1.173599 +v -0.449863 -0.440113 1.173635 +v -0.379757 0.935315 -0.155425 +v -0.449361 0.148002 -1.184011 +v -0.377166 0.934873 0.155420 +v -0.433963 -0.148001 1.184014 +v -0.452775 -0.148000 -1.184006 +v -0.430374 0.148001 1.184010 +v -0.397854 0.916307 -0.457864 +v -0.476276 -0.723253 1.157205 +v -0.492686 -0.723215 -1.157145 +v -0.389806 0.915794 0.457834 +v -0.415978 0.892434 0.743695 +v -0.438543 0.440115 1.173640 +v -0.456971 0.440110 -1.173625 +v -0.428353 0.892458 -0.743715 +v -0.405209 -0.932799 0.155466 +v -0.440439 -0.892465 0.743721 +v -0.488054 -0.870611 -1.015714 +v -0.424069 -0.915849 -0.457925 +v -0.416552 -0.915826 0.457912 +v -0.473526 -0.870651 1.015759 +v -0.452056 -0.892458 -0.743716 +v -0.407620 -0.932816 -0.155470 +v -0.477782 0.865807 -1.082257 +v -0.470113 0.653396 -1.161591 +v -0.452538 0.653414 1.161625 +v -0.442114 0.875786 0.948768 +v -0.473149 -0.511806 -1.169844 +v -0.455587 -0.511826 1.169887 +v -0.382882 0.931969 -0.232397 +v -0.449271 0.074068 -1.185082 +v -0.376543 0.937125 0.077865 +v -0.436814 -0.221676 1.182271 +v -0.455461 -0.221673 -1.182258 +v -0.430262 0.074068 1.185081 +v -0.404486 0.910229 -0.530888 +v -0.484190 -0.792510 1.152742 +v -0.500172 -0.792465 -1.152678 +v -0.385221 0.921482 0.383718 +v -0.408387 0.898299 0.673724 +v -0.435317 0.367814 1.177005 +v -0.453953 0.367812 -1.176996 +v -0.437421 0.886704 -0.812811 +v -0.404677 -0.934675 0.077889 +v -0.433476 -0.898356 0.673767 +v -0.497933 -0.865748 -1.082186 +v -0.430128 -0.910179 -0.530939 +v -0.412413 -0.921116 0.383798 +v -0.464567 -0.875764 0.948744 +v -0.460433 -0.886684 -0.812795 +v -0.410453 -0.929824 -0.232457 +v -0.456886 0.875776 -0.948756 +v -0.481934 0.792516 -1.152749 +v -0.465080 0.792545 1.152793 +v -0.461808 0.865835 1.082293 +v -0.462981 -0.367805 -1.176977 +v -0.444799 -0.367814 1.177006 +v -0.377659 0.937316 -0.077866 +v -0.450129 0.221675 -1.182266 +v -0.378847 0.931340 0.232386 +v -0.431909 -0.074067 1.185082 +v -0.450837 -0.074067 -1.185080 +v -0.431211 0.221675 1.182267 +v -0.391996 0.922170 -0.383743 +v -0.468839 -0.653397 1.161595 +v -0.485658 -0.653365 -1.161539 +v -0.395238 0.910040 0.530857 +v -0.424166 0.886692 0.812801 +v -0.442512 0.511831 1.169899 +v -0.460691 0.511822 -1.169878 +v -0.419801 0.898334 -0.673750 +v -0.406697 -0.929801 0.232450 +v -0.447975 -0.886701 0.812809 +v -0.478480 -0.875730 -0.948709 +v -0.418731 -0.921143 -0.383810 +v -0.421479 -0.910161 0.530927 +v -0.482864 -0.865794 1.082242 +v -0.444177 -0.898357 -0.673769 +v -0.405715 -0.934682 -0.077891 +v -0.860065 0.863474 -1.115320 +v -0.844402 0.618236 -1.163737 +v -0.826664 0.618252 1.163768 +v -0.814329 0.878429 0.915030 +v -0.852951 -0.547430 -1.167851 +v -0.835564 -0.547452 1.167899 +v -0.761695 0.949603 -0.270590 +v -0.826253 0.037043 -1.185352 +v -0.753392 0.959705 0.038953 +v -0.815413 -0.258379 1.181164 +v -0.833959 -0.258375 -1.181147 +v -0.807244 0.037042 1.185351 +v -0.784953 0.916810 -0.566993 +v -0.865193 -0.826922 1.150500 +v -0.880955 -0.826874 -1.150435 +v -0.760149 0.940121 0.346257 +v -0.781716 0.905263 0.638387 +v -0.810874 0.331459 1.178519 +v -0.829598 0.331457 -1.178513 +v -0.819012 0.884117 -0.847062 +v -0.781540 -0.935154 0.038964 +v -0.807107 -0.901324 0.638438 +v -0.879854 -0.863414 -1.115244 +v -0.810291 -0.907256 -0.567036 +v -0.787535 -0.923562 0.346336 +v -0.837125 -0.878413 0.915013 +v -0.841673 -0.883864 -0.847038 +v -0.789087 -0.927955 -0.270654 +v -0.838873 0.873189 -0.982336 +v -0.855652 0.757958 -1.154983 +v -0.838608 0.757985 1.155025 +v -0.833624 0.868227 1.049108 +v -0.842167 -0.404023 -1.175341 +v -0.824127 -0.404034 1.175373 +v -0.755459 0.958441 -0.116703 +v -0.826530 0.184879 -1.183220 +v -0.754758 0.953327 0.193992 +v -0.809716 -0.111059 1.184635 +v -0.828592 -0.111058 -1.184630 +v -0.807571 0.184878 1.183219 +v -0.771705 0.934718 -0.420940 +v -0.849376 -0.688401 1.159413 +v -0.865994 -0.688366 -1.159355 +v -0.769301 0.923008 0.494482 +v -0.796882 0.889895 0.778351 +v -0.817318 0.476049 1.171812 +v -0.835626 0.476042 -1.171793 +v -0.800890 0.899011 -0.708846 +v -0.782716 -0.931432 0.194048 +v -0.821020 -0.889563 0.778368 +v -0.860107 -0.873139 -0.982283 +v -0.798187 -0.918555 -0.421005 +v -0.795802 -0.913029 0.494557 +v -0.855031 -0.868190 1.049063 +v -0.824932 -0.895396 -0.708856 +v -0.783430 -0.933898 -0.116738 +v -0.849326 0.868203 -1.049078 +v -0.849737 0.688401 -1.159412 +v -0.832332 0.688423 1.159449 +v -0.823771 0.873204 0.982354 +v -0.847256 -0.476028 -1.171763 +v -0.829526 -0.476045 1.171803 +v -0.758076 0.954940 -0.194000 +v -0.826149 0.111060 -1.184633 +v -0.753602 0.957514 0.116700 +v -0.812172 -0.184878 1.183224 +v -0.830907 -0.184876 -1.183213 +v -0.807147 0.111060 1.184632 +v -0.777959 0.925941 -0.494513 +v -0.857058 -0.757955 1.154979 +v -0.873256 -0.757913 -1.154917 +v -0.764285 0.931846 0.420912 +v -0.788985 0.897111 0.708823 +v -0.813716 0.404035 1.175375 +v -0.832253 0.404032 -1.175363 +v -0.809707 0.891042 -0.778366 +v -0.781703 -0.933886 0.116735 +v -0.813764 -0.895399 0.708858 +v -0.869840 -0.868147 -1.049012 +v -0.803893 -0.913050 -0.494570 +v -0.791262 -0.918529 0.420992 +v -0.845877 -0.873176 0.982322 +v -0.833067 -0.889551 -0.778358 +v -0.785804 -0.931452 -0.194053 +v -0.828752 0.878424 -0.915024 +v -0.862108 0.826930 -1.150511 +v -0.845450 0.826963 1.150557 +v -0.843840 0.863506 1.115362 +v -0.837723 -0.331452 -1.178497 +v -0.819410 -0.331459 1.178522 +v -0.753889 0.959891 -0.038953 +v -0.827684 0.258379 -1.181158 +v -0.756954 0.947414 0.270575 +v -0.808069 -0.037042 1.185352 +v -0.827036 -0.037042 -1.185351 +v -0.808818 0.258379 1.181160 +v -0.766260 0.942739 -0.346278 +v -0.842196 -0.618238 1.163743 +v -0.859211 -0.618209 -1.163690 +v -0.775133 0.914016 0.566962 +v -0.805349 0.883885 0.847057 +v -0.821646 0.547460 1.167915 +v -0.839687 0.547449 -1.167890 +v -0.792618 0.907712 -0.638415 +v -0.784672 -0.927930 0.270646 +v -0.828823 -0.883885 0.847057 +v -0.850703 -0.878384 -0.914984 +v -0.793233 -0.923589 -0.346347 +v -0.801102 -0.907242 0.567026 +v -0.864542 -0.863462 1.115305 +v -0.817322 -0.901330 -0.638443 +v -0.782002 -0.935157 -0.038965 +v -0.846833 0.853245 1.140654 +v -0.863285 0.853211 -1.140608 +v -0.763864 0.946340 -0.308556 +v -0.826548 0.000001 -1.185443 +v -0.753505 0.959993 0.000000 +v -0.817319 -0.294978 1.179911 +v -0.835754 -0.294972 -1.179890 +v -0.807553 0.000000 1.185442 +v -0.788706 0.912234 -0.602833 +v -0.867121 -0.853201 1.140595 +v -0.882660 -0.853152 -1.140530 +v -0.758430 0.943915 0.308538 +v -0.778334 0.909586 0.602803 +v -0.809746 0.294977 1.179908 +v -0.828547 0.294976 -1.179903 +v -0.823831 0.881137 -0.881129 +v -0.781649 -0.935315 -0.000001 +v -0.804020 -0.904291 0.602860 +v -0.813731 -0.904301 -0.602868 +v -0.838809 -0.582923 1.165847 +v -0.856013 -0.582898 -1.165797 +v -0.809778 0.881130 0.881129 +v -0.824071 0.582934 1.165868 +v -0.841965 0.582920 -1.165840 +v -0.785993 -0.925842 0.308614 +v -0.832915 -0.881121 0.881121 +v -0.846138 -0.881096 -0.881097 +v -0.791056 -0.925869 -0.308624 +v -0.844061 0.870664 -1.015774 +v -0.852624 0.723255 -1.157206 +v -0.835397 0.723279 1.157246 +v -0.828649 0.870684 1.015798 +v -0.844633 -0.440099 -1.173599 +v -0.826744 -0.440113 1.173635 +v -0.756639 0.956936 -0.155425 +v -0.826242 0.148002 -1.184011 +v -0.754048 0.955655 0.155420 +v -0.810844 -0.148001 1.184014 +v -0.829656 -0.148000 -1.184006 +v -0.807256 0.148001 1.184010 +v -0.774735 0.930399 -0.457864 +v -0.853157 -0.723253 1.157205 +v -0.869568 -0.723215 -1.157145 +v -0.766687 0.927471 0.457834 +v -0.792859 0.893366 0.743695 +v -0.815424 0.440115 1.173640 +v -0.833852 0.440110 -1.173625 +v -0.805234 0.894915 -0.743715 +v -0.782090 -0.932799 0.155466 +v -0.817320 -0.892465 0.743721 +v -0.864935 -0.870611 -1.015714 +v -0.800950 -0.915849 -0.457925 +v -0.793434 -0.915826 0.457912 +v -0.850407 -0.870651 1.015759 +v -0.828937 -0.892458 -0.743716 +v -0.784501 -0.932816 -0.155470 +v -0.854663 0.865807 -1.082257 +v -0.846994 0.653396 -1.161591 +v -0.829419 0.653414 1.161625 +v -0.818995 0.875786 0.948768 +v -0.850030 -0.511806 -1.169844 +v -0.832468 -0.511826 1.169887 +v -0.759763 0.952484 -0.232397 +v -0.826152 0.074068 -1.185082 +v -0.753424 0.958874 0.077865 +v -0.813696 -0.221676 1.182271 +v -0.832342 -0.221673 -1.182258 +v -0.807144 0.074068 1.185081 +v -0.781368 0.921395 -0.530888 +v -0.861072 -0.792510 1.152742 +v -0.877054 -0.792465 -1.152678 +v -0.762103 0.936080 0.383718 +v -0.785268 0.901090 0.673724 +v -0.812198 0.367814 1.177005 +v -0.830834 0.367812 -1.176996 +v -0.814302 0.887430 -0.812811 +v -0.781558 -0.934675 0.077889 +v -0.810357 -0.898356 0.673767 +v -0.874815 -0.865748 -1.082186 +v -0.807009 -0.910179 -0.530939 +v -0.789294 -0.921116 0.383798 +v -0.841448 -0.875764 0.948744 +v -0.837314 -0.886684 -0.812795 +v -0.787335 -0.929824 -0.232457 +v -0.833768 0.875776 -0.948756 +v -0.858815 0.792516 -1.152749 +v -0.841961 0.792545 1.152793 +v -0.838690 0.865835 1.082293 +v -0.839862 -0.367805 -1.176977 +v -0.821681 -0.367814 1.177006 +v -0.754541 0.959431 -0.077866 +v -0.827011 0.221675 -1.182266 +v -0.755728 0.950566 0.232386 +v -0.808790 -0.074067 1.185082 +v -0.827719 -0.074067 -1.185080 +v -0.808092 0.221675 1.182267 +v -0.768877 0.938848 -0.383743 +v -0.845721 -0.653397 1.161595 +v -0.862540 -0.653365 -1.161539 +v -0.772119 0.918506 0.530857 +v -0.801048 0.886735 0.812801 +v -0.819393 0.511831 1.169899 +v -0.837572 0.511822 -1.169878 +v -0.796682 0.903290 -0.673750 +v -0.783578 -0.929801 0.232450 +v -0.824856 -0.886701 0.812809 +v -0.855361 -0.875730 -0.948709 +v -0.795613 -0.921143 -0.383810 +v -0.798360 -0.910161 0.530927 +v -0.859745 -0.865794 1.082242 +v -0.821059 -0.898357 -0.673769 +v -0.782596 -0.934682 -0.077891 +v -0.474364 0.845974 -1.092717 +v -0.458985 0.604821 -1.138487 +v -0.441631 0.604835 1.138514 +v -0.429569 0.858624 0.894401 +v -0.467333 -0.535296 -1.141966 +v -0.450332 -0.535316 1.142007 +v -0.378533 0.903008 -0.262598 +v -0.441215 0.036149 -1.156770 +v -0.370539 0.909805 0.037765 +v -0.430634 -0.252269 1.153228 +v -0.448742 -0.252265 -1.153212 +v -0.422665 0.036149 1.156770 +v -0.401004 0.883094 -0.551845 +v -0.479393 -0.810240 1.127290 +v -0.494837 -0.810199 -1.127234 +v -0.376997 0.897873 0.336235 +v -0.397820 0.877931 0.621868 +v -0.426200 0.323716 1.150991 +v -0.444486 0.323714 -1.150984 +v -0.434148 0.863245 -0.827276 +v -0.397831 -0.906606 0.037775 +v -0.422555 -0.877990 0.621909 +v -0.493753 -0.845923 -1.092652 +v -0.425665 -0.883007 -0.551880 +v -0.403592 -0.896801 0.336300 +v -0.451852 -0.858610 0.894385 +v -0.456280 -0.863221 -0.827254 +v -0.405118 -0.900517 -0.262651 +v -0.453574 0.854191 -0.960965 +v -0.470026 0.742273 -1.131082 +v -0.453335 0.742296 1.131119 +v -0.448450 0.849995 1.027078 +v -0.456770 -0.394728 -1.148301 +v -0.439145 -0.394738 1.148329 +v -0.372532 0.908783 -0.113164 +v -0.441487 0.180463 -1.154966 +v -0.371831 0.905867 0.188174 +v -0.425076 -0.108391 1.156164 +v -0.443499 -0.108390 -1.156158 +v -0.422981 0.180463 1.154966 +v -0.388186 0.893733 -0.409038 +v -0.463865 -0.673805 1.134829 +v -0.480131 -0.673775 -1.134779 +v -0.385811 0.887903 0.480879 +v -0.412555 0.868026 0.759523 +v -0.432491 0.465285 1.145318 +v -0.450385 0.465279 -1.145301 +v -0.416482 0.872967 -0.691099 +v -0.398953 -0.903457 0.188220 +v -0.436108 -0.868042 0.759536 +v -0.474347 -0.854149 -0.960918 +v -0.413920 -0.892564 -0.409092 +v -0.411583 -0.887891 0.480940 +v -0.469408 -0.849964 1.027039 +v -0.439923 -0.872975 -0.691106 +v -0.399657 -0.905544 -0.113193 +v -0.463822 0.849974 -1.027052 +v -0.464218 0.673804 -1.134828 +v -0.447182 0.673823 1.134860 +v -0.438801 0.854204 0.960981 +v -0.461752 -0.465268 -1.145275 +v -0.444424 -0.465282 1.145309 +v -0.375050 0.906447 -0.188180 +v -0.441114 0.108390 -1.156161 +v -0.370731 0.908445 0.113162 +v -0.427472 -0.180464 1.154970 +v -0.445760 -0.180462 -1.154960 +v -0.422570 0.108390 1.156162 +v -0.394231 0.888441 -0.480904 +v -0.471402 -0.742271 1.131078 +v -0.487266 -0.742235 -1.131025 +v -0.380975 0.892986 0.409016 +v -0.404876 0.872943 0.691080 +v -0.428973 0.394739 1.148332 +v -0.447084 0.394735 -1.148320 +v -0.425069 0.868041 -0.759535 +v -0.397983 -0.905534 0.113191 +v -0.429034 -0.872978 0.691107 +v -0.483905 -0.849927 -1.026995 +v -0.419451 -0.887908 -0.480950 +v -0.407191 -0.892543 0.409082 +v -0.460426 -0.854180 0.960952 +v -0.447864 -0.868031 -0.759528 +v -0.401948 -0.903474 -0.188224 +v -0.443667 0.858619 -0.894395 +v -0.476370 0.810247 -1.127299 +v -0.460047 0.810275 1.127339 +v -0.458468 0.846002 1.092753 +v -0.452422 -0.323710 -1.150970 +v -0.434536 -0.323717 1.150993 +v -0.371021 0.909864 -0.037765 +v -0.442615 0.252267 -1.153222 +v -0.373932 0.902261 0.262585 +v -0.423469 -0.036149 1.156771 +v -0.441980 -0.036149 -1.156769 +v -0.424195 0.252268 1.153225 +v -0.382932 0.898683 -0.336252 +v -0.456827 -0.604824 1.138491 +v -0.473472 -0.604799 -1.138446 +v -0.391446 0.882910 0.551819 +v -0.420804 0.863240 0.827272 +v -0.436722 0.535322 1.142021 +v -0.454363 0.535312 -1.141999 +v -0.408441 0.877965 -0.621891 +v -0.400833 -0.900496 0.262644 +v -0.443730 -0.863239 0.827270 +v -0.465123 -0.858585 -0.894360 +v -0.409125 -0.896823 -0.336309 +v -0.416722 -0.882996 0.551872 +v -0.478751 -0.845965 1.092704 +v -0.432506 -0.877994 -0.621913 +v -0.398279 -0.906609 -0.037776 +v -0.461406 0.836118 1.117759 +v -0.477528 0.836089 -1.117719 +v -0.380622 0.900941 -0.299528 +v -0.441503 0.000000 -1.156846 +v -0.370650 0.909984 0.000000 +v -0.432495 -0.288042 1.152168 +v -0.450497 -0.288037 -1.152149 +v -0.422966 -0.000000 1.156847 +v -0.404643 0.880488 -0.586977 +v -0.481287 -0.836081 1.117707 +v -0.496514 -0.836039 -1.117652 +v -0.375347 0.900147 0.299513 +v -0.394545 0.880427 0.586952 +v -0.425100 0.288041 1.152166 +v -0.443459 0.288040 -1.152161 +v -0.438856 0.860909 -0.860908 +v -0.397937 -0.906742 -0.000000 +v -0.419555 -0.880500 0.586999 +v -0.429010 -0.880508 -0.587005 +v -0.453509 -0.570136 1.140271 +v -0.470335 -0.570114 -1.140228 +v -0.425125 0.860909 0.860909 +v -0.439094 0.570144 1.140290 +v -0.456595 0.570133 -1.140265 +v -0.402105 -0.898729 0.299576 +v -0.447731 -0.860901 0.860901 +v -0.460651 -0.860879 -0.860880 +v -0.407019 -0.898751 -0.299584 +v -0.458659 0.852056 -0.994065 +v -0.467052 0.708102 -1.132963 +v -0.450186 0.708123 1.132997 +v -0.443576 0.852073 0.994086 +v -0.459184 -0.430060 -1.146828 +v -0.441703 -0.430073 1.146859 +v -0.373667 0.907764 -0.150734 +v -0.441206 0.144454 -1.155635 +v -0.371154 0.907298 0.150730 +v -0.426177 -0.144455 1.155638 +v -0.444538 -0.144454 -1.155631 +v -0.422674 0.144454 1.155635 +v -0.391113 0.891112 -0.445087 +v -0.467574 -0.708101 1.132961 +v -0.483641 -0.708068 -1.132910 +v -0.383289 0.890450 0.445063 +v -0.408641 0.870471 0.725393 +v -0.430641 0.430074 1.146865 +v -0.448649 0.430069 -1.146850 +v -0.420711 0.870491 -0.725409 +v -0.398352 -0.904615 0.150769 +v -0.432500 -0.870497 0.725413 +v -0.479087 -0.852011 -0.994013 +v -0.416597 -0.890276 -0.445138 +v -0.409291 -0.890256 0.445128 +v -0.464869 -0.852045 0.994052 +v -0.443831 -0.870490 -0.725408 +v -0.400690 -0.904629 -0.150772 +v -0.469060 0.847947 -1.059934 +v -0.461527 0.639378 -1.136672 +v -0.444329 0.639394 1.136702 +v -0.434130 0.856389 0.927755 +v -0.464470 -0.500347 -1.143651 +v -0.447301 -0.500364 1.143689 +v -0.376674 0.904853 -0.225475 +v -0.441117 0.072284 -1.156541 +v -0.370566 0.909288 0.075497 +v -0.428959 -0.216406 1.154164 +v -0.447162 -0.216403 -1.154151 +v -0.422566 0.072283 1.156541 +v -0.397530 0.885756 -0.516489 +v -0.475344 -0.776316 1.129186 +v -0.491000 -0.776278 -1.129132 +v -0.378875 0.895473 0.372738 +v -0.401266 0.875432 0.656575 +v -0.427492 0.359284 1.149711 +v -0.445696 0.359282 -1.149701 +v -0.429551 0.865623 -0.793488 +v -0.397846 -0.906201 0.075516 +v -0.425717 -0.875479 0.656609 +v -0.488796 -0.847898 -1.059873 +v -0.422476 -0.885479 -0.516530 +v -0.405289 -0.894732 0.372804 +v -0.456085 -0.856369 0.927733 +v -0.452016 -0.865606 -0.793473 +v -0.403425 -0.902097 -0.225525 +v -0.448575 0.856380 -0.927744 +v -0.473133 0.776320 -1.129193 +v -0.456624 0.776346 1.129231 +v -0.453416 0.847971 1.059965 +v -0.454515 -0.359276 -1.149685 +v -0.436755 -0.359285 1.149710 +v -0.371649 0.909486 -0.075497 +v -0.441957 0.216405 -1.154159 +v -0.372758 0.904178 0.225466 +v -0.424173 -0.072284 1.156542 +v -0.442646 -0.072284 -1.156539 +v -0.423488 0.216405 1.154161 +v -0.385456 0.896269 -0.372758 +v -0.460281 -0.639380 1.136674 +v -0.476739 -0.639352 -1.136627 +v -0.388532 0.885381 0.516463 +v -0.416611 0.865614 0.793480 +v -0.434519 0.500368 1.143700 +v -0.452291 0.500360 -1.143681 +v -0.412390 0.875461 -0.656596 +v -0.399781 -0.902078 0.225519 +v -0.439854 -0.865621 0.793485 +v -0.469691 -0.856341 -0.927703 +v -0.411427 -0.894754 -0.372815 +v -0.414062 -0.885465 0.516521 +v -0.474037 -0.847937 1.059920 +v -0.436146 -0.875480 -0.656610 +v -0.398852 -0.906207 -0.075518 +v -0.482220 0.845978 -1.092721 +v -0.466829 0.604823 -1.138490 +v -0.449475 0.604836 1.138515 +v -0.437406 0.858624 0.894400 +v -0.475173 -0.535299 -1.141970 +v -0.458172 -0.535317 1.142009 +v -0.386315 0.903290 -0.262594 +v -0.449040 0.036149 -1.156771 +v -0.378313 0.910127 0.037765 +v -0.438462 -0.252269 1.153228 +v -0.456570 -0.252266 -1.153215 +v -0.430490 0.036149 1.156768 +v -0.408808 0.883157 -0.551841 +v -0.487249 -0.810244 1.127295 +v -0.502693 -0.810204 -1.127240 +v -0.384783 0.898062 0.336230 +v -0.405631 0.877925 0.621864 +v -0.434030 0.323716 1.150990 +v -0.452317 0.323715 -1.150986 +v -0.441979 0.863245 -0.827276 +v -0.405604 -0.906597 0.037774 +v -0.430365 -0.877989 0.621908 +v -0.501609 -0.845928 -1.092657 +v -0.433468 -0.883006 -0.551879 +v -0.411378 -0.896795 0.336298 +v -0.459689 -0.858612 0.894387 +v -0.464111 -0.863224 -0.827256 +v -0.412898 -0.900510 -0.262649 +v -0.461418 0.854193 -0.960967 +v -0.477878 0.742276 -1.131086 +v -0.461187 0.742298 1.131121 +v -0.456299 0.849996 1.027080 +v -0.464604 -0.394730 -1.148304 +v -0.446979 -0.394739 1.148330 +v -0.380308 0.909107 -0.113162 +v -0.449313 0.180464 -1.154967 +v -0.379609 0.906147 0.188170 +v -0.432902 -0.108391 1.156163 +v -0.451324 -0.108390 -1.156160 +v -0.430807 0.180463 1.154965 +v -0.395977 0.893925 -0.409034 +v -0.471713 -0.673807 1.134832 +v -0.487979 -0.673778 -1.134784 +v -0.393609 0.887961 0.480874 +v -0.420379 0.868024 0.759521 +v -0.440328 0.465285 1.145318 +v -0.458222 0.465280 -1.145303 +v -0.424299 0.872965 -0.691097 +v -0.406730 -0.903449 0.188218 +v -0.443932 -0.868042 0.759537 +v -0.482191 -0.854153 -0.960922 +v -0.421711 -0.892561 -0.409091 +v -0.419381 -0.887887 0.480938 +v -0.477257 -0.849967 1.027042 +v -0.447740 -0.872976 -0.691107 +v -0.407432 -0.905535 -0.113192 +v -0.471672 0.849977 -1.027055 +v -0.472066 0.673806 -1.134832 +v -0.455030 0.673824 1.134862 +v -0.446644 0.854205 0.960981 +v -0.469589 -0.465269 -1.145279 +v -0.452260 -0.465283 1.145311 +v -0.382828 0.906756 -0.188177 +v -0.448940 0.108390 -1.156163 +v -0.378507 0.908753 0.113160 +v -0.435298 -0.180464 1.154969 +v -0.453586 -0.180463 -1.154962 +v -0.430395 0.108390 1.156160 +v -0.402029 0.888573 -0.480900 +v -0.479254 -0.742273 1.131082 +v -0.495118 -0.742239 -1.131031 +v -0.388767 0.893115 0.409011 +v -0.412693 0.872939 0.691077 +v -0.436807 0.394739 1.148332 +v -0.454918 0.394736 -1.148322 +v -0.432893 0.868040 -0.759535 +v -0.405757 -0.905525 0.113190 +v -0.436851 -0.872978 0.691107 +v -0.491755 -0.849931 -1.027000 +v -0.427249 -0.887905 -0.480949 +v -0.414982 -0.892538 0.409080 +v -0.468270 -0.854183 0.960955 +v -0.455688 -0.868033 -0.759529 +v -0.409725 -0.903467 -0.188223 +v -0.451504 0.858621 -0.894396 +v -0.484226 0.810250 -1.127304 +v -0.467904 0.810277 1.127342 +v -0.466323 0.846004 1.092756 +v -0.460253 -0.323711 -1.150973 +v -0.442367 -0.323717 1.150993 +v -0.378795 0.910189 -0.037764 +v -0.450443 0.252268 -1.153223 +v -0.381714 0.902501 0.262581 +v -0.431294 -0.036149 1.156769 +v -0.449805 -0.036149 -1.156770 +v -0.432024 0.252267 1.153224 +v -0.390718 0.898926 -0.336248 +v -0.464671 -0.604825 1.138494 +v -0.481316 -0.604802 -1.138451 +v -0.399250 0.882903 0.551815 +v -0.428634 0.863239 0.827271 +v -0.444562 0.535322 1.142022 +v -0.462203 0.535314 -1.142002 +v -0.416251 0.877961 -0.621889 +v -0.408614 -0.900488 0.262642 +v -0.451561 -0.863241 0.827272 +v -0.472961 -0.858588 -0.894363 +v -0.416910 -0.896818 -0.336307 +v -0.424525 -0.882993 0.551870 +v -0.486606 -0.845968 1.092708 +v -0.440316 -0.877994 -0.621913 +v -0.406052 -0.906600 -0.037775 +v -0.469263 0.836120 1.117762 +v -0.485385 0.836093 -1.117723 +v -0.388406 0.901205 -0.299524 +v -0.449327 0.000000 -1.156847 +v -0.378425 0.910309 0.000000 +v -0.440324 -0.288042 1.152168 +v -0.458326 -0.288038 -1.152152 +v -0.430791 -0.000000 1.156845 +v -0.412450 0.880515 -0.586974 +v -0.489144 -0.836084 1.117712 +v -0.504371 -0.836043 -1.117658 +v -0.383131 0.900363 0.299509 +v -0.402352 0.880421 0.586948 +v -0.432929 0.288041 1.152165 +v -0.451288 0.288041 -1.152162 +v -0.446690 0.860909 -0.860909 +v -0.405711 -0.906733 -0.000000 +v -0.427362 -0.880498 0.586998 +v -0.436817 -0.880507 -0.587005 +v -0.461351 -0.570137 1.140274 +v -0.478177 -0.570116 -1.140233 +v -0.432959 0.860908 0.860909 +v -0.446936 0.570145 1.140291 +v -0.464437 0.570134 -1.140268 +v -0.409888 -0.898722 0.299574 +v -0.455565 -0.860903 0.860902 +v -0.468485 -0.860882 -0.860883 +v -0.414802 -0.898746 -0.299582 +v -0.466505 0.852058 -0.994068 +v -0.474902 0.708104 -1.132967 +v -0.458036 0.708124 1.132999 +v -0.451423 0.852074 0.994087 +v -0.467019 -0.430062 -1.146832 +v -0.449538 -0.430073 1.146861 +v -0.381444 0.908082 -0.150732 +v -0.449032 0.144455 -1.155637 +v -0.378931 0.907593 0.150728 +v -0.434002 -0.144455 1.155637 +v -0.452363 -0.144454 -1.155633 +v -0.430500 0.144454 1.155634 +v -0.398908 0.891275 -0.445083 +v -0.475424 -0.708104 1.132965 +v -0.491491 -0.708072 -1.132915 +v -0.391084 0.890545 0.445059 +v -0.416461 0.870468 0.725391 +v -0.438476 0.430074 1.146864 +v -0.456484 0.430070 -1.146852 +v -0.428532 0.870489 -0.725408 +v -0.406128 -0.904606 0.150767 +v -0.440320 -0.870497 0.725413 +v -0.486934 -0.852015 -0.994017 +v -0.424391 -0.890273 -0.445137 +v -0.417085 -0.890252 0.445125 +v -0.472716 -0.852048 0.994055 +v -0.451651 -0.870491 -0.725410 +v -0.408466 -0.904620 -0.150770 +v -0.476912 0.847950 -1.059937 +v -0.469373 0.639380 -1.136675 +v -0.452175 0.639395 1.136703 +v -0.441970 0.856389 0.927755 +v -0.472309 -0.500349 -1.143655 +v -0.455140 -0.500365 1.143691 +v -0.384454 0.905150 -0.225472 +v -0.448942 0.072284 -1.156542 +v -0.378341 0.909605 0.075495 +v -0.436786 -0.216406 1.154164 +v -0.454989 -0.216404 -1.154154 +v -0.430391 0.072283 1.156539 +v -0.405331 0.885855 -0.516485 +v -0.483198 -0.776319 1.129190 +v -0.498854 -0.776282 -1.129137 +v -0.386664 0.895633 0.372733 +v -0.409080 0.875428 0.656571 +v -0.435324 0.359284 1.149710 +v -0.453528 0.359282 -1.149703 +v -0.437378 0.865623 -0.793488 +v -0.405620 -0.906192 0.075516 +v -0.433531 -0.875478 0.656608 +v -0.496649 -0.847902 -1.059878 +v -0.430277 -0.885478 -0.516529 +v -0.413077 -0.894726 0.372802 +v -0.463926 -0.856372 0.927735 +v -0.459843 -0.865609 -0.793475 +v -0.411204 -0.902090 -0.225523 +v -0.456415 0.856381 -0.927746 +v -0.480987 0.776323 -1.129197 +v -0.464478 0.776347 1.129233 +v -0.461268 0.847973 1.059967 +v -0.462347 -0.359277 -1.149688 +v -0.444587 -0.359285 1.149711 +v -0.379424 0.909813 -0.075496 +v -0.449784 0.216405 -1.154161 +v -0.380538 0.904440 0.225462 +v -0.431998 -0.072284 1.156541 +v -0.450471 -0.072284 -1.156541 +v -0.431316 0.216405 1.154160 +v -0.393245 0.896488 -0.372754 +v -0.468127 -0.639382 1.136678 +v -0.484585 -0.639355 -1.136632 +v -0.396333 0.885402 0.516458 +v -0.424439 0.865612 0.793478 +v -0.442358 0.500369 1.143700 +v -0.460130 0.500362 -1.143683 +v -0.420203 0.875459 -0.656594 +v -0.407560 -0.902070 0.225517 +v -0.447681 -0.865622 0.793486 +v -0.477531 -0.856345 -0.927707 +v -0.419215 -0.894750 -0.372813 +v -0.421863 -0.885461 0.516519 +v -0.481890 -0.847940 1.059924 +v -0.443959 -0.875481 -0.656611 +v -0.406626 -0.906198 -0.075517 +v -1.156713 0.483817 -0.827696 +v -1.144587 0.288986 -0.842425 +v -1.131746 0.285881 0.842395 +v -1.122844 0.481751 0.652505 +v -1.150561 -0.559301 -0.838463 +v -1.138077 -0.559279 0.838417 +v -1.090221 0.488413 -0.168858 +v -1.131158 -0.139993 -0.821621 +v -1.085806 0.484632 0.023838 +v -1.123636 -0.346882 0.825649 +v -1.136601 -0.346886 -0.825668 +v -1.117983 -0.140557 0.821620 +v -1.103589 0.491492 -0.374202 +v -1.160576 -0.780918 0.855161 +v -1.172298 -0.780965 -0.855226 +v -1.088829 0.486141 0.218688 +v -1.101077 0.485915 0.428143 +v -1.120441 0.069062 0.828196 +v -1.133600 0.071309 -0.828204 +v -1.126161 0.488315 -0.595265 +v -1.103050 -0.738073 0.023826 +v -1.118108 -0.770635 0.428092 +v -1.171406 -0.807124 -0.827768 +v -1.120312 -0.764927 -0.374159 +v -1.106137 -0.749230 0.218610 +v -1.139100 -0.792687 0.652517 +v -1.142087 -0.787442 -0.595288 +v -1.107325 -0.745003 -0.168796 +v -1.140568 0.485560 -0.710378 +v -1.153227 0.399858 -0.850849 +v -1.140670 0.396708 0.850809 +v -1.136934 0.480296 0.768769 +v -1.142547 -0.452015 -0.831256 +v -1.129788 -0.452004 0.831223 +v -1.086943 0.485822 -0.071659 +v -1.131380 -0.035146 -0.823674 +v -1.086254 0.485187 0.119928 +v -1.119689 -0.243363 0.822309 +v -1.132792 -0.243363 -0.822315 +v -1.118182 -0.036642 0.823672 +v -1.095741 0.490611 -0.269462 +v -1.148392 -0.668930 0.846583 +v -1.160531 -0.668964 -0.846642 +v -1.093741 0.486611 0.321337 +v -1.110820 0.484053 0.538744 +v -1.124975 0.176602 0.834652 +v -1.138016 0.179395 -0.834671 +v -1.113766 0.490622 -0.482983 +v -1.103554 -0.741656 0.119872 +v -1.127527 -0.781955 0.538724 +v -1.155928 -0.797764 -0.710430 +v -1.112698 -0.754052 -0.269398 +v -1.110968 -0.759369 0.321262 +v -1.152624 -0.802526 0.768809 +v -1.130148 -0.776342 -0.482972 +v -1.104135 -0.739282 -0.071625 +v -1.148442 0.484458 -0.768797 +v -1.148656 0.344276 -0.846587 +v -1.135946 0.341113 0.846552 +v -1.129647 0.480822 0.710362 +v -1.146301 -0.505368 -0.834699 +v -1.133671 -0.505351 0.834658 +v -1.088309 0.487108 -0.119918 +v -1.131096 -0.087764 -0.822313 +v -1.085800 0.484820 0.071664 +v -1.121385 -0.294969 0.823667 +v -1.134427 -0.294971 -0.823679 +v -1.117906 -0.088816 0.822312 +v -1.099371 0.491260 -0.321306 +v -1.154263 -0.724642 0.850851 +v -1.166201 -0.724682 -0.850913 +v -1.090985 0.486492 0.269490 +v -1.105654 0.485100 0.483006 +v -1.122425 0.122605 0.831222 +v -1.135535 0.125153 -0.831235 +v -1.119697 0.489600 -0.538728 +v -1.103074 -0.739293 0.071628 +v -1.122538 -0.776338 0.482970 +v -1.163481 -0.802569 -0.768860 +v -1.116224 -0.759350 -0.321250 +v -1.108266 -0.754075 0.269410 +v -1.145634 -0.797728 0.710389 +v -1.135865 -0.781968 -0.538734 +v -1.105463 -0.741637 -0.119867 +v -1.133129 0.486911 -0.652509 +v -1.158282 0.455714 -0.855154 +v -1.145898 0.452647 0.855110 +v -1.144670 0.480391 0.827656 +v -1.139310 -0.399208 -0.828218 +v -1.126440 -0.399200 0.828192 +v -1.086111 0.484759 -0.023836 +v -1.132214 0.017875 -0.825658 +v -1.087258 0.485665 0.168874 +v -1.118554 -0.191947 0.821618 +v -1.131702 -0.191846 -0.821621 +v -1.119027 0.015981 0.825654 +v -1.092694 0.489623 -0.218665 +v -1.142990 -0.613804 0.842416 +v -1.155310 -0.613833 -0.842470 +v -1.097105 0.486427 0.374233 +v -1.116559 0.482887 0.595271 +v -1.128085 0.231035 0.838403 +v -1.141036 0.234015 -0.838427 +v -1.108391 0.491274 -0.428115 +v -1.104570 -0.745026 0.168804 +v -1.133056 -0.787420 0.595268 +v -1.148785 -0.792717 -0.652547 +v -1.109734 -0.749205 -0.218599 +v -1.114249 -0.764939 0.374168 +v -1.160037 -0.807076 0.827708 +v -1.124957 -0.770631 -0.428087 +v -1.103332 -0.738070 -0.023824 +v -1.146968 0.473604 0.849309 +v -1.159221 0.476731 -0.849353 +v -1.091387 0.489038 -0.193644 +v -1.131362 -0.165966 -0.821534 +v -1.085893 0.484610 0.000001 +v -1.124970 -0.372985 0.826855 +v -1.137890 -0.372990 -0.826877 +v -1.118198 -0.166271 0.821532 +v -1.105917 0.491440 -0.401035 +v -1.162078 -0.801621 0.849363 +v -1.173656 -0.801669 -0.849427 +v -1.087971 0.485911 0.193664 +v -1.099015 0.486211 0.401065 +v -1.119663 0.042464 0.826859 +v -1.132838 0.044540 -0.826865 +v -1.129584 0.487617 -0.623804 +v -1.103126 -0.737918 0.000001 +v -1.116106 -0.767780 0.401006 +v -1.122566 -0.767771 -0.400999 +v -1.140471 -0.586466 0.840391 +v -1.152875 -0.586492 -0.840441 +v -1.119635 0.482305 0.623805 +v -1.129847 0.258408 0.840374 +v -1.142746 0.261459 -0.840401 +v -1.105284 -0.747036 0.193589 +v -1.136015 -0.790081 0.623810 +v -1.145378 -0.790106 -0.623835 +v -1.108461 -0.747011 -0.193579 +v -1.144453 0.484965 -0.739524 +v -1.150880 0.372032 -0.848710 +v -1.138244 0.368866 0.848672 +v -1.133232 0.480495 0.739501 +v -1.144360 -0.478621 -0.832932 +v -1.131663 -0.478607 0.832895 +v -1.087559 0.486457 -0.095717 +v -1.131169 -0.061505 -0.822912 +v -1.085960 0.484984 0.095725 +v -1.120467 -0.269135 0.822907 +v -1.133542 -0.269136 -0.822916 +v -1.117973 -0.062784 0.822911 +v -1.097482 0.490983 -0.295252 +v -1.151271 -0.696713 0.848709 +v -1.163311 -0.696751 -0.848769 +v -1.092288 0.486586 0.295281 +v -1.108164 0.484599 0.510771 +v -1.123630 0.149548 0.832892 +v -1.136708 0.152225 -0.832908 +v -1.116664 0.490151 -0.510751 +v -1.103248 -0.740339 0.095679 +v -1.124964 -0.779162 0.510743 +v -1.159655 -0.800197 -0.739581 +v -1.114391 -0.756656 -0.295191 +v -1.109545 -0.756677 0.295203 +v -1.149074 -0.800158 0.739535 +v -1.132942 -0.779171 -0.510749 +v -1.104733 -0.740323 -0.095674 +v -1.152530 0.484066 -0.798190 +v -1.146557 0.316592 -0.844489 +v -1.133780 0.313450 0.844457 +v -1.126183 0.481249 0.681360 +v -1.148369 -0.532260 -0.836546 +v -1.135809 -0.532241 0.836502 +v -1.089196 0.487765 -0.144289 +v -1.131093 -0.113926 -0.821881 +v -1.085775 0.484701 0.047714 +v -1.122441 -0.320881 0.824584 +v -1.135447 -0.320884 -0.824599 +v -1.117910 -0.114739 0.821880 +v -1.101407 0.491432 -0.347624 +v -1.157366 -0.752711 0.853004 +v -1.169198 -0.752755 -0.853067 +v -1.089833 0.486339 0.243961 +v -1.103291 0.485542 0.455460 +v -1.121362 0.095776 0.829654 +v -1.134499 0.098180 -0.829664 +v -1.122864 0.488982 -0.566903 +v -1.103032 -0.738534 0.047689 +v -1.120252 -0.773492 0.455416 +v -1.167399 -0.804877 -0.798258 +v -1.118198 -0.762114 -0.347574 +v -1.107130 -0.751584 0.243881 +v -1.142308 -0.795237 0.681380 +v -1.138915 -0.784727 -0.566918 +v -1.106327 -0.743204 -0.144232 +v -1.136792 0.486217 -0.681371 +v -1.155695 0.427753 -0.853000 +v -1.143222 0.424635 0.852957 +v -1.140749 0.480252 0.798156 +v -1.140863 -0.425547 -0.829681 +v -1.128047 -0.425537 0.829652 +v -1.086461 0.485210 -0.047710 +v -1.131728 -0.008686 -0.824592 +v -1.086686 0.485418 0.144303 +v -1.119051 -0.217639 0.821878 +v -1.132179 -0.217634 -0.821883 +v -1.118533 -0.010387 0.824589 +v -1.094145 0.490153 -0.243935 +v -1.145631 -0.641293 0.844483 +v -1.157862 -0.641324 -0.844539 +v -1.095346 0.486559 0.347655 +v -1.113620 0.483476 0.566914 +v -1.126460 0.203765 0.836493 +v -1.139459 0.206660 -0.836514 +v -1.111008 0.490999 -0.455434 +v -1.103994 -0.743225 0.144239 +v -1.130225 -0.784710 0.566903 +v -1.152303 -0.795270 -0.681415 +v -1.111146 -0.751560 -0.243869 +v -1.112536 -0.762130 0.347584 +v -1.156280 -0.804832 0.798202 +v -1.127485 -0.773492 -0.455415 +v -1.103668 -0.738527 -0.047687 +v -1.156713 0.483817 -0.827696 +v -1.122844 0.481751 0.652505 +v -1.090221 0.488413 -0.168858 +v -1.085806 0.484632 0.023838 +v -1.103589 0.491492 -0.374202 +v -1.088829 0.486141 0.218688 +v -1.101077 0.485915 0.428143 +v -1.126161 0.488315 -0.595265 +v -1.140568 0.485560 -0.710378 +v -1.136934 0.480296 0.768769 +v -1.086943 0.485822 -0.071659 +v -1.086254 0.485187 0.119928 +v -1.095741 0.490611 -0.269462 +v -1.093741 0.486611 0.321337 +v -1.110820 0.484053 0.538744 +v -1.113766 0.490622 -0.482983 +v -1.148442 0.484458 -0.768797 +v -1.129647 0.480822 0.710362 +v -1.088309 0.487108 -0.119918 +v -1.085800 0.484820 0.071664 +v -1.099371 0.491260 -0.321306 +v -1.090985 0.486492 0.269490 +v -1.105654 0.485100 0.483006 +v -1.119697 0.489600 -0.538728 +v -1.133129 0.486911 -0.652509 +v -1.158282 0.455714 -0.855154 +v -1.145898 0.452647 0.855110 +v -1.144670 0.480391 0.827656 +v -1.086111 0.484759 -0.023836 +v -1.087258 0.485665 0.168874 +v -1.092694 0.489623 -0.218665 +v -1.097105 0.486427 0.374233 +v -1.116559 0.482887 0.595271 +v -1.108391 0.491274 -0.428115 +v -1.146968 0.473604 0.849309 +v -1.159221 0.476731 -0.849353 +v -1.091387 0.489038 -0.193644 +v -1.085893 0.484610 0.000001 +v -1.105917 0.491440 -0.401035 +v -1.087971 0.485911 0.193664 +v -1.099015 0.486211 0.401065 +v -1.129584 0.487617 -0.623804 +v -1.119635 0.482305 0.623805 +v -1.144453 0.484965 -0.739524 +v -1.133232 0.480495 0.739501 +v -1.087559 0.486457 -0.095717 +v -1.085960 0.484984 0.095725 +v -1.097482 0.490983 -0.295252 +v -1.092288 0.486586 0.295281 +v -1.108164 0.484599 0.510771 +v -1.116664 0.490151 -0.510751 +v -1.152530 0.484066 -0.798190 +v -1.126183 0.481249 0.681360 +v -1.089196 0.487765 -0.144289 +v -1.085775 0.484701 0.047714 +v -1.101407 0.491432 -0.347624 +v -1.089833 0.486339 0.243961 +v -1.103291 0.485542 0.455460 +v -1.122864 0.488982 -0.566903 +v -1.136792 0.486217 -0.681371 +v -1.140749 0.480252 0.798156 +v -1.086461 0.485210 -0.047710 +v -1.086686 0.485418 0.144303 +v -1.094145 0.490153 -0.243935 +v -1.095346 0.486559 0.347655 +v -1.113620 0.483476 0.566914 +v -1.111008 0.490999 -0.455434 +vt 0.000000 0.000000 +vt 0.857292 0.208642 +vt 0.841642 0.208754 +vt 0.841751 0.187883 +vt 0.857401 0.187770 +vt 0.841868 0.166999 +vt 0.857517 0.166885 +vt 0.873177 0.166767 +vt 0.873061 0.187653 +vt 0.872952 0.208527 +vt 0.982879 0.207598 +vt 0.967144 0.207744 +vt 0.967241 0.186858 +vt 0.982973 0.186710 +vt 0.967346 0.165965 +vt 0.983074 0.165815 +vt 0.998811 0.165660 +vt 0.998713 0.186557 +vt 0.998623 0.207447 +vt 0.607774 0.376152 +vt 0.592309 0.376180 +vt 0.592338 0.355451 +vt 0.607806 0.355422 +vt 0.592371 0.334710 +vt 0.607843 0.334679 +vt 0.623321 0.334644 +vt 0.623282 0.355389 +vt 0.623247 0.376121 +vt 0.608742 0.042344 +vt 0.593186 0.042365 +vt 0.593269 0.021317 +vt 0.608834 0.021300 +vt 0.593356 0.000245 +vt 0.608930 0.000232 +vt 0.624506 0.000214 +vt 0.624401 0.021278 +vt 0.624301 0.042319 +vt 0.608141 0.209878 +vt 0.592642 0.209912 +vt 0.592699 0.189046 +vt 0.608204 0.189013 +vt 0.592759 0.168159 +vt 0.608270 0.168126 +vt 0.623786 0.168088 +vt 0.623714 0.188974 +vt 0.623646 0.209839 +vt 0.732402 0.209413 +vt 0.716838 0.209489 +vt 0.716933 0.188624 +vt 0.732500 0.188548 +vt 0.717034 0.167742 +vt 0.732604 0.167666 +vt 0.748183 0.167585 +vt 0.748076 0.188467 +vt 0.747975 0.209333 +vt 0.982388 0.374488 +vt 0.966629 0.374592 +vt 0.966667 0.353755 +vt 0.982424 0.353644 +vt 0.966713 0.332914 +vt 0.982467 0.332796 +vt 0.998233 0.332674 +vt 0.998193 0.353529 +vt 0.998160 0.374381 +vt 0.484195 0.376242 +vt 0.468758 0.376236 +vt 0.468761 0.355510 +vt 0.484201 0.355517 +vt 0.468764 0.334771 +vt 0.484208 0.334777 +vt 0.499653 0.334784 +vt 0.499642 0.355523 +vt 0.499632 0.376248 +vt 0.607674 0.541687 +vt 0.592215 0.541695 +vt 0.592212 0.521020 +vt 0.607670 0.521009 +vt 0.592213 0.500345 +vt 0.607671 0.500331 +vt 0.623138 0.500316 +vt 0.623137 0.520997 +vt 0.623142 0.541678 +vt 0.484344 0.042363 +vt 0.468796 0.042355 +vt 0.468797 0.021289 +vt 0.484356 0.021299 +vt 0.468797 0.000197 +vt 0.484369 0.000204 +vt 0.499940 0.000222 +vt 0.499914 0.021313 +vt 0.499891 0.042377 +vt 0.235261 0.020735 +vt 0.235383 0.041752 +vt 0.219787 0.041665 +vt 0.219660 0.020652 +vt 0.219527 -0.000380 +vt 0.235132 -0.000302 +vt 0.250732 -0.000230 +vt 0.250855 0.020811 +vt 0.250973 0.041833 +vt 0.731714 0.541576 +vt 0.716168 0.541594 +vt 0.716159 0.520888 +vt 0.731704 0.520865 +vt 0.716157 0.500182 +vt 0.731702 0.500153 +vt 0.747260 0.500123 +vt 0.747262 0.520840 +vt 0.747273 0.541557 +vt 0.484153 0.707208 +vt 0.468703 0.707205 +vt 0.468707 0.686486 +vt 0.484152 0.686488 +vt 0.468711 0.665778 +vt 0.484152 0.665781 +vt 0.499592 0.665782 +vt 0.499596 0.686488 +vt 0.499602 0.707207 +vt 0.236387 0.707314 +vt 0.220823 0.707332 +vt 0.220883 0.686575 +vt 0.236445 0.686561 +vt 0.220936 0.665826 +vt 0.236496 0.665817 +vt 0.252043 0.665809 +vt 0.251994 0.686548 +vt 0.251938 0.707296 +vt 0.236575 0.354889 +vt 0.236610 0.375648 +vt 0.221055 0.375576 +vt 0.221019 0.354813 +vt 0.220977 0.334039 +vt 0.236534 0.334120 +vt 0.252078 0.334196 +vt 0.252118 0.354962 +vt 0.252152 0.375716 +vt 0.982575 0.687009 +vt 0.982636 0.707847 +vt 0.966873 0.707804 +vt 0.966811 0.686973 +vt 0.966756 0.666145 +vt 0.982523 0.666173 +vt 0.998303 0.666204 +vt 0.998353 0.687048 +vt 0.998410 0.707893 +vt 0.731923 0.686630 +vt 0.731982 0.707378 +vt 0.716425 0.707359 +vt 0.716368 0.686615 +vt 0.716318 0.665880 +vt 0.731871 0.665891 +vt 0.747436 0.665903 +vt 0.747490 0.686646 +vt 0.747551 0.707398 +vt 0.731840 0.375795 +vt 0.716293 0.375852 +vt 0.716339 0.355103 +vt 0.731887 0.355042 +vt 0.716392 0.334342 +vt 0.731941 0.334278 +vt 0.747503 0.334210 +vt 0.747448 0.354978 +vt 0.747399 0.375735 +vt 0.983831 0.040285 +vt 0.968124 0.040429 +vt 0.968279 0.019476 +vt 0.983982 0.019335 +vt 0.968440 -0.001485 +vt 0.984140 -0.001622 +vt 0.995879 0.003512 +vt 0.999691 0.019190 +vt 0.999544 0.040136 +vt 0.733350 0.041988 +vt 0.717755 0.042051 +vt 0.717895 0.021034 +vt 0.733495 0.020975 +vt 0.718040 -0.000002 +vt 0.733646 -0.000057 +vt 0.749257 -0.000116 +vt 0.749102 0.020911 +vt 0.748952 0.041919 +vt 0.858363 0.041297 +vt 0.842711 0.041401 +vt 0.842875 0.020418 +vt 0.858528 0.020318 +vt 0.843047 -0.000580 +vt 0.858700 -0.000675 +vt 0.874359 -0.000776 +vt 0.874187 0.020213 +vt 0.874022 0.041188 +vt 0.732605 0.852970 +vt 0.732723 0.873833 +vt 0.717139 0.873800 +vt 0.717025 0.852938 +vt 0.716918 0.832094 +vt 0.732494 0.832126 +vt 0.748080 0.832160 +vt 0.748195 0.853005 +vt 0.748317 0.873867 +vt 0.608205 0.852772 +vt 0.608277 0.873638 +vt 0.592752 0.873625 +vt 0.592688 0.852757 +vt 0.592628 0.831912 +vt 0.608138 0.831927 +vt 0.623654 0.831944 +vt 0.623728 0.852788 +vt 0.623807 0.873654 +vt 0.607793 0.686528 +vt 0.607829 0.707252 +vt 0.592352 0.707241 +vt 0.592320 0.686518 +vt 0.592292 0.665807 +vt 0.607762 0.665814 +vt 0.623241 0.665822 +vt 0.623275 0.686538 +vt 0.623314 0.707264 +vt 0.983287 0.853826 +vt 0.983414 0.874702 +vt 0.967673 0.874625 +vt 0.967543 0.853750 +vt 0.967422 0.832883 +vt 0.983168 0.832956 +vt 0.998925 0.833034 +vt 0.999040 0.853906 +vt 0.999163 0.874784 +vt 0.857613 0.853313 +vt 0.857750 0.874178 +vt 0.842087 0.874126 +vt 0.841950 0.853262 +vt 0.841822 0.832411 +vt 0.857484 0.832461 +vt 0.873157 0.832512 +vt 0.873286 0.853367 +vt 0.873424 0.874233 +vt 0.856823 0.686780 +vt 0.856892 0.707566 +vt 0.841233 0.707538 +vt 0.841164 0.686758 +vt 0.841105 0.665984 +vt 0.856763 0.666000 +vt 0.872436 0.666016 +vt 0.872496 0.686802 +vt 0.872564 0.707594 +vt 0.236683 0.520756 +vt 0.236668 0.541472 +vt 0.221114 0.541446 +vt 0.221130 0.520724 +vt 0.221139 0.500001 +vt 0.236692 0.500039 +vt 0.252232 0.500075 +vt 0.252223 0.520786 +vt 0.252209 0.541497 +vt 0.111850 0.520466 +vt 0.111830 0.541242 +vt 0.096157 0.541209 +vt 0.096178 0.520425 +vt 0.096191 0.499641 +vt 0.111863 0.499691 +vt 0.127519 0.499740 +vt 0.127507 0.520507 +vt 0.127487 0.541273 +vt 0.111756 0.354175 +vt 0.111793 0.374979 +vt 0.096126 0.374880 +vt 0.096091 0.354069 +vt 0.096049 0.333252 +vt 0.111714 0.333364 +vt 0.127364 0.333472 +vt 0.127407 0.354277 +vt 0.127444 0.375074 +vt 0.235683 0.873805 +vt 0.220096 0.873841 +vt 0.220211 0.852975 +vt 0.235795 0.852938 +vt 0.220319 0.832125 +vt 0.235899 0.832089 +vt 0.251469 0.832056 +vt 0.251368 0.852905 +vt 0.251262 0.873771 +vt 0.110703 0.874188 +vt 0.095033 0.874252 +vt 0.095162 0.853378 +vt 0.110831 0.853316 +vt 0.095282 0.832515 +vt 0.110952 0.832455 +vt 0.126610 0.832399 +vt 0.126490 0.853257 +vt 0.126361 0.874128 +vt 0.111509 0.707505 +vt 0.095837 0.707537 +vt 0.095902 0.686734 +vt 0.111574 0.686709 +vt 0.095960 0.665936 +vt 0.111632 0.665918 +vt 0.127290 0.665901 +vt 0.127232 0.686685 +vt 0.127166 0.707475 +vt 0.484174 0.873603 +vt 0.468667 0.873601 +vt 0.468672 0.852729 +vt 0.484170 0.852729 +vt 0.468677 0.831878 +vt 0.484166 0.831880 +vt 0.499655 0.831876 +vt 0.499667 0.852725 +vt 0.499680 0.873598 +vt 0.360085 0.873617 +vt 0.344559 0.873631 +vt 0.344631 0.852762 +vt 0.360150 0.852748 +vt 0.344698 0.831915 +vt 0.360210 0.831901 +vt 0.375716 0.831889 +vt 0.375663 0.852737 +vt 0.375606 0.873607 +vt 0.360495 0.707214 +vt 0.345015 0.707221 +vt 0.345053 0.686492 +vt 0.360529 0.686487 +vt 0.345087 0.665775 +vt 0.360560 0.665772 +vt 0.376025 0.665770 +vt 0.375998 0.686483 +vt 0.375967 0.707207 +vt 0.236090 0.188350 +vt 0.236169 0.209221 +vt 0.220601 0.209124 +vt 0.220518 0.188253 +vt 0.220430 0.167364 +vt 0.236005 0.167462 +vt 0.251569 0.167554 +vt 0.251651 0.188442 +vt 0.251727 0.209312 +vt 0.111226 0.187420 +vt 0.111315 0.208301 +vt 0.095657 0.208163 +vt 0.095568 0.187279 +vt 0.095473 0.166383 +vt 0.111130 0.166526 +vt 0.126776 0.166662 +vt 0.126872 0.187555 +vt 0.126962 0.208435 +vt 0.110276 0.019904 +vt 0.110417 0.040890 +vt 0.094764 0.040755 +vt 0.094622 0.019773 +vt 0.094474 -0.001221 +vt 0.110128 -0.001095 +vt 0.125774 -0.000974 +vt 0.125922 0.020030 +vt 0.126064 0.041019 +vt 0.484258 0.209977 +vt 0.468781 0.209970 +vt 0.468783 0.189100 +vt 0.484268 0.189108 +vt 0.468785 0.168208 +vt 0.484278 0.168216 +vt 0.499770 0.168226 +vt 0.499752 0.189118 +vt 0.499736 0.209987 +vt 0.360346 0.188921 +vt 0.360390 0.209790 +vt 0.344889 0.209739 +vt 0.344839 0.188871 +vt 0.344787 0.167982 +vt 0.360299 0.168032 +vt 0.375807 0.168076 +vt 0.375847 0.188966 +vt 0.375885 0.209834 +vt 0.359886 0.021184 +vt 0.359955 0.042231 +vt 0.344399 0.042192 +vt 0.344321 0.021148 +vt 0.344240 0.000080 +vt 0.359813 0.000112 +vt 0.375384 0.000139 +vt 0.375448 0.021214 +vt 0.375508 0.042265 +vt 0.484159 0.541709 +vt 0.468732 0.541705 +vt 0.468735 0.521037 +vt 0.484162 0.521042 +vt 0.468739 0.500369 +vt 0.484165 0.500374 +vt 0.499592 0.500377 +vt 0.499589 0.521044 +vt 0.499587 0.541711 +vt 0.360674 0.520956 +vt 0.360664 0.541635 +vt 0.345202 0.541619 +vt 0.345212 0.520936 +vt 0.345217 0.500253 +vt 0.360679 0.500276 +vt 0.376132 0.500296 +vt 0.376127 0.520973 +vt 0.376119 0.541649 +vt 0.360614 0.355353 +vt 0.360633 0.376085 +vt 0.345165 0.376045 +vt 0.345142 0.355310 +vt 0.345116 0.334563 +vt 0.360591 0.334607 +vt 0.376058 0.334647 +vt 0.376077 0.355391 +vt 0.376094 0.376121 +vt 0.982353 0.541171 +vt 0.966579 0.541201 +vt 0.966561 0.520378 +vt 0.982334 0.520338 +vt 0.966549 0.499556 +vt 0.982321 0.499505 +vt 0.998107 0.499452 +vt 0.998121 0.520296 +vt 0.998141 0.541141 +vt 0.856574 0.541396 +vt 0.840917 0.541422 +vt 0.840903 0.520666 +vt 0.856559 0.520634 +vt 0.840896 0.499911 +vt 0.856552 0.499871 +vt 0.872223 0.499830 +vt 0.872230 0.520600 +vt 0.872245 0.541370 +vt 0.856683 0.375233 +vt 0.841030 0.375313 +vt 0.841080 0.354527 +vt 0.856732 0.354441 +vt 0.841138 0.333733 +vt 0.856789 0.333642 +vt 0.872454 0.333547 +vt 0.872398 0.354352 +vt 0.872349 0.375150 +vt 0.856564 0.458340 +vt 0.840909 0.458395 +vt 0.840927 0.437632 +vt 0.856581 0.437571 +vt 0.840954 0.416865 +vt 0.856607 0.416797 +vt 0.872275 0.416727 +vt 0.872250 0.437507 +vt 0.872233 0.458284 +vt 0.794030 0.458547 +vt 0.778432 0.458594 +vt 0.778452 0.437856 +vt 0.794050 0.437803 +vt 0.778479 0.417113 +vt 0.794077 0.417054 +vt 0.809689 0.416993 +vt 0.809661 0.437748 +vt 0.809642 0.458498 +vt 0.794155 0.375537 +vt 0.778556 0.375606 +vt 0.778606 0.354840 +vt 0.794205 0.354766 +vt 0.778663 0.334064 +vt 0.794263 0.333986 +vt 0.809875 0.333905 +vt 0.809817 0.354690 +vt 0.809766 0.375465 +vt 0.856634 0.603687 +vt 0.856669 0.624454 +vt 0.841011 0.624451 +vt 0.840976 0.603691 +vt 0.840950 0.582933 +vt 0.856608 0.582922 +vt 0.872280 0.582911 +vt 0.872307 0.603683 +vt 0.872341 0.624458 +vt 0.794087 0.603703 +vt 0.794120 0.624444 +vt 0.778517 0.624442 +vt 0.778485 0.603707 +vt 0.778461 0.582975 +vt 0.794063 0.582965 +vt 0.809678 0.582955 +vt 0.809703 0.603699 +vt 0.809736 0.624447 +vt 0.794032 0.541493 +vt 0.778432 0.541515 +vt 0.778420 0.520787 +vt 0.794019 0.520758 +vt 0.778416 0.500058 +vt 0.794015 0.500023 +vt 0.809628 0.499987 +vt 0.809633 0.520729 +vt 0.809646 0.541470 +vt 0.982411 0.603672 +vt 0.982441 0.624505 +vt 0.966671 0.624494 +vt 0.966639 0.603671 +vt 0.966615 0.582848 +vt 0.982388 0.582839 +vt 0.998175 0.582832 +vt 0.998197 0.603676 +vt 0.998225 0.624518 +vt 0.919409 0.603674 +vt 0.919443 0.624471 +vt 0.903728 0.624466 +vt 0.903694 0.603677 +vt 0.903668 0.582889 +vt 0.919383 0.582878 +vt 0.935112 0.582867 +vt 0.935138 0.603672 +vt 0.935172 0.624478 +vt 0.919347 0.541288 +vt 0.903632 0.541316 +vt 0.903615 0.520530 +vt 0.919330 0.520493 +vt 0.903607 0.499743 +vt 0.919321 0.499698 +vt 0.935049 0.499652 +vt 0.935059 0.520456 +vt 0.935076 0.541259 +vt 0.360672 0.438215 +vt 0.360678 0.458907 +vt 0.345216 0.458878 +vt 0.345209 0.438182 +vt 0.345198 0.417479 +vt 0.360663 0.417514 +vt 0.376119 0.417546 +vt 0.376127 0.438244 +vt 0.376132 0.458933 +vt 0.298763 0.438066 +vt 0.298773 0.458773 +vt 0.283270 0.458733 +vt 0.283260 0.438022 +vt 0.283245 0.417303 +vt 0.298749 0.417353 +vt 0.314242 0.417398 +vt 0.314256 0.438108 +vt 0.314264 0.458811 +vt 0.298676 0.355155 +vt 0.298706 0.375898 +vt 0.283199 0.375841 +vt 0.283168 0.355095 +vt 0.283132 0.334336 +vt 0.298643 0.334400 +vt 0.314143 0.334459 +vt 0.314175 0.355211 +vt 0.314202 0.375951 +vt 0.360609 0.624371 +vt 0.345141 0.624369 +vt 0.345162 0.603676 +vt 0.360628 0.603682 +vt 0.345179 0.582988 +vt 0.360643 0.582997 +vt 0.376100 0.583006 +vt 0.376086 0.603687 +vt 0.376069 0.624374 +vt 0.298682 0.624361 +vt 0.283174 0.624359 +vt 0.283201 0.603650 +vt 0.298707 0.603657 +vt 0.283222 0.582945 +vt 0.298728 0.582957 +vt 0.314222 0.582968 +vt 0.314203 0.603663 +vt 0.314178 0.624363 +vt 0.298768 0.520868 +vt 0.298756 0.541564 +vt 0.283252 0.541542 +vt 0.283265 0.520842 +vt 0.283273 0.500142 +vt 0.298775 0.500173 +vt 0.314266 0.500202 +vt 0.314260 0.520893 +vt 0.314248 0.541583 +vt 0.484153 0.603720 +vt 0.484152 0.624399 +vt 0.468718 0.624396 +vt 0.468722 0.603717 +vt 0.468725 0.583043 +vt 0.484155 0.583047 +vt 0.499584 0.583049 +vt 0.499585 0.603722 +vt 0.499586 0.624400 +vt 0.422411 0.624384 +vt 0.406969 0.624380 +vt 0.406982 0.603698 +vt 0.422421 0.603703 +vt 0.406992 0.583021 +vt 0.422430 0.583027 +vt 0.437864 0.583033 +vt 0.437857 0.603708 +vt 0.437849 0.624388 +vt 0.422449 0.521014 +vt 0.422443 0.541684 +vt 0.407007 0.541674 +vt 0.407014 0.521002 +vt 0.407018 0.500330 +vt 0.422453 0.500344 +vt 0.437884 0.500355 +vt 0.437880 0.521024 +vt 0.437875 0.541692 +vt 0.360141 0.105234 +vt 0.360197 0.126189 +vt 0.344671 0.126141 +vt 0.344608 0.105187 +vt 0.344542 0.084212 +vt 0.360083 0.084256 +vt 0.375619 0.084295 +vt 0.375670 0.105274 +vt 0.375718 0.126231 +vt 0.297979 0.105011 +vt 0.298061 0.125959 +vt 0.282512 0.125887 +vt 0.282425 0.104940 +vt 0.282333 0.083973 +vt 0.297893 0.084041 +vt 0.313448 0.084104 +vt 0.313528 0.105076 +vt 0.313604 0.126026 +vt 0.297608 0.021006 +vt 0.297708 0.042039 +vt 0.282135 0.041976 +vt 0.282029 0.020947 +vt 0.281918 -0.000104 +vt 0.297504 -0.000049 +vt 0.313086 -0.000000 +vt 0.313183 0.021059 +vt 0.313276 0.042096 +vt 0.360504 0.272278 +vt 0.360536 0.293071 +vt 0.345054 0.293023 +vt 0.345018 0.272229 +vt 0.344978 0.251418 +vt 0.360469 0.251467 +vt 0.375953 0.251511 +vt 0.375983 0.272321 +vt 0.376011 0.293113 +vt 0.298514 0.272049 +vt 0.298561 0.292848 +vt 0.283045 0.292779 +vt 0.282995 0.271978 +vt 0.282939 0.251162 +vt 0.298462 0.251234 +vt 0.313975 0.251301 +vt 0.314023 0.272115 +vt 0.314067 0.292911 +vt 0.298281 0.188683 +vt 0.298345 0.209551 +vt 0.282815 0.209477 +vt 0.282746 0.188608 +vt 0.282672 0.167720 +vt 0.298212 0.167795 +vt 0.313744 0.167863 +vt 0.313807 0.188751 +vt 0.313867 0.209620 +vt 0.484223 0.293251 +vt 0.468770 0.293244 +vt 0.468772 0.272454 +vt 0.484232 0.272462 +vt 0.468775 0.251647 +vt 0.484240 0.251654 +vt 0.499705 0.251662 +vt 0.499691 0.272470 +vt 0.499677 0.293259 +vt 0.422391 0.272415 +vt 0.422404 0.293205 +vt 0.406944 0.293180 +vt 0.406926 0.272390 +vt 0.406906 0.251581 +vt 0.422376 0.251607 +vt 0.437844 0.251626 +vt 0.437853 0.272434 +vt 0.437861 0.293224 +vt 0.422326 0.189061 +vt 0.422344 0.209931 +vt 0.406861 0.209905 +vt 0.406836 0.189036 +vt 0.406809 0.168145 +vt 0.422306 0.168170 +vt 0.437800 0.168189 +vt 0.437813 0.189080 +vt 0.437824 0.209950 +vt 0.110803 0.103767 +vt 0.110918 0.124699 +vt 0.095263 0.124557 +vt 0.095148 0.103625 +vt 0.095026 0.082681 +vt 0.110681 0.082821 +vt 0.126327 0.082956 +vt 0.126448 0.103903 +vt 0.126564 0.124836 +vt 0.048129 0.103164 +vt 0.048239 0.124094 +vt 0.032545 0.123927 +vt 0.032438 0.102998 +vt 0.032323 0.082059 +vt 0.048012 0.082224 +vt 0.063692 0.082382 +vt 0.063811 0.103323 +vt 0.063923 0.124254 +vt 0.047621 0.019341 +vt 0.047758 0.040312 +vt 0.032074 0.040152 +vt 0.031940 0.019185 +vt 0.031799 -0.001792 +vt 0.047477 -0.001640 +vt 0.063149 -0.001494 +vt 0.063295 0.019492 +vt 0.063434 0.040466 +vt 0.111544 0.270878 +vt 0.111607 0.291716 +vt 0.095945 0.291593 +vt 0.095883 0.270750 +vt 0.095815 0.249898 +vt 0.111474 0.250030 +vt 0.127122 0.250158 +vt 0.127192 0.271002 +vt 0.127256 0.291835 +vt 0.048823 0.270338 +vt 0.048880 0.291196 +vt 0.033165 0.291054 +vt 0.033111 0.270190 +vt 0.033050 0.249319 +vt 0.048760 0.249472 +vt 0.064457 0.249619 +vt 0.064523 0.270480 +vt 0.064582 0.291333 +vt 0.048529 0.186824 +vt 0.048613 0.207716 +vt 0.032908 0.207556 +vt 0.032827 0.186662 +vt 0.032740 0.165759 +vt 0.048439 0.165924 +vt 0.064128 0.166083 +vt 0.064220 0.186982 +vt 0.064306 0.207870 +vt 0.236376 0.271736 +vt 0.236434 0.292544 +vt 0.220875 0.292456 +vt 0.220815 0.271645 +vt 0.220749 0.250820 +vt 0.236313 0.250913 +vt 0.251865 0.251001 +vt 0.251926 0.271822 +vt 0.251982 0.292627 +vt 0.174059 0.271344 +vt 0.174123 0.292166 +vt 0.158514 0.292060 +vt 0.158450 0.271235 +vt 0.158379 0.250398 +vt 0.173990 0.250511 +vt 0.189588 0.250619 +vt 0.189657 0.271449 +vt 0.189719 0.292267 +vt 0.173744 0.187928 +vt 0.173832 0.208803 +vt 0.158220 0.208685 +vt 0.158131 0.187809 +vt 0.158035 0.166918 +vt 0.173649 0.167038 +vt 0.189253 0.167153 +vt 0.189346 0.188042 +vt 0.189433 0.208915 +vt 0.360320 0.790267 +vt 0.344820 0.790281 +vt 0.344875 0.769492 +vt 0.360369 0.769479 +vt 0.344926 0.748719 +vt 0.360415 0.748708 +vt 0.375897 0.748699 +vt 0.375856 0.769469 +vt 0.375813 0.790256 +vt 0.298277 0.790335 +vt 0.282744 0.790358 +vt 0.282818 0.769563 +vt 0.298346 0.769542 +vt 0.282887 0.748784 +vt 0.298410 0.748765 +vt 0.313924 0.748748 +vt 0.313864 0.769523 +vt 0.313799 0.790315 +vt 0.298523 0.707253 +vt 0.283006 0.707266 +vt 0.283056 0.686525 +vt 0.298571 0.686515 +vt 0.283101 0.665795 +vt 0.298613 0.665789 +vt 0.314114 0.665783 +vt 0.314074 0.686507 +vt 0.314029 0.707241 +vt 0.359788 0.957328 +vt 0.344229 0.957333 +vt 0.344318 0.936372 +vt 0.359869 0.936363 +vt 0.344403 0.915435 +vt 0.359945 0.915424 +vt 0.375483 0.915416 +vt 0.375416 0.936358 +vt 0.375344 0.957325 +vt 0.297524 0.957368 +vt 0.281945 0.957386 +vt 0.282066 0.936435 +vt 0.297638 0.936415 +vt 0.282180 0.915506 +vt 0.297745 0.915484 +vt 0.313304 0.915465 +vt 0.313203 0.936398 +vt 0.313097 0.957354 +vt 0.297944 0.873688 +vt 0.282392 0.873712 +vt 0.282488 0.852846 +vt 0.298035 0.852821 +vt 0.282580 0.831999 +vt 0.298121 0.831974 +vt 0.313654 0.831951 +vt 0.313575 0.852798 +vt 0.313489 0.873666 +vt 0.484193 0.957353 +vt 0.468644 0.957351 +vt 0.468650 0.936374 +vt 0.484188 0.936374 +vt 0.468656 0.915423 +vt 0.484183 0.915424 +vt 0.499709 0.915418 +vt 0.499725 0.936368 +vt 0.499742 0.957345 +vt 0.421998 0.957330 +vt 0.406449 0.957326 +vt 0.406500 0.936354 +vt 0.422039 0.936356 +vt 0.406548 0.915409 +vt 0.422077 0.915409 +vt 0.437604 0.915412 +vt 0.437576 0.936360 +vt 0.437547 0.957336 +vt 0.422146 0.873592 +vt 0.406636 0.873595 +vt 0.406676 0.852723 +vt 0.422178 0.852720 +vt 0.406714 0.831875 +vt 0.422208 0.831872 +vt 0.437699 0.831871 +vt 0.437677 0.852720 +vt 0.437654 0.873593 +vt 0.111169 0.790768 +vt 0.095499 0.790821 +vt 0.095595 0.769988 +vt 0.111266 0.769939 +vt 0.095684 0.749164 +vt 0.111355 0.749120 +vt 0.127012 0.749078 +vt 0.126923 0.769893 +vt 0.126827 0.790717 +vt 0.048413 0.791002 +vt 0.032693 0.791070 +vt 0.032784 0.770217 +vt 0.048506 0.770154 +vt 0.032867 0.749370 +vt 0.048591 0.749314 +vt 0.064302 0.749261 +vt 0.064215 0.770096 +vt 0.064121 0.790938 +vt 0.048738 0.707649 +vt 0.033010 0.707692 +vt 0.033070 0.686859 +vt 0.048800 0.686823 +vt 0.033123 0.666028 +vt 0.048854 0.666002 +vt 0.064571 0.665978 +vt 0.064515 0.686791 +vt 0.064452 0.707609 +vt 0.110106 0.957806 +vt 0.094436 0.957868 +vt 0.094598 0.936945 +vt 0.110267 0.936882 +vt 0.094751 0.916035 +vt 0.110421 0.915971 +vt 0.126081 0.915910 +vt 0.125928 0.936823 +vt 0.125767 0.957749 +vt 0.047377 0.958080 +vt 0.031674 0.958160 +vt 0.031831 0.937244 +vt 0.047536 0.937162 +vt 0.031979 0.916336 +vt 0.047686 0.916254 +vt 0.063384 0.916176 +vt 0.063232 0.937085 +vt 0.063071 0.958004 +vt 0.047962 0.874468 +vt 0.032250 0.874549 +vt 0.032373 0.853667 +vt 0.048087 0.853589 +vt 0.032488 0.832794 +vt 0.048204 0.832718 +vt 0.063908 0.832647 +vt 0.063789 0.853514 +vt 0.063663 0.874391 +vt 0.235170 0.957458 +vt 0.219565 0.957489 +vt 0.219708 0.936549 +vt 0.235309 0.936516 +vt 0.219844 0.915628 +vt 0.235440 0.915593 +vt 0.251028 0.915561 +vt 0.250902 0.936486 +vt 0.250768 0.957431 +vt 0.172702 0.957602 +vt 0.157065 0.957647 +vt 0.157223 0.936717 +vt 0.172857 0.936669 +vt 0.157372 0.915802 +vt 0.173004 0.915753 +vt 0.188626 0.915708 +vt 0.188482 0.936626 +vt 0.188331 0.957561 +vt 0.173275 0.873970 +vt 0.157647 0.874019 +vt 0.157773 0.853150 +vt 0.173399 0.853102 +vt 0.157891 0.832296 +vt 0.173515 0.832249 +vt 0.189127 0.832205 +vt 0.189013 0.853057 +vt 0.188892 0.873924 +vt 0.111859 0.437353 +vt 0.111867 0.458135 +vt 0.096197 0.458068 +vt 0.096190 0.437277 +vt 0.096176 0.416483 +vt 0.111844 0.416567 +vt 0.127497 0.416648 +vt 0.127513 0.437426 +vt 0.127522 0.458200 +vt 0.049090 0.437034 +vt 0.049094 0.457852 +vt 0.033361 0.457775 +vt 0.033359 0.436947 +vt 0.033351 0.416117 +vt 0.049080 0.416213 +vt 0.064794 0.416306 +vt 0.064806 0.437118 +vt 0.064811 0.457926 +vt 0.049010 0.353729 +vt 0.049040 0.374561 +vt 0.033315 0.374448 +vt 0.033288 0.353607 +vt 0.033253 0.332762 +vt 0.048973 0.332891 +vt 0.064679 0.333015 +vt 0.064718 0.353846 +vt 0.064750 0.374671 +vt 0.111725 0.624349 +vt 0.096053 0.624352 +vt 0.096088 0.603564 +vt 0.111761 0.603570 +vt 0.096116 0.582779 +vt 0.111789 0.582793 +vt 0.127447 0.582808 +vt 0.127418 0.603577 +vt 0.127383 0.624348 +vt 0.048942 0.624367 +vt 0.033208 0.624375 +vt 0.033240 0.603550 +vt 0.048976 0.603551 +vt 0.033266 0.582725 +vt 0.049002 0.582737 +vt 0.064723 0.582751 +vt 0.064695 0.603555 +vt 0.064661 0.624360 +vt 0.049066 0.520296 +vt 0.049044 0.541109 +vt 0.033307 0.541075 +vt 0.033330 0.520250 +vt 0.033346 0.499426 +vt 0.049082 0.499482 +vt 0.064801 0.499536 +vt 0.064786 0.520340 +vt 0.064765 0.541143 +vt 0.236579 0.624352 +vt 0.221021 0.624351 +vt 0.221053 0.603621 +vt 0.236610 0.603628 +vt 0.221078 0.582894 +vt 0.236634 0.582908 +vt 0.252176 0.582921 +vt 0.252153 0.603636 +vt 0.252123 0.624354 +vt 0.174267 0.624347 +vt 0.158654 0.624347 +vt 0.158689 0.603591 +vt 0.174301 0.603598 +vt 0.158716 0.582837 +vt 0.174328 0.582852 +vt 0.189926 0.582866 +vt 0.189900 0.603606 +vt 0.189866 0.624348 +vt 0.174385 0.520620 +vt 0.174367 0.541364 +vt 0.158755 0.541334 +vt 0.158774 0.520584 +vt 0.158785 0.499833 +vt 0.174395 0.499877 +vt 0.189991 0.499920 +vt 0.189981 0.520656 +vt 0.189964 0.541392 +vt 0.857149 0.769970 +vt 0.857252 0.790790 +vt 0.841591 0.790745 +vt 0.841489 0.769929 +vt 0.841395 0.749123 +vt 0.857055 0.749160 +vt 0.872727 0.749199 +vt 0.872822 0.770013 +vt 0.872925 0.790836 +vt 0.794581 0.769817 +vt 0.794680 0.790623 +vt 0.779066 0.790587 +vt 0.778969 0.769782 +vt 0.778880 0.748991 +vt 0.794490 0.749022 +vt 0.810112 0.749054 +vt 0.810205 0.769853 +vt 0.810305 0.790662 +vt 0.794268 0.686698 +vt 0.794334 0.707464 +vt 0.778727 0.707441 +vt 0.778662 0.686680 +vt 0.778606 0.665928 +vt 0.794210 0.665941 +vt 0.809828 0.665954 +vt 0.809887 0.686717 +vt 0.809954 0.707487 +vt 0.858215 0.936853 +vt 0.858387 0.957772 +vt 0.842720 0.957724 +vt 0.842548 0.936803 +vt 0.842386 0.915896 +vt 0.858051 0.915948 +vt 0.873726 0.916002 +vt 0.873890 0.936906 +vt 0.874063 0.957823 +vt 0.795600 0.936670 +vt 0.795765 0.957598 +vt 0.780129 0.957562 +vt 0.779968 0.936631 +vt 0.779816 0.915718 +vt 0.795444 0.915759 +vt 0.811082 0.915802 +vt 0.811241 0.936711 +vt 0.811408 0.957637 +vt 0.795025 0.853124 +vt 0.795157 0.873986 +vt 0.779534 0.873944 +vt 0.779405 0.853082 +vt 0.779284 0.832236 +vt 0.794902 0.832276 +vt 0.810531 0.832319 +vt 0.810656 0.853168 +vt 0.810790 0.874030 +vt 0.983848 0.937373 +vt 0.984011 0.958279 +vt 0.968282 0.958202 +vt 0.968116 0.937295 +vt 0.967960 0.916397 +vt 0.983694 0.916476 +vt 0.999437 0.916559 +vt 0.999587 0.937456 +vt 0.999746 0.958360 +vt 0.920967 0.937084 +vt 0.921139 0.957996 +vt 0.905439 0.957935 +vt 0.905266 0.937021 +vt 0.905103 0.916120 +vt 0.920804 0.916184 +vt 0.936514 0.916251 +vt 0.936676 0.937151 +vt 0.936846 0.958061 +vt 0.920369 0.853544 +vt 0.920505 0.874414 +vt 0.904802 0.874351 +vt 0.904665 0.853482 +vt 0.904536 0.832624 +vt 0.920242 0.832684 +vt 0.935958 0.832747 +vt 0.936084 0.853610 +vt 0.936219 0.874481 +vt 0.607963 0.769512 +vt 0.608017 0.790298 +vt 0.592520 0.790283 +vt 0.592472 0.769497 +vt 0.592428 0.748729 +vt 0.607914 0.748743 +vt 0.623408 0.748758 +vt 0.623462 0.769528 +vt 0.623521 0.790315 +vt 0.546032 0.769467 +vt 0.546061 0.790252 +vt 0.530583 0.790247 +vt 0.530560 0.769462 +vt 0.530539 0.748695 +vt 0.546005 0.748701 +vt 0.561474 0.748708 +vt 0.561507 0.769475 +vt 0.561543 0.790260 +vt 0.545939 0.686497 +vt 0.545958 0.707217 +vt 0.530504 0.707212 +vt 0.530489 0.686493 +vt 0.530476 0.665786 +vt 0.545923 0.665790 +vt 0.561374 0.665795 +vt 0.561394 0.686503 +vt 0.561417 0.707224 +vt 0.608519 0.936376 +vt 0.608609 0.957337 +vt 0.593049 0.957332 +vt 0.592969 0.936368 +vt 0.592892 0.915430 +vt 0.608433 0.915440 +vt 0.623980 0.915452 +vt 0.624073 0.936387 +vt 0.624172 0.957345 +vt 0.546338 0.936359 +vt 0.546389 0.957330 +vt 0.530839 0.957334 +vt 0.530800 0.936360 +vt 0.530762 0.915413 +vt 0.546291 0.915414 +vt 0.561821 0.915417 +vt 0.561879 0.936360 +vt 0.561940 0.957329 +vt 0.546164 0.852730 +vt 0.546204 0.873600 +vt 0.530694 0.873597 +vt 0.530663 0.852726 +vt 0.530634 0.831878 +vt 0.546127 0.831882 +vt 0.561623 0.831890 +vt 0.561668 0.852737 +vt 0.561716 0.873606 +vt 0.733122 0.936531 +vt 0.733270 0.957470 +vt 0.717665 0.957444 +vt 0.717523 0.936503 +vt 0.717388 0.915582 +vt 0.732982 0.915612 +vt 0.748584 0.915645 +vt 0.748729 0.936562 +vt 0.748882 0.957498 +vt 0.670769 0.936433 +vt 0.670892 0.957383 +vt 0.655313 0.957368 +vt 0.655198 0.936415 +vt 0.655089 0.915485 +vt 0.670653 0.915506 +vt 0.686223 0.915528 +vt 0.686347 0.936454 +vt 0.686476 0.957401 +vt 0.670340 0.852853 +vt 0.670438 0.873716 +vt 0.654887 0.873693 +vt 0.654795 0.852829 +vt 0.654709 0.831985 +vt 0.670248 0.832009 +vt 0.685795 0.832035 +vt 0.685893 0.852879 +vt 0.685997 0.873742 +vt 0.857771 0.125076 +vt 0.842121 0.125189 +vt 0.842258 0.104264 +vt 0.857909 0.104152 +vt 0.842403 0.083324 +vt 0.858053 0.083214 +vt 0.873712 0.083099 +vt 0.873568 0.104035 +vt 0.873431 0.124959 +vt 0.795227 0.125501 +vt 0.779614 0.125595 +vt 0.779746 0.104663 +vt 0.795361 0.104571 +vt 0.779883 0.083715 +vt 0.795500 0.083625 +vt 0.811126 0.083529 +vt 0.810984 0.104473 +vt 0.810849 0.125402 +vt 0.795799 0.041683 +vt 0.780177 0.041767 +vt 0.780333 0.020767 +vt 0.795959 0.020687 +vt 0.780496 -0.000251 +vt 0.796124 -0.000325 +vt 0.811759 -0.000405 +vt 0.811591 0.020602 +vt 0.811429 0.041594 +vt 0.732830 0.125847 +vt 0.717252 0.125922 +vt 0.717369 0.104983 +vt 0.732951 0.104911 +vt 0.717492 0.084025 +vt 0.733078 0.083956 +vt 0.748672 0.083881 +vt 0.748541 0.104833 +vt 0.748416 0.125768 +vt 0.670565 0.126112 +vt 0.655018 0.126165 +vt 0.655115 0.105219 +vt 0.670668 0.105168 +vt 0.655216 0.084251 +vt 0.670775 0.084203 +vt 0.686341 0.084149 +vt 0.686228 0.105112 +vt 0.686120 0.126054 +vt 0.671005 0.042209 +vt 0.655432 0.042251 +vt 0.655547 0.021218 +vt 0.671127 0.021180 +vt 0.655667 0.000163 +vt 0.671254 0.000129 +vt 0.686845 0.000091 +vt 0.686711 0.021137 +vt 0.686582 0.042162 +vt 0.983298 0.124002 +vt 0.967577 0.124153 +vt 0.967703 0.103235 +vt 0.983420 0.103085 +vt 0.967836 0.082308 +vt 0.983550 0.082159 +vt 0.999271 0.082005 +vt 0.999145 0.102929 +vt 0.999026 0.123846 +vt 0.920464 0.124577 +vt 0.904777 0.124709 +vt 0.904912 0.103788 +vt 0.920598 0.103657 +vt 0.905055 0.082855 +vt 0.920739 0.082726 +vt 0.936430 0.082591 +vt 0.936291 0.103521 +vt 0.936159 0.124440 +vt 0.921042 0.040831 +vt 0.905361 0.040955 +vt 0.905525 0.019987 +vt 0.921204 0.019867 +vt 0.905696 -0.000992 +vt 0.921373 -0.001107 +vt 0.937057 -0.001228 +vt 0.936890 0.019742 +vt 0.936729 0.040702 +vt 0.731719 0.458723 +vt 0.716174 0.458761 +vt 0.716193 0.438045 +vt 0.731738 0.438001 +vt 0.716220 0.417322 +vt 0.731765 0.417273 +vt 0.747323 0.417222 +vt 0.747296 0.437955 +vt 0.747276 0.458682 +vt 0.669614 0.458864 +vt 0.654117 0.458893 +vt 0.654135 0.438194 +vt 0.669632 0.438160 +vt 0.654158 0.417487 +vt 0.669656 0.417450 +vt 0.685166 0.417410 +vt 0.685141 0.438124 +vt 0.685122 0.458832 +vt 0.669722 0.376003 +vt 0.654221 0.376046 +vt 0.654260 0.355309 +vt 0.669764 0.355263 +vt 0.654305 0.334560 +vt 0.669811 0.334512 +vt 0.685327 0.334459 +vt 0.685278 0.355214 +vt 0.685234 0.375956 +vt 0.732205 0.769690 +vt 0.732294 0.790486 +vt 0.716726 0.790456 +vt 0.716640 0.769662 +vt 0.716561 0.748881 +vt 0.732123 0.748906 +vt 0.747697 0.748933 +vt 0.747781 0.769719 +vt 0.747873 0.790518 +vt 0.670008 0.769587 +vt 0.670082 0.790377 +vt 0.654553 0.790354 +vt 0.654484 0.769566 +vt 0.654420 0.748793 +vt 0.669940 0.748813 +vt 0.685470 0.748834 +vt 0.685542 0.769610 +vt 0.685620 0.790402 +vt 0.669774 0.686573 +vt 0.669823 0.707307 +vt 0.654310 0.707292 +vt 0.654264 0.686560 +vt 0.654224 0.665840 +vt 0.669731 0.665849 +vt 0.685248 0.665859 +vt 0.685294 0.686586 +vt 0.685346 0.707323 +vt 0.982865 0.770381 +vt 0.982957 0.791234 +vt 0.967205 0.791169 +vt 0.967110 0.770320 +vt 0.967022 0.749477 +vt 0.982780 0.749533 +vt 0.998549 0.749592 +vt 0.998631 0.770446 +vt 0.998720 0.791304 +vt 0.919912 0.770155 +vt 0.920014 0.790990 +vt 0.904306 0.790936 +vt 0.904204 0.770105 +vt 0.904110 0.749282 +vt 0.919820 0.749327 +vt 0.935542 0.749374 +vt 0.935633 0.770207 +vt 0.935733 0.791047 +vt 0.919594 0.686880 +vt 0.919661 0.707690 +vt 0.903949 0.707656 +vt 0.903881 0.686852 +vt 0.903822 0.666053 +vt 0.919535 0.666073 +vt 0.935262 0.666095 +vt 0.935320 0.686909 +vt 0.935386 0.707726 +vt 0.236679 0.437870 +vt 0.236690 0.458597 +vt 0.221137 0.458547 +vt 0.221126 0.437815 +vt 0.221109 0.417076 +vt 0.236662 0.417137 +vt 0.252202 0.417196 +vt 0.252219 0.437924 +vt 0.252229 0.458645 +vt 0.174385 0.437632 +vt 0.174395 0.458384 +vt 0.158786 0.458325 +vt 0.158776 0.437566 +vt 0.158759 0.416802 +vt 0.174368 0.416874 +vt 0.189962 0.416944 +vt 0.189980 0.437695 +vt 0.189990 0.458440 +vt 0.174275 0.354562 +vt 0.174312 0.375340 +vt 0.158704 0.375255 +vt 0.158666 0.354470 +vt 0.158622 0.333677 +vt 0.174231 0.333773 +vt 0.189826 0.333866 +vt 0.189870 0.354649 +vt 0.189907 0.375422 +vt 0.236088 0.790441 +vt 0.220515 0.790473 +vt 0.220602 0.769669 +vt 0.236173 0.769639 +vt 0.220683 0.748878 +vt 0.236251 0.748852 +vt 0.251807 0.748827 +vt 0.251732 0.769612 +vt 0.251651 0.790411 +vt 0.173725 0.790584 +vt 0.158105 0.790625 +vt 0.158200 0.769809 +vt 0.173819 0.769770 +vt 0.158287 0.749003 +vt 0.173905 0.748969 +vt 0.189510 0.748936 +vt 0.189426 0.769734 +vt 0.189334 0.790544 +vt 0.174056 0.707397 +vt 0.158440 0.707421 +vt 0.158504 0.686643 +vt 0.174120 0.686624 +vt 0.158562 0.665872 +vt 0.174176 0.665859 +vt 0.189777 0.665847 +vt 0.189721 0.686606 +vt 0.189658 0.707374 +vt 0.484160 0.790246 +vt 0.468687 0.790244 +vt 0.468691 0.769458 +vt 0.484158 0.769459 +vt 0.468695 0.748690 +vt 0.484155 0.748692 +vt 0.499616 0.748691 +vt 0.499624 0.769458 +vt 0.499633 0.790244 +vt 0.422262 0.790239 +vt 0.406783 0.790242 +vt 0.406814 0.769455 +vt 0.422287 0.769452 +vt 0.406843 0.748687 +vt 0.422310 0.748684 +vt 0.437773 0.748684 +vt 0.437757 0.769452 +vt 0.437739 0.790238 +vt 0.422350 0.707199 +vt 0.406894 0.707200 +vt 0.406916 0.686478 +vt 0.422368 0.686478 +vt 0.406936 0.665769 +vt 0.422384 0.665769 +vt 0.437828 0.665771 +vt 0.437817 0.686479 +vt 0.437803 0.707199 +vt 0.731761 0.603717 +vt 0.731790 0.624436 +vt 0.716240 0.624434 +vt 0.716213 0.603720 +vt 0.716192 0.583009 +vt 0.731740 0.583001 +vt 0.747300 0.582993 +vt 0.747322 0.603714 +vt 0.747353 0.624438 +vt 0.669641 0.603726 +vt 0.669664 0.624427 +vt 0.654162 0.624425 +vt 0.654140 0.603727 +vt 0.654124 0.583034 +vt 0.669624 0.583029 +vt 0.685135 0.583023 +vt 0.685153 0.603724 +vt 0.685178 0.624430 +vt 0.669605 0.541642 +vt 0.654106 0.541655 +vt 0.654100 0.520967 +vt 0.669597 0.520950 +vt 0.654100 0.500279 +vt 0.669597 0.500257 +vt 0.685105 0.500234 +vt 0.685106 0.520931 +vt 0.685114 0.541627 +vt 0.235718 0.104691 +vt 0.235819 0.125633 +vt 0.220238 0.125536 +vt 0.220134 0.104596 +vt 0.220024 0.083637 +vt 0.235612 0.083730 +vt 0.251192 0.083817 +vt 0.251294 0.104780 +vt 0.251391 0.125723 +vt 0.173331 0.104276 +vt 0.173443 0.125212 +vt 0.157826 0.125093 +vt 0.157712 0.104157 +vt 0.157592 0.083207 +vt 0.173213 0.083323 +vt 0.188824 0.083434 +vt 0.188940 0.104388 +vt 0.189050 0.125326 +vt 0.172821 0.020368 +vt 0.172958 0.041369 +vt 0.157334 0.041259 +vt 0.157195 0.020261 +vt 0.157050 -0.000752 +vt 0.172678 -0.000650 +vt 0.188300 -0.000554 +vt 0.188440 0.020469 +vt 0.188574 0.041474 +vt 0.484298 0.126363 +vt 0.468790 0.126355 +vt 0.468792 0.105392 +vt 0.484309 0.105402 +vt 0.468794 0.084406 +vt 0.484320 0.084414 +vt 0.499847 0.084427 +vt 0.499827 0.105413 +vt 0.499807 0.126374 +vt 0.422238 0.105360 +vt 0.422262 0.126320 +vt 0.406750 0.126296 +vt 0.406718 0.105337 +vt 0.406683 0.084354 +vt 0.422212 0.084375 +vt 0.437740 0.084391 +vt 0.437757 0.105376 +vt 0.437772 0.126337 +vt 0.422124 0.021273 +vt 0.422155 0.042332 +vt 0.406608 0.042315 +vt 0.406566 0.021258 +vt 0.406522 0.000176 +vt 0.422089 0.000187 +vt 0.437658 0.000194 +vt 0.437681 0.021282 +vt 0.437703 0.042344 +vt 0.607698 0.603729 +vt 0.607715 0.624417 +vt 0.592250 0.624414 +vt 0.592236 0.603729 +vt 0.592225 0.583048 +vt 0.607687 0.583046 +vt 0.623156 0.583043 +vt 0.623169 0.603729 +vt 0.623188 0.624420 +vt 0.545889 0.603727 +vt 0.545898 0.624407 +vt 0.530458 0.624404 +vt 0.530451 0.603725 +vt 0.530448 0.583051 +vt 0.545884 0.583052 +vt 0.561325 0.583051 +vt 0.561332 0.603728 +vt 0.561343 0.624409 +vt 0.545880 0.541710 +vt 0.530446 0.541712 +vt 0.530446 0.521044 +vt 0.545879 0.521041 +vt 0.530449 0.500376 +vt 0.545882 0.500372 +vt 0.561319 0.500365 +vt 0.561318 0.521036 +vt 0.561319 0.541707 +vt 0.484173 0.459027 +vt 0.468745 0.459022 +vt 0.468749 0.438340 +vt 0.484178 0.438345 +vt 0.468752 0.417649 +vt 0.484183 0.417654 +vt 0.499614 0.417659 +vt 0.499607 0.438350 +vt 0.499601 0.459031 +vt 0.422455 0.438309 +vt 0.422456 0.458993 +vt 0.407020 0.458976 +vt 0.407017 0.438291 +vt 0.407013 0.417597 +vt 0.422452 0.417616 +vt 0.437887 0.417631 +vt 0.437888 0.438323 +vt 0.437888 0.459006 +vt 0.422434 0.355474 +vt 0.422442 0.376200 +vt 0.406997 0.376179 +vt 0.406987 0.355451 +vt 0.406974 0.334710 +vt 0.422425 0.334733 +vt 0.437873 0.334751 +vt 0.437878 0.355491 +vt 0.437882 0.376217 +vt 0.982315 0.457839 +vt 0.966547 0.457909 +vt 0.966556 0.437083 +vt 0.982323 0.437004 +vt 0.966573 0.416256 +vt 0.982338 0.416168 +vt 0.998115 0.416077 +vt 0.998103 0.436922 +vt 0.998097 0.457766 +vt 0.919326 0.458105 +vt 0.903614 0.458167 +vt 0.903629 0.437375 +vt 0.919340 0.437305 +vt 0.903652 0.416579 +vt 0.919362 0.416502 +vt 0.935085 0.416423 +vt 0.935065 0.437234 +vt 0.935052 0.458042 +vt 0.919428 0.374884 +vt 0.903722 0.374976 +vt 0.903768 0.354166 +vt 0.919473 0.354068 +vt 0.903822 0.333349 +vt 0.919526 0.333245 +vt 0.935242 0.333138 +vt 0.935192 0.353967 +vt 0.935149 0.374790 +vt 0.732070 0.292714 +vt 0.716516 0.292783 +vt 0.716588 0.271983 +vt 0.732143 0.271911 +vt 0.716665 0.251168 +vt 0.732223 0.251094 +vt 0.747792 0.251016 +vt 0.747710 0.271835 +vt 0.747634 0.292640 +vt 0.669921 0.292968 +vt 0.654410 0.293020 +vt 0.654469 0.272227 +vt 0.669984 0.272173 +vt 0.654534 0.251417 +vt 0.670052 0.251362 +vt 0.685580 0.251302 +vt 0.685509 0.272114 +vt 0.685442 0.292911 +vt 0.670204 0.209688 +vt 0.654677 0.209743 +vt 0.654755 0.188879 +vt 0.670287 0.188823 +vt 0.654838 0.167994 +vt 0.670375 0.167939 +vt 0.685920 0.167879 +vt 0.685827 0.188762 +vt 0.685740 0.209627 +vt 0.607927 0.293148 +vt 0.592448 0.293180 +vt 0.592492 0.272391 +vt 0.607975 0.272358 +vt 0.592539 0.251584 +vt 0.608027 0.251550 +vt 0.623522 0.251511 +vt 0.623465 0.272319 +vt 0.623413 0.293110 +vt 0.546046 0.293245 +vt 0.530587 0.293256 +vt 0.530612 0.272467 +vt 0.546075 0.272457 +vt 0.530637 0.251660 +vt 0.546107 0.251650 +vt 0.561579 0.251634 +vt 0.561543 0.272441 +vt 0.561509 0.293229 +vt 0.546175 0.209977 +vt 0.530693 0.209987 +vt 0.530724 0.189118 +vt 0.546213 0.189109 +vt 0.530756 0.168228 +vt 0.546252 0.168220 +vt 0.561750 0.168205 +vt 0.561704 0.189094 +vt 0.561660 0.209961 +vt 0.608413 0.126289 +vt 0.592888 0.126319 +vt 0.592957 0.105365 +vt 0.608489 0.105337 +vt 0.593030 0.084389 +vt 0.608570 0.084363 +vt 0.624114 0.084331 +vt 0.624026 0.105303 +vt 0.623942 0.126253 +vt 0.546337 0.126373 +vt 0.530825 0.126379 +vt 0.530862 0.105420 +vt 0.546382 0.105415 +vt 0.530901 0.084436 +vt 0.546430 0.084432 +vt 0.561961 0.084423 +vt 0.561904 0.105404 +vt 0.561851 0.126361 +vt 0.546533 0.042393 +vt 0.530985 0.042393 +vt 0.531030 0.021333 +vt 0.546588 0.021336 +vt 0.531078 0.000247 +vt 0.546646 0.000254 +vt 0.562215 0.000256 +vt 0.562147 0.021335 +vt 0.562082 0.042389 +vt 0.607687 0.458966 +vt 0.592229 0.458985 +vt 0.592243 0.438297 +vt 0.607702 0.438276 +vt 0.592261 0.417601 +vt 0.607722 0.417577 +vt 0.623191 0.417551 +vt 0.623170 0.438251 +vt 0.623155 0.458945 +vt 0.545895 0.459023 +vt 0.530460 0.459029 +vt 0.530470 0.438347 +vt 0.545905 0.438340 +vt 0.530481 0.417656 +vt 0.545918 0.417648 +vt 0.561360 0.417636 +vt 0.561345 0.438329 +vt 0.561333 0.459013 +vt 0.545952 0.376235 +vt 0.530509 0.376244 +vt 0.530526 0.355519 +vt 0.545972 0.355510 +vt 0.530545 0.334781 +vt 0.545994 0.334771 +vt 0.561448 0.334755 +vt 0.561422 0.355495 +vt 0.561398 0.376221 +vt 0.982575 0.291085 +vt 0.966827 0.291215 +vt 0.966896 0.270357 +vt 0.982640 0.270222 +vt 0.966971 0.249493 +vt 0.982713 0.249354 +vt 0.998465 0.249210 +vt 0.998396 0.270083 +vt 0.998335 0.290951 +vt 0.919654 0.291581 +vt 0.903954 0.291695 +vt 0.904031 0.270856 +vt 0.919729 0.270737 +vt 0.904115 0.250007 +vt 0.919812 0.249885 +vt 0.935521 0.249758 +vt 0.935440 0.270614 +vt 0.935367 0.291463 +vt 0.920000 0.208155 +vt 0.904307 0.208283 +vt 0.904413 0.187406 +vt 0.920105 0.187275 +vt 0.904527 0.166518 +vt 0.920218 0.166386 +vt 0.935917 0.166250 +vt 0.935807 0.187141 +vt 0.935704 0.208022 +vt 0.856927 0.292016 +vt 0.841277 0.292116 +vt 0.841357 0.271293 +vt 0.857007 0.271189 +vt 0.841445 0.250458 +vt 0.857095 0.250352 +vt 0.872756 0.250241 +vt 0.872669 0.271082 +vt 0.872590 0.291913 +vt 0.794400 0.292395 +vt 0.778799 0.292480 +vt 0.778878 0.271670 +vt 0.794479 0.271581 +vt 0.778963 0.250846 +vt 0.794566 0.250755 +vt 0.810180 0.250660 +vt 0.810093 0.271489 +vt 0.810013 0.292306 +vt 0.794760 0.209063 +vt 0.779154 0.209157 +vt 0.779260 0.188290 +vt 0.794867 0.188195 +vt 0.779371 0.167408 +vt 0.794980 0.167313 +vt 0.810599 0.167212 +vt 0.810484 0.188096 +vt 0.810376 0.208964 +vt 0.779055 0.230009 +vt 0.794659 0.229916 +vt 0.810275 0.229819 +vt 0.763372 0.250933 +vt 0.747881 0.230182 +vt 0.763462 0.230098 +vt 0.763559 0.209247 +vt 0.763663 0.188381 +vt 0.763772 0.167499 +vt 0.778728 0.313278 +vt 0.794328 0.313196 +vt 0.809940 0.313111 +vt 0.763077 0.334139 +vt 0.747565 0.313431 +vt 0.763141 0.313357 +vt 0.763211 0.292562 +vt 0.763288 0.271754 +vt 0.841203 0.312929 +vt 0.856854 0.312834 +vt 0.872518 0.312734 +vt 0.825500 0.333820 +vt 0.825565 0.313022 +vt 0.825638 0.292213 +vt 0.825719 0.271393 +vt 0.825807 0.250561 +vt 0.904207 0.229150 +vt 0.919903 0.229024 +vt 0.935609 0.228894 +vt 0.888430 0.250126 +vt 0.872851 0.229389 +vt 0.888523 0.229272 +vt 0.888624 0.208407 +vt 0.888732 0.187531 +vt 0.888847 0.166644 +vt 0.903884 0.312526 +vt 0.919586 0.312417 +vt 0.935301 0.312304 +vt 0.888132 0.333450 +vt 0.888195 0.312632 +vt 0.888266 0.291806 +vt 0.888344 0.270971 +vt 0.966767 0.312067 +vt 0.982518 0.311943 +vt 0.998280 0.311815 +vt 0.950972 0.333028 +vt 0.951028 0.312187 +vt 0.951091 0.291341 +vt 0.951162 0.270488 +vt 0.951240 0.249628 +vt 0.530494 0.396956 +vt 0.545934 0.396947 +vt 0.561378 0.396934 +vt 0.515047 0.417660 +vt 0.499623 0.396959 +vt 0.515057 0.396960 +vt 0.515069 0.376248 +vt 0.515083 0.355524 +vt 0.515098 0.334785 +vt 0.530453 0.479705 +vt 0.545887 0.479699 +vt 0.561325 0.479691 +vt 0.515019 0.500378 +vt 0.499596 0.479706 +vt 0.515024 0.479707 +vt 0.515030 0.459032 +vt 0.515037 0.438350 +vt 0.592219 0.479667 +vt 0.607677 0.479651 +vt 0.623144 0.479632 +vt 0.576763 0.500356 +vt 0.576769 0.479680 +vt 0.576778 0.459000 +vt 0.576791 0.438314 +vt 0.576807 0.417620 +vt 0.530942 0.063427 +vt 0.546480 0.063425 +vt 0.562020 0.063418 +vt 0.515374 0.084434 +vt 0.499869 0.063415 +vt 0.515405 0.063423 +vt 0.515438 0.042387 +vt 0.515472 0.021325 +vt 0.515509 0.000236 +vt 0.530790 0.147315 +vt 0.546293 0.147308 +vt 0.561799 0.147295 +vt 0.515262 0.168230 +vt 0.499788 0.147312 +vt 0.515288 0.147317 +vt 0.515316 0.126380 +vt 0.515344 0.105419 +vt 0.592822 0.147250 +vt 0.608339 0.147218 +vt 0.623862 0.147181 +vt 0.577252 0.168185 +vt 0.577308 0.147275 +vt 0.577367 0.126343 +vt 0.577429 0.105387 +vt 0.577494 0.084409 +vt 0.530664 0.230834 +vt 0.546140 0.230824 +vt 0.561619 0.230808 +vt 0.515170 0.251664 +vt 0.499720 0.230835 +vt 0.515191 0.230837 +vt 0.515214 0.209990 +vt 0.515238 0.189121 +vt 0.530565 0.314026 +vt 0.546019 0.314016 +vt 0.561477 0.314001 +vt 0.499665 0.314030 +vt 0.515114 0.314031 +vt 0.515131 0.293260 +vt 0.515150 0.272472 +vt 0.592408 0.313953 +vt 0.607883 0.313921 +vt 0.623365 0.313885 +vt 0.576907 0.334735 +vt 0.576940 0.313979 +vt 0.576976 0.293208 +vt 0.577015 0.272419 +vt 0.577057 0.251612 +vt 0.654603 0.230589 +vt 0.670126 0.230534 +vt 0.685657 0.230473 +vt 0.639024 0.251466 +vt 0.623582 0.230684 +vt 0.639089 0.230639 +vt 0.639158 0.209794 +vt 0.639231 0.188929 +vt 0.639309 0.168044 +vt 0.654355 0.313797 +vt 0.669863 0.313747 +vt 0.685382 0.313692 +vt 0.638809 0.334604 +vt 0.638856 0.313843 +vt 0.638907 0.293068 +vt 0.638963 0.272276 +vt 0.716451 0.313570 +vt 0.732002 0.313502 +vt 0.700854 0.334403 +vt 0.700911 0.313633 +vt 0.700974 0.292849 +vt 0.701043 0.272051 +vt 0.701118 0.251237 +vt 0.903683 0.395780 +vt 0.919391 0.395696 +vt 0.935113 0.395608 +vt 0.887957 0.416654 +vt 0.872308 0.395941 +vt 0.887989 0.395862 +vt 0.888028 0.375064 +vt 0.888076 0.354260 +vt 0.903607 0.478956 +vt 0.919320 0.478902 +vt 0.935047 0.478848 +vt 0.887908 0.499787 +vt 0.872224 0.479058 +vt 0.887908 0.479008 +vt 0.887916 0.458226 +vt 0.887932 0.437442 +vt 0.966544 0.478732 +vt 0.982315 0.478672 +vt 0.998099 0.478609 +vt 0.950792 0.499605 +vt 0.950789 0.478791 +vt 0.950792 0.457976 +vt 0.950804 0.437160 +vt 0.950822 0.416341 +vt 0.422448 0.396914 +vt 0.407006 0.396893 +vt 0.437885 0.396930 +vt 0.391560 0.396868 +vt 0.391569 0.417573 +vt 0.376108 0.396839 +vt 0.391549 0.376152 +vt 0.391535 0.355423 +vt 0.391519 0.334681 +vt 0.422455 0.479671 +vt 0.407020 0.479656 +vt 0.437886 0.479683 +vt 0.391580 0.479638 +vt 0.391578 0.500314 +vt 0.376134 0.479617 +vt 0.391579 0.458956 +vt 0.391575 0.438269 +vt 0.468742 0.479698 +vt 0.484169 0.479703 +vt 0.453315 0.479692 +vt 0.453312 0.500363 +vt 0.453317 0.459016 +vt 0.453319 0.438333 +vt 0.453320 0.417642 +vt 0.545881 0.562380 +vt 0.530446 0.562381 +vt 0.561321 0.562378 +vt 0.515015 0.562381 +vt 0.515015 0.583050 +vt 0.499585 0.562379 +vt 0.515015 0.541713 +vt 0.515016 0.521045 +vt 0.545909 0.645094 +vt 0.530466 0.645091 +vt 0.561356 0.645098 +vt 0.515026 0.645088 +vt 0.515033 0.665783 +vt 0.499588 0.645086 +vt 0.515021 0.624402 +vt 0.515017 0.603724 +vt 0.607736 0.645111 +vt 0.592269 0.645106 +vt 0.623212 0.645117 +vt 0.576810 0.645102 +vt 0.576830 0.665801 +vt 0.576793 0.624412 +vt 0.576780 0.603728 +vt 0.576772 0.583050 +vt 0.422185 0.063366 +vt 0.406647 0.063347 +vt 0.437722 0.063380 +vt 0.391107 0.063322 +vt 0.391153 0.084327 +vt 0.375565 0.063292 +vt 0.391059 0.042293 +vt 0.391008 0.021239 +vt 0.390953 0.000160 +vt 0.422285 0.147257 +vt 0.406781 0.147232 +vt 0.437787 0.147275 +vt 0.391274 0.147201 +vt 0.391310 0.168114 +vt 0.375764 0.147164 +vt 0.391236 0.126267 +vt 0.391195 0.105309 +vt 0.468788 0.147293 +vt 0.484288 0.147302 +vt 0.453288 0.147287 +vt 0.453293 0.168202 +vt 0.453281 0.126349 +vt 0.453275 0.105387 +vt 0.453267 0.084401 +vt 0.173088 0.062354 +vt 0.157466 0.062241 +vt 0.188702 0.062463 +vt 0.141836 0.062120 +vt 0.141964 0.083084 +vt 0.126198 0.061995 +vt 0.141702 0.041142 +vt 0.141562 0.020148 +vt 0.141415 -0.000860 +vt 0.173549 0.146133 +vt 0.157934 0.146013 +vt 0.189155 0.146247 +vt 0.142308 0.145887 +vt 0.142411 0.166793 +vt 0.126673 0.145756 +vt 0.142200 0.124967 +vt 0.142085 0.104033 +vt 0.235914 0.146556 +vt 0.220337 0.146459 +vt 0.251483 0.146648 +vt 0.204751 0.146356 +vt 0.204847 0.167261 +vt 0.204649 0.125434 +vt 0.204541 0.104495 +vt 0.204428 0.083539 +vt 0.669613 0.562335 +vt 0.654115 0.562344 +vt 0.685123 0.562325 +vt 0.638626 0.562352 +vt 0.638635 0.583039 +vt 0.623149 0.562360 +vt 0.638619 0.541667 +vt 0.638614 0.520983 +vt 0.638614 0.500298 +vt 0.669694 0.645134 +vt 0.654190 0.645128 +vt 0.685210 0.645141 +vt 0.638696 0.645122 +vt 0.638728 0.665831 +vt 0.638670 0.624422 +vt 0.638650 0.603728 +vt 0.731827 0.645160 +vt 0.716276 0.645154 +vt 0.747391 0.645167 +vt 0.700737 0.645147 +vt 0.700777 0.665869 +vt 0.700703 0.624432 +vt 0.700677 0.603722 +vt 0.700657 0.583017 +vt 0.406870 0.727936 +vt 0.422331 0.727934 +vt 0.437789 0.727934 +vt 0.391373 0.748692 +vt 0.375934 0.727946 +vt 0.391404 0.727940 +vt 0.391434 0.707203 +vt 0.391460 0.686480 +vt 0.391484 0.665769 +vt 0.406750 0.811048 +vt 0.422236 0.811045 +vt 0.437719 0.811044 +vt 0.391217 0.831881 +vt 0.375766 0.811063 +vt 0.391260 0.811054 +vt 0.391300 0.790248 +vt 0.391338 0.769461 +vt 0.468682 0.811051 +vt 0.484163 0.811051 +vt 0.499644 0.811049 +vt 0.453189 0.831873 +vt 0.453201 0.811046 +vt 0.453213 0.790240 +vt 0.453224 0.769454 +vt 0.453235 0.748686 +vt 0.158367 0.728207 +vt 0.173984 0.728178 +vt 0.189588 0.728150 +vt 0.142656 0.749039 +vt 0.127093 0.728273 +vt 0.142737 0.728239 +vt 0.142810 0.707447 +vt 0.142875 0.686663 +vt 0.142933 0.665886 +vt 0.158002 0.811454 +vt 0.173624 0.811409 +vt 0.189234 0.811367 +vt 0.142256 0.832346 +vt 0.126722 0.811553 +vt 0.142368 0.811502 +vt 0.142472 0.790670 +vt 0.142568 0.769850 +vt 0.220421 0.811291 +vt 0.235997 0.811257 +vt 0.251563 0.811226 +vt 0.204729 0.832163 +vt 0.204833 0.811328 +vt 0.204930 0.790507 +vt 0.205020 0.769700 +vt 0.205103 0.748906 +vt 0.174343 0.396111 +vt 0.158735 0.396032 +vt 0.189938 0.396187 +vt 0.143112 0.395949 +vt 0.143135 0.416726 +vt 0.127474 0.395864 +vt 0.143081 0.375166 +vt 0.143044 0.354375 +vt 0.143000 0.333576 +vt 0.174399 0.479132 +vt 0.158789 0.479080 +vt 0.189994 0.479181 +vt 0.143164 0.479026 +vt 0.143160 0.499787 +vt 0.127524 0.478971 +vt 0.143162 0.458264 +vt 0.143152 0.437497 +vt 0.236694 0.479320 +vt 0.221141 0.479275 +vt 0.252234 0.479362 +vt 0.205575 0.479229 +vt 0.205572 0.499961 +vt 0.205571 0.458495 +vt 0.205560 0.437756 +vt 0.205542 0.417012 +vt 0.919736 0.728506 +vt 0.904025 0.728466 +vt 0.935460 0.728547 +vt 0.888327 0.728429 +vt 0.888413 0.749239 +vt 0.872642 0.728393 +vt 0.888250 0.707624 +vt 0.888182 0.686827 +vt 0.888122 0.666034 +vt 0.920123 0.811833 +vt 0.904417 0.811776 +vt 0.935841 0.811893 +vt 0.888721 0.811721 +vt 0.888841 0.832567 +vt 0.873037 0.811669 +vt 0.888609 0.790885 +vt 0.888507 0.770058 +vt 0.983059 0.812093 +vt 0.967309 0.812023 +vt 0.998818 0.812167 +vt 0.951570 0.811956 +vt 0.951685 0.832814 +vt 0.951464 0.791106 +vt 0.951366 0.770262 +vt 0.951276 0.749424 +vt 0.669878 0.728053 +vt 0.654362 0.728036 +vt 0.685405 0.728072 +vt 0.638856 0.728019 +vt 0.638910 0.748775 +vt 0.623358 0.728004 +vt 0.638807 0.707277 +vt 0.638765 0.686549 +vt 0.670162 0.811184 +vt 0.654628 0.811161 +vt 0.685704 0.811210 +vt 0.639103 0.811139 +vt 0.639178 0.831963 +vt 0.623586 0.811120 +vt 0.639033 0.790334 +vt 0.638969 0.769546 +vt 0.732390 0.811298 +vt 0.716818 0.811267 +vt 0.747973 0.811332 +vt 0.701256 0.811237 +vt 0.701352 0.832063 +vt 0.701168 0.790428 +vt 0.701085 0.769635 +vt 0.701010 0.748857 +vt 0.654187 0.396771 +vt 0.669686 0.396731 +vt 0.685197 0.396688 +vt 0.638670 0.417520 +vt 0.623217 0.396841 +vt 0.638697 0.396808 +vt 0.638729 0.376085 +vt 0.638767 0.355351 +vt 0.654106 0.479588 +vt 0.669602 0.479562 +vt 0.685110 0.479535 +vt 0.638620 0.479611 +vt 0.638631 0.458920 +vt 0.638648 0.438224 +vt 0.716162 0.479473 +vt 0.731707 0.479439 +vt 0.747264 0.479404 +vt 0.700625 0.500209 +vt 0.700630 0.479505 +vt 0.700642 0.458798 +vt 0.700661 0.438086 +vt 0.700687 0.417367 +vt 0.905205 0.061911 +vt 0.920887 0.061784 +vt 0.936576 0.061652 +vt 0.889380 0.082979 +vt 0.873864 0.062150 +vt 0.889530 0.062033 +vt 0.889688 0.041074 +vt 0.889853 0.020103 +vt 0.890024 -0.000881 +vt 0.904649 0.145619 +vt 0.920337 0.145487 +vt 0.936035 0.145350 +vt 0.873300 0.145869 +vt 0.888970 0.145746 +vt 0.889099 0.124836 +vt 0.889236 0.103914 +vt 0.967458 0.145063 +vt 0.983182 0.144912 +vt 0.998915 0.144757 +vt 0.951627 0.166110 +vt 0.951742 0.145209 +vt 0.951864 0.124299 +vt 0.951993 0.103380 +vt 0.952129 0.082452 +vt 0.655322 0.063262 +vt 0.670887 0.063217 +vt 0.686459 0.063166 +vt 0.639662 0.084294 +vt 0.624205 0.063336 +vt 0.639761 0.063302 +vt 0.639864 0.042288 +vt 0.639972 0.021251 +vt 0.640085 0.000191 +vt 0.654926 0.147090 +vt 0.670468 0.147036 +vt 0.686017 0.146976 +vt 0.639391 0.147138 +vt 0.639477 0.126212 +vt 0.639567 0.105264 +vt 0.717140 0.146841 +vt 0.732714 0.146766 +vt 0.748296 0.146685 +vt 0.701472 0.167813 +vt 0.701574 0.146911 +vt 0.701682 0.125991 +vt 0.701795 0.105050 +vt 0.701913 0.084090 +vt 0.780027 0.062749 +vt 0.795647 0.062662 +vt 0.811274 0.062570 +vt 0.764273 0.083800 +vt 0.748809 0.062909 +vt 0.764414 0.062832 +vt 0.764561 0.041846 +vt 0.764714 0.020841 +vt 0.764874 -0.000181 +vt 0.779490 0.146510 +vt 0.795100 0.146414 +vt 0.810721 0.146315 +vt 0.763888 0.146600 +vt 0.764011 0.125684 +vt 0.764139 0.104751 +vt 0.841991 0.146101 +vt 0.857641 0.145987 +vt 0.826228 0.167108 +vt 0.826351 0.146210 +vt 0.826481 0.125298 +vt 0.826617 0.104371 +vt 0.826760 0.083429 +vt 0.670542 0.894600 +vt 0.654985 0.894578 +vt 0.686107 0.894625 +vt 0.639435 0.894559 +vt 0.639531 0.915468 +vt 0.623891 0.894542 +vt 0.639344 0.873672 +vt 0.639258 0.852807 +vt 0.671021 0.978356 +vt 0.671156 0.999353 +vt 0.655562 0.999345 +vt 0.655434 0.978344 +vt 0.686613 0.978370 +vt 0.686755 0.999363 +vt 0.639853 0.978335 +vt 0.639972 0.999340 +vt 0.624386 0.999337 +vt 0.624276 0.978328 +vt 0.639740 0.957355 +vt 0.639633 0.936400 +vt 0.733425 0.978429 +vt 0.733588 0.999409 +vt 0.717971 0.999391 +vt 0.717814 0.978407 +vt 0.749042 0.978454 +vt 0.749210 0.999430 +vt 0.702210 0.978387 +vt 0.702360 0.999376 +vt 0.702067 0.957421 +vt 0.701931 0.936477 +vt 0.701802 0.915554 +vt 0.546246 0.894495 +vt 0.530727 0.894493 +vt 0.561767 0.894499 +vt 0.515210 0.894493 +vt 0.515235 0.915415 +vt 0.499694 0.894495 +vt 0.515186 0.873596 +vt 0.515164 0.852724 +vt 0.515144 0.831876 +vt 0.546443 0.978329 +vt 0.546500 0.999356 +vt 0.530928 0.999365 +vt 0.530882 0.978335 +vt 0.562005 0.978324 +vt 0.562074 0.999348 +vt 0.515321 0.978343 +vt 0.515355 0.999376 +vt 0.499781 0.999387 +vt 0.499761 0.978351 +vt 0.515291 0.957339 +vt 0.515262 0.936363 +vt 0.608704 0.978324 +vt 0.608804 0.999336 +vt 0.593225 0.999338 +vt 0.593135 0.978322 +vt 0.577569 0.978322 +vt 0.577648 0.999342 +vt 0.577493 0.957329 +vt 0.577422 0.936363 +vt 0.577355 0.915422 +vt 0.545980 0.727951 +vt 0.530520 0.727946 +vt 0.561444 0.727958 +vt 0.515063 0.727942 +vt 0.515077 0.748692 +vt 0.499608 0.727941 +vt 0.515052 0.707209 +vt 0.515042 0.686490 +vt 0.546093 0.811057 +vt 0.530608 0.811052 +vt 0.561581 0.811065 +vt 0.515125 0.811049 +vt 0.515107 0.790244 +vt 0.515091 0.769458 +vt 0.608075 0.811102 +vt 0.592572 0.811087 +vt 0.577074 0.811075 +vt 0.577123 0.831900 +vt 0.577029 0.790271 +vt 0.576986 0.769485 +vt 0.576948 0.748718 +vt 0.920650 0.895294 +vt 0.904948 0.895230 +vt 0.936362 0.895361 +vt 0.889254 0.895169 +vt 0.889410 0.916059 +vt 0.873571 0.895111 +vt 0.889108 0.874290 +vt 0.888970 0.853423 +vt 0.921319 0.978918 +vt 0.921509 0.999853 +vt 0.905811 0.999797 +vt 0.905621 0.978860 +vt 0.937025 0.978981 +vt 0.937213 0.999912 +vt 0.889929 0.978805 +vt 0.890120 0.999746 +vt 0.874436 0.999698 +vt 0.874245 0.978753 +vt 0.889747 0.957877 +vt 0.889574 0.936962 +vt 0.984182 0.979192 +vt 0.984362 1.000114 +vt 0.968640 1.000042 +vt 0.968456 0.979118 +vt 0.999914 0.979271 +vt 0.996113 0.994940 +vt 0.952737 0.979047 +vt 0.952923 0.999975 +vt 0.952560 0.958129 +vt 0.952392 0.937221 +vt 0.952233 0.916322 +vt 0.795296 0.894864 +vt 0.779671 0.894823 +vt 0.810932 0.894908 +vt 0.764054 0.894784 +vt 0.764196 0.915680 +vt 0.748447 0.894747 +vt 0.763921 0.873905 +vt 0.763795 0.853043 +vt 0.763677 0.832197 +vt 0.795937 0.978544 +vt 0.796118 0.999508 +vt 0.780476 0.999479 +vt 0.780298 0.978511 +vt 0.811584 0.978580 +vt 0.811768 0.999540 +vt 0.764667 0.978481 +vt 0.764840 0.999453 +vt 0.764502 0.957528 +vt 0.764345 0.936595 +vt 0.858569 0.978705 +vt 0.858759 0.999654 +vt 0.843088 0.999613 +vt 0.842900 0.978661 +vt 0.827238 0.978619 +vt 0.827425 0.999575 +vt 0.827060 0.957679 +vt 0.826890 0.936756 +vt 0.826730 0.915848 +vt 0.794408 0.728238 +vt 0.778799 0.728211 +vt 0.810029 0.728266 +vt 0.763204 0.728185 +vt 0.763283 0.748961 +vt 0.747620 0.728160 +vt 0.763133 0.707419 +vt 0.763070 0.686663 +vt 0.763014 0.665915 +vt 0.794787 0.811443 +vt 0.779171 0.811404 +vt 0.810414 0.811484 +vt 0.763566 0.811367 +vt 0.763464 0.790551 +vt 0.763369 0.769750 +vt 0.857364 0.811620 +vt 0.841702 0.811572 +vt 0.826052 0.811527 +vt 0.826171 0.832364 +vt 0.825942 0.790703 +vt 0.825841 0.769890 +vt 0.825747 0.749088 +vt 0.158736 0.562085 +vt 0.174348 0.562107 +vt 0.189945 0.562129 +vt 0.143089 0.582823 +vt 0.127467 0.562040 +vt 0.143129 0.541304 +vt 0.143109 0.562063 +vt 0.143148 0.520546 +vt 0.158611 0.645107 +vt 0.174225 0.645100 +vt 0.189825 0.645095 +vt 0.127340 0.645122 +vt 0.142983 0.645114 +vt 0.143026 0.624347 +vt 0.143061 0.603584 +vt 0.220982 0.645086 +vt 0.236541 0.645082 +vt 0.252086 0.645078 +vt 0.205363 0.665836 +vt 0.205410 0.645090 +vt 0.205450 0.624349 +vt 0.205483 0.603613 +vt 0.205509 0.582880 +vt 0.033286 0.561900 +vt 0.049023 0.561923 +vt 0.064743 0.561947 +vt 0.017513 0.582714 +vt 0.001744 0.582705 +vt 0.001761 0.561855 +vt 0.001783 0.541005 +vt 0.017553 0.541040 +vt 0.017533 0.561877 +vt 0.017577 0.520204 +vt 0.001808 0.520156 +vt 0.001827 0.499308 +vt 0.017595 0.499368 +vt 0.033169 0.645201 +vt 0.048902 0.645183 +vt 0.064620 0.645167 +vt 0.017377 0.666058 +vt 0.001616 0.666091 +vt 0.001657 0.645244 +vt 0.017421 0.645221 +vt 0.001693 0.624398 +vt 0.017458 0.624385 +vt 0.001721 0.603552 +vt 0.017489 0.603550 +vt 0.096010 0.645142 +vt 0.111683 0.645131 +vt 0.080273 0.665956 +vt 0.080322 0.645154 +vt 0.080364 0.624355 +vt 0.080399 0.603559 +vt 0.080427 0.582764 +vt 0.049063 0.395389 +vt 0.033337 0.395284 +vt 0.064775 0.395491 +vt 0.017595 0.395176 +vt 0.017607 0.416018 +vt 0.001848 0.415915 +vt 0.001838 0.395063 +vt 0.001822 0.374209 +vt 0.017576 0.374330 +vt 0.017551 0.353481 +vt 0.001800 0.353351 +vt 0.001772 0.332490 +vt 0.017519 0.332628 +vt 0.049091 0.478667 +vt 0.033357 0.478601 +vt 0.064809 0.478732 +vt 0.017607 0.478532 +vt 0.001841 0.478460 +vt 0.001849 0.457613 +vt 0.017613 0.457695 +vt 0.017613 0.436857 +vt 0.001851 0.436764 +vt 0.111869 0.478914 +vt 0.096198 0.478855 +vt 0.080511 0.478795 +vt 0.080504 0.499589 +vt 0.080512 0.457998 +vt 0.080506 0.437199 +vt 0.080492 0.416396 +vt 0.157514 0.894903 +vt 0.173143 0.894854 +vt 0.188763 0.894807 +vt 0.141731 0.915854 +vt 0.126225 0.895012 +vt 0.141874 0.894956 +vt 0.142010 0.874072 +vt 0.142137 0.853202 +vt 0.172369 0.999521 +vt 0.156726 0.999559 +vt 0.156900 0.978595 +vt 0.172539 0.978553 +vt 0.188171 0.978515 +vt 0.188004 0.999487 +vt 0.141077 0.999601 +vt 0.125420 0.999648 +vt 0.125598 0.978691 +vt 0.141253 0.978641 +vt 0.141420 0.957696 +vt 0.141580 0.936768 +vt 0.234872 0.999406 +vt 0.219256 0.999429 +vt 0.219414 0.978449 +vt 0.235025 0.978422 +vt 0.250629 0.978398 +vt 0.250482 0.999386 +vt 0.203633 0.999456 +vt 0.203796 0.978480 +vt 0.203952 0.957523 +vt 0.204099 0.936585 +vt 0.204240 0.915666 +vt 0.032119 0.895438 +vt 0.047828 0.895356 +vt 0.063528 0.895279 +vt 0.016264 0.916424 +vt 0.000539 0.916517 +vt 0.000673 0.895617 +vt 0.016401 0.895525 +vt 0.000798 0.874725 +vt 0.016529 0.874634 +vt 0.000915 0.853840 +vt 0.016649 0.853751 +vt 0.001023 0.832960 +vt 0.016761 0.832875 +vt 0.047033 0.999947 +vt 0.031334 1.000023 +vt 0.031509 0.979087 +vt 0.047209 0.979008 +vt 0.062902 0.978935 +vt 0.062724 0.999878 +vt 0.015801 0.979170 +vt 0.015629 1.000103 +vt 0.003890 0.994934 +vt 0.000086 0.979259 +vt 0.000246 0.958338 +vt 0.015964 0.958246 +vt 0.000397 0.937423 +vt 0.016118 0.937331 +vt 0.109757 0.999698 +vt 0.094086 0.999753 +vt 0.094265 0.978804 +vt 0.109935 0.978745 +vt 0.078408 0.999813 +vt 0.078587 0.978867 +vt 0.078758 0.957934 +vt 0.078919 0.937012 +vt 0.079072 0.916103 +vt 0.032942 0.728529 +vt 0.048668 0.728479 +vt 0.064381 0.728432 +vt 0.017130 0.749431 +vt 0.001379 0.749496 +vt 0.001449 0.728640 +vt 0.017202 0.728583 +vt 0.001512 0.707788 +vt 0.017268 0.707738 +vt 0.001567 0.686938 +vt 0.017326 0.686897 +vt 0.032595 0.811928 +vt 0.048313 0.811856 +vt 0.064019 0.811788 +vt 0.001124 0.812087 +vt 0.016865 0.812005 +vt 0.001217 0.791218 +vt 0.016961 0.791142 +vt 0.001302 0.770355 +vt 0.017049 0.770284 +vt 0.095395 0.811663 +vt 0.111064 0.811606 +vt 0.079601 0.832579 +vt 0.079713 0.811724 +vt 0.079816 0.790878 +vt 0.079912 0.770040 +vt 0.080000 0.749211 +vt 0.406593 0.894489 +vt 0.422112 0.894488 +vt 0.437630 0.894490 +vt 0.391017 0.915412 +vt 0.375546 0.894500 +vt 0.391071 0.894493 +vt 0.391123 0.873599 +vt 0.391172 0.852729 +vt 0.421909 0.999360 +vt 0.406337 0.999350 +vt 0.406394 0.978324 +vt 0.421955 0.978331 +vt 0.437515 0.978339 +vt 0.437481 0.999372 +vt 0.390764 0.999342 +vt 0.375190 0.999336 +vt 0.375269 0.978317 +vt 0.390833 0.978320 +vt 0.390898 0.957324 +vt 0.390959 0.936355 +vt 0.484205 0.999399 +vt 0.468629 0.999396 +vt 0.468637 0.978359 +vt 0.484199 0.978359 +vt 0.453054 0.999384 +vt 0.453076 0.978349 +vt 0.453095 0.957343 +vt 0.453113 0.936366 +vt 0.453130 0.915416 +vt 0.282289 0.894599 +vt 0.297848 0.894575 +vt 0.313399 0.894554 +vt 0.266608 0.915532 +vt 0.251148 0.894656 +vt 0.266723 0.894626 +vt 0.266831 0.873740 +vt 0.266933 0.852874 +vt 0.267029 0.832026 +vt 0.297279 0.999345 +vt 0.281685 0.999356 +vt 0.281818 0.978359 +vt 0.297405 0.978345 +vt 0.312986 0.978334 +vt 0.312869 0.999338 +vt 0.266086 0.999369 +vt 0.266227 0.978377 +vt 0.266360 0.957407 +vt 0.266487 0.936459 +vt 0.359614 0.999333 +vt 0.344035 0.999332 +vt 0.344135 0.978320 +vt 0.359703 0.978317 +vt 0.328454 0.999334 +vt 0.328562 0.978325 +vt 0.328665 0.957342 +vt 0.328763 0.936383 +vt 0.328856 0.915448 +vt 0.282949 0.728018 +vt 0.298469 0.728002 +vt 0.313979 0.727987 +vt 0.267352 0.748805 +vt 0.251876 0.728056 +vt 0.267418 0.728036 +vt 0.267478 0.707281 +vt 0.267531 0.686536 +vt 0.267578 0.665802 +vt 0.282665 0.811170 +vt 0.298202 0.811146 +vt 0.313729 0.811124 +vt 0.267119 0.811196 +vt 0.267203 0.790383 +vt 0.267281 0.769587 +vt 0.344761 0.811088 +vt 0.360267 0.811074 +vt 0.329180 0.831932 +vt 0.329249 0.811105 +vt 0.329314 0.790297 +vt 0.329374 0.769506 +vt 0.329429 0.748733 +vt 0.173914 0.229664 +vt 0.158303 0.229548 +vt 0.189513 0.229774 +vt 0.142680 0.229428 +vt 0.142757 0.250280 +vt 0.127045 0.229302 +vt 0.142597 0.208563 +vt 0.142507 0.187684 +vt 0.174180 0.312975 +vt 0.158571 0.312874 +vt 0.189776 0.313072 +vt 0.142949 0.312768 +vt 0.127313 0.312658 +vt 0.142891 0.291950 +vt 0.142827 0.271121 +vt 0.236487 0.313338 +vt 0.220929 0.313254 +vt 0.252033 0.313418 +vt 0.205359 0.313165 +vt 0.205408 0.333955 +vt 0.205303 0.292364 +vt 0.205242 0.271550 +vt 0.205174 0.250722 +vt 0.048690 0.228598 +vt 0.032982 0.228442 +vt 0.064385 0.228749 +vt 0.017263 0.228279 +vt 0.017328 0.249162 +vt 0.001593 0.248998 +vt 0.001533 0.228112 +vt 0.001465 0.207218 +vt 0.017192 0.207390 +vt 0.017115 0.186493 +vt 0.001392 0.186318 +vt 0.001311 0.165411 +vt 0.017031 0.165588 +vt 0.048930 0.312046 +vt 0.033212 0.311911 +vt 0.064634 0.312178 +vt 0.017481 0.311770 +vt 0.001737 0.311625 +vt 0.001695 0.290755 +vt 0.017437 0.290907 +vt 0.017385 0.270037 +vt 0.001648 0.269879 +vt 0.111664 0.312544 +vt 0.096001 0.312426 +vt 0.080324 0.312304 +vt 0.080371 0.333135 +vt 0.080270 0.291465 +vt 0.080210 0.270618 +vt 0.080142 0.249761 +vt 0.047888 0.061273 +vt 0.032202 0.061110 +vt 0.063566 0.061430 +vt 0.016509 0.060941 +vt 0.016627 0.081887 +vt 0.000922 0.081710 +vt 0.000808 0.060765 +vt 0.000687 0.039812 +vt 0.016384 0.039985 +vt 0.016253 0.019022 +vt 0.000559 0.018852 +vt 0.004382 0.003168 +vt 0.016114 -0.001951 +vt 0.048342 0.145014 +vt 0.032646 0.144848 +vt 0.064029 0.145174 +vt 0.016940 0.144676 +vt 0.001224 0.144497 +vt 0.001130 0.123576 +vt 0.016842 0.123755 +vt 0.016738 0.102825 +vt 0.001030 0.102647 +vt 0.111027 0.145619 +vt 0.095371 0.145476 +vt 0.079705 0.145328 +vt 0.079806 0.166236 +vt 0.079598 0.124408 +vt 0.079484 0.103477 +vt 0.079363 0.082535 +vt 0.422361 0.230779 +vt 0.406884 0.230753 +vt 0.437835 0.230798 +vt 0.391404 0.230721 +vt 0.391432 0.251549 +vt 0.375920 0.230683 +vt 0.391375 0.209873 +vt 0.391344 0.189004 +vt 0.422415 0.313978 +vt 0.406960 0.313953 +vt 0.437867 0.313996 +vt 0.391500 0.313923 +vt 0.376035 0.313888 +vt 0.391479 0.293149 +vt 0.391457 0.272358 +vt 0.468767 0.314016 +vt 0.484216 0.314023 +vt 0.453318 0.314009 +vt 0.453319 0.334764 +vt 0.453316 0.293237 +vt 0.453313 0.272448 +vt 0.453310 0.251639 +vt 0.298406 0.230402 +vt 0.282879 0.230328 +vt 0.313923 0.230470 +vt 0.267344 0.230249 +vt 0.267407 0.251084 +vt 0.251799 0.230165 +vt 0.267276 0.209397 +vt 0.267203 0.188528 +vt 0.267125 0.167640 +vt 0.298604 0.313631 +vt 0.283091 0.313565 +vt 0.314107 0.313693 +vt 0.267567 0.313494 +vt 0.267611 0.334268 +vt 0.267519 0.292705 +vt 0.267466 0.271903 +vt 0.360565 0.313847 +vt 0.345087 0.313800 +vt 0.329601 0.313749 +vt 0.329634 0.334513 +vt 0.329565 0.292970 +vt 0.329525 0.272174 +vt 0.329481 0.251362 +vt 0.297803 0.063051 +vt 0.282236 0.062985 +vt 0.313364 0.063111 +vt 0.266664 0.062913 +vt 0.266766 0.083898 +vt 0.251085 0.062835 +vt 0.266557 0.041908 +vt 0.266445 0.020882 +vt 0.266327 -0.000164 +vt 0.298138 0.146887 +vt 0.282594 0.146813 +vt 0.313676 0.146955 +vt 0.267043 0.146734 +vt 0.266955 0.125808 +vt 0.266863 0.104863 +vt 0.360250 0.147121 +vt 0.344731 0.147072 +vt 0.329206 0.147016 +vt 0.329268 0.167926 +vt 0.329140 0.126086 +vt 0.329071 0.105134 +vt 0.328998 0.084161 +vt 0.407000 0.562347 +vt 0.422437 0.562355 +vt 0.437870 0.562362 +vt 0.391549 0.583013 +vt 0.376110 0.562327 +vt 0.391566 0.541662 +vt 0.391558 0.562337 +vt 0.391574 0.520989 +vt 0.406954 0.645070 +vt 0.422398 0.645072 +vt 0.437839 0.645075 +vt 0.376049 0.645068 +vt 0.391504 0.645069 +vt 0.391522 0.624377 +vt 0.391537 0.603693 +vt 0.468715 0.645083 +vt 0.484152 0.645085 +vt 0.453270 0.665774 +vt 0.453278 0.645078 +vt 0.453284 0.624391 +vt 0.453290 0.603712 +vt 0.453295 0.583038 +vt 0.283238 0.562243 +vt 0.298742 0.562260 +vt 0.314235 0.562275 +vt 0.267706 0.582933 +vt 0.252193 0.562208 +vt 0.267722 0.562226 +vt 0.267737 0.541520 +vt 0.267751 0.520815 +vt 0.267759 0.500109 +vt 0.283141 0.645073 +vt 0.298650 0.645071 +vt 0.314149 0.645070 +vt 0.267619 0.645075 +vt 0.267654 0.624356 +vt 0.267683 0.603643 +vt 0.345116 0.645068 +vt 0.360586 0.645067 +vt 0.329605 0.665779 +vt 0.329637 0.645068 +vt 0.329665 0.624366 +vt 0.329687 0.603670 +vt 0.329705 0.582978 +vt 0.298730 0.396630 +vt 0.283225 0.396577 +vt 0.314224 0.396680 +vt 0.267708 0.396521 +vt 0.267730 0.417251 +vt 0.252180 0.396460 +vt 0.267681 0.375781 +vt 0.267649 0.355030 +vt 0.298777 0.479475 +vt 0.283274 0.479439 +vt 0.314268 0.479508 +vt 0.267760 0.479402 +vt 0.267756 0.458690 +vt 0.267746 0.437974 +vt 0.360680 0.479594 +vt 0.345219 0.479568 +vt 0.329748 0.479539 +vt 0.329747 0.500228 +vt 0.329745 0.458846 +vt 0.329737 0.438147 +vt 0.329725 0.417441 +vt 0.919364 0.562083 +vt 0.903649 0.562102 +vt 0.935094 0.562063 +vt 0.887948 0.562121 +vt 0.887967 0.582900 +vt 0.872262 0.562140 +vt 0.887932 0.541343 +vt 0.887915 0.520565 +vt 0.919485 0.645271 +vt 0.903771 0.645258 +vt 0.935213 0.645285 +vt 0.888071 0.645246 +vt 0.872384 0.645235 +vt 0.888028 0.624462 +vt 0.887993 0.603680 +vt 0.982478 0.645339 +vt 0.966710 0.645319 +vt 0.998260 0.645361 +vt 0.950955 0.645301 +vt 0.951003 0.666119 +vt 0.950914 0.624485 +vt 0.950882 0.603671 +vt 0.950856 0.582857 +vt 0.794046 0.562229 +vt 0.778446 0.562245 +vt 0.809661 0.562212 +vt 0.762859 0.562260 +vt 0.762874 0.582984 +vt 0.747286 0.562275 +vt 0.762846 0.541537 +vt 0.762834 0.520814 +vt 0.762831 0.500091 +vt 0.794161 0.645190 +vt 0.778557 0.645182 +vt 0.809778 0.645198 +vt 0.762967 0.645175 +vt 0.762928 0.624440 +vt 0.762897 0.603711 +vt 0.856712 0.645225 +vt 0.841053 0.645215 +vt 0.825409 0.645206 +vt 0.825459 0.665969 +vt 0.825366 0.624449 +vt 0.825332 0.603695 +vt 0.825307 0.582944 +vt 0.778514 0.396363 +vt 0.794112 0.396299 +vt 0.809724 0.396233 +vt 0.762894 0.417169 +vt 0.747358 0.396483 +vt 0.762929 0.396425 +vt 0.762971 0.375672 +vt 0.763021 0.354911 +vt 0.778420 0.479327 +vt 0.794018 0.479286 +vt 0.809631 0.479244 +vt 0.762835 0.479366 +vt 0.762847 0.458639 +vt 0.762867 0.437907 +vt 0.840899 0.479154 +vt 0.856554 0.479107 +vt 0.825255 0.499950 +vt 0.825258 0.479200 +vt 0.825269 0.458447 +vt 0.825287 0.437691 +vt 0.825314 0.416930 +vt 0.840988 0.396092 +vt 0.856641 0.396018 +vt 0.825349 0.396164 +vt 0.825392 0.375391 +vt 0.825442 0.354610 +vt 0.856590 0.562159 +vt 0.840933 0.562177 +vt 0.825290 0.562195 +vt 0.825275 0.541446 +vt 0.825261 0.520698 +vt 0.982371 0.562006 +vt 0.966597 0.562025 +vt 0.998160 0.561987 +vt 0.950838 0.562044 +vt 0.950821 0.541231 +vt 0.950803 0.520418 +vt 0.360650 0.396805 +vt 0.345183 0.396767 +vt 0.329708 0.396725 +vt 0.329688 0.376000 +vt 0.329663 0.355263 +vt 0.345190 0.562303 +vt 0.360654 0.562315 +vt 0.329718 0.562289 +vt 0.329730 0.541602 +vt 0.329741 0.520916 +vt 0.468729 0.562373 +vt 0.484157 0.562377 +vt 0.453304 0.541699 +vt 0.453300 0.562368 +vt 0.453308 0.521032 +vt 0.360020 0.063255 +vt 0.344472 0.063213 +vt 0.328920 0.063165 +vt 0.328839 0.042147 +vt 0.328754 0.021106 +vt 0.328664 0.000043 +vt 0.360431 0.230638 +vt 0.344935 0.230588 +vt 0.329433 0.230532 +vt 0.329382 0.209683 +vt 0.329327 0.188814 +vt 0.468778 0.230818 +vt 0.484249 0.230826 +vt 0.453307 0.230811 +vt 0.453303 0.209963 +vt 0.453298 0.189093 +vt 0.110552 0.061862 +vt 0.094898 0.061724 +vt 0.079236 0.061580 +vt 0.079102 0.040614 +vt 0.078962 0.019636 +vt 0.078815 -0.001354 +vt 0.111398 0.229172 +vt 0.095739 0.229036 +vt 0.080068 0.228895 +vt 0.079987 0.208019 +vt 0.079900 0.187133 +vt 0.236244 0.230075 +vt 0.220678 0.229980 +vt 0.205101 0.229880 +vt 0.205022 0.209023 +vt 0.204937 0.188150 +vt 0.344972 0.727963 +vt 0.360457 0.727953 +vt 0.329480 0.727974 +vt 0.329527 0.707230 +vt 0.329568 0.686499 +vt 0.344484 0.894521 +vt 0.360017 0.894509 +vt 0.328944 0.894536 +vt 0.329028 0.873647 +vt 0.329106 0.852779 +vt 0.468662 0.894500 +vt 0.484178 0.894500 +vt 0.453146 0.894494 +vt 0.453161 0.873596 +vt 0.453175 0.852723 +vt 0.095764 0.728347 +vt 0.111436 0.728309 +vt 0.080079 0.728388 +vt 0.080152 0.707572 +vt 0.080216 0.686761 +vt 0.094896 0.895137 +vt 0.110566 0.895073 +vt 0.079217 0.895206 +vt 0.079353 0.874320 +vt 0.079481 0.853444 +vt 0.219974 0.894725 +vt 0.235565 0.894689 +vt 0.204373 0.894765 +vt 0.204499 0.873881 +vt 0.204617 0.853014 +vt 0.111822 0.395775 +vt 0.096155 0.395684 +vt 0.080472 0.395589 +vt 0.080446 0.374777 +vt 0.080412 0.353960 +vt 0.096137 0.561994 +vt 0.111810 0.562017 +vt 0.080469 0.541177 +vt 0.080448 0.561970 +vt 0.080490 0.520383 +vt 0.221097 0.562170 +vt 0.236652 0.562189 +vt 0.205546 0.541420 +vt 0.205528 0.562150 +vt 0.205562 0.520691 +vt 0.856969 0.728359 +vt 0.841309 0.728326 +vt 0.825663 0.728296 +vt 0.825586 0.707512 +vt 0.825519 0.686737 +vt 0.857897 0.895056 +vt 0.842232 0.895004 +vt 0.826577 0.894955 +vt 0.826433 0.874077 +vt 0.826298 0.853214 +vt 0.983550 0.895585 +vt 0.967812 0.895507 +vt 0.999296 0.895668 +vt 0.952083 0.895432 +vt 0.951941 0.874551 +vt 0.951809 0.853678 +vt 0.607869 0.727990 +vt 0.592388 0.727978 +vt 0.576913 0.727967 +vt 0.576882 0.707232 +vt 0.576854 0.686510 +vt 0.608353 0.894527 +vt 0.592820 0.894515 +vt 0.577292 0.894506 +vt 0.577232 0.873614 +vt 0.577176 0.852746 +vt 0.732849 0.894713 +vt 0.717260 0.894681 +vt 0.701679 0.894652 +vt 0.701563 0.873770 +vt 0.701454 0.852907 +vt 0.842553 0.062370 +vt 0.858204 0.062262 +vt 0.826910 0.062472 +vt 0.827066 0.041500 +vt 0.827230 0.020512 +vt 0.827400 -0.000490 +vt 0.717621 0.063048 +vt 0.733211 0.062981 +vt 0.702037 0.063110 +vt 0.702165 0.042109 +vt 0.702300 0.021088 +vt 0.702440 0.000047 +vt 0.967976 0.061373 +vt 0.983687 0.061226 +vt 0.999404 0.061074 +vt 0.952273 0.061515 +vt 0.952423 0.040568 +vt 0.952581 0.019612 +vt 0.952746 -0.001354 +vt 0.716253 0.396591 +vt 0.731799 0.396539 +vt 0.700719 0.396641 +vt 0.700758 0.375906 +vt 0.700803 0.355160 +vt 0.732049 0.728136 +vt 0.716489 0.728114 +vt 0.700941 0.728093 +vt 0.700880 0.707341 +vt 0.700825 0.686600 +vt 0.982704 0.728688 +vt 0.966944 0.728638 +vt 0.998476 0.728741 +vt 0.951195 0.728592 +vt 0.951123 0.707764 +vt 0.951059 0.686940 +vt 0.236639 0.396397 +vt 0.221085 0.396330 +vt 0.205518 0.396260 +vt 0.205488 0.375501 +vt 0.205451 0.354733 +vt 0.220757 0.728100 +vt 0.236322 0.728077 +vt 0.205179 0.728124 +vt 0.205247 0.707352 +vt 0.205309 0.686590 +vt 0.468699 0.727940 +vt 0.484154 0.727942 +vt 0.453245 0.727936 +vt 0.453254 0.707201 +vt 0.453262 0.686482 +vt 0.731726 0.562288 +vt 0.716179 0.562301 +vt 0.700645 0.562313 +vt 0.700635 0.541611 +vt 0.700626 0.520910 +vt 0.235500 0.062751 +vt 0.219908 0.062661 +vt 0.204309 0.062565 +vt 0.204184 0.041573 +vt 0.204053 0.020563 +vt 0.203917 -0.000464 +vt 0.468795 0.063393 +vt 0.484332 0.063402 +vt 0.453259 0.063389 +vt 0.453249 0.042352 +vt 0.453239 0.021288 +vt 0.453226 0.000197 +vt 0.607680 0.562366 +vt 0.592220 0.562371 +vt 0.576767 0.562375 +vt 0.576764 0.541702 +vt 0.576761 0.521029 +vt 0.468755 0.396948 +vt 0.484189 0.396954 +vt 0.453321 0.396941 +vt 0.453321 0.376229 +vt 0.453320 0.355504 +vt 0.966597 0.395426 +vt 0.982359 0.395330 +vt 0.998134 0.395230 +vt 0.950848 0.395518 +vt 0.950882 0.374693 +vt 0.950923 0.353863 +vt 0.716749 0.230337 +vt 0.732309 0.230262 +vt 0.701198 0.230407 +vt 0.701284 0.209560 +vt 0.701376 0.188696 +vt 0.592589 0.230758 +vt 0.608082 0.230724 +vt 0.577101 0.230786 +vt 0.577149 0.209939 +vt 0.577199 0.189073 +vt 0.593106 0.063388 +vt 0.608654 0.063365 +vt 0.577562 0.063406 +vt 0.577633 0.042379 +vt 0.577707 0.021329 +vt 0.577785 0.000253 +vt 0.592283 0.396896 +vt 0.607746 0.396870 +vt 0.576827 0.396917 +vt 0.576850 0.376203 +vt 0.576877 0.355476 +vt 0.967054 0.228622 +vt 0.982792 0.228479 +vt 0.998541 0.228332 +vt 0.951326 0.228760 +vt 0.951419 0.207885 +vt 0.951519 0.187002 +vt 0.841540 0.229612 +vt 0.857189 0.229503 +vt 0.825902 0.229718 +vt 0.826003 0.208861 +vt 0.826112 0.187991 +vn 0.000000 1.000000 0.000000 +vn 0.000000 -1.000000 -0.000000 +vn 0.000000 -0.000000 1.000000 +vn 0.000000 0.000000 -1.000000 +vn -0.577400 0.577300 -0.577400 +vn -0.577400 0.577300 0.577400 +vn -0.577400 -0.577300 -0.577400 +vn -0.577400 -0.577300 0.577400 +vn -0.707100 0.000000 -0.707100 +vn -0.707100 -0.707100 -0.000000 +vn -0.707100 -0.000000 0.707100 +vn -0.707100 0.707100 0.000000 +vn 0.000000 -0.707100 0.707100 +vn 0.000000 0.707100 0.707100 +vn 0.000000 -0.707100 -0.707100 +vn 0.000000 0.707100 -0.707100 +vn -1.000000 -0.000000 0.000000 +vn 0.457200 0.888200 -0.045600 +vn 0.544700 -0.013600 -0.838500 +vn 0.393600 -0.919000 -0.021100 +vn 0.525500 0.001200 -0.850800 +vn 0.503500 -0.045300 -0.862800 +vn 0.426200 0.904600 0.008900 +vn 0.528800 -0.848700 0.001700 +vn 0.504300 -0.863500 -0.003500 +vn 0.479100 0.876800 -0.041200 +vn 0.521400 0.025600 0.852900 +vn 0.536900 0.843600 -0.005600 +vn 0.538000 0.842900 -0.004800 +vn 0.543700 -0.016500 -0.839100 +vn 0.386800 -0.921900 -0.022000 +vn 0.525600 0.023200 0.850400 +vn 0.517100 -0.855900 -0.002500 +vn 0.542200 -0.019400 -0.840000 +vn 0.380200 -0.924600 -0.022800 +vn 0.498400 -0.047000 -0.865600 +vn 0.472000 0.880600 -0.042800 +vn 0.449300 -0.893300 -0.012200 +vn 0.537700 0.843100 -0.003500 +vn 0.537600 0.843200 -0.008000 +vn 0.548100 -0.007400 0.836400 +vn 0.474400 0.042600 0.879300 +vn 0.529600 0.020700 0.848000 +vn 0.513300 -0.858200 -0.002700 +vn 0.540300 -0.022200 -0.841200 +vn 0.419600 0.906300 -0.050400 +vn 0.373600 -0.927300 -0.023600 +vn 0.493200 -0.048500 -0.868500 +vn 0.442300 -0.896700 -0.013400 +vn 0.462000 0.886900 0.001600 +vn 0.475900 -0.879400 -0.007600 +vn 0.546900 -0.008100 0.837200 +vn 0.475700 0.879600 -0.001200 +vn 0.435400 -0.900100 -0.014600 +vn 0.480100 0.041200 0.876200 +vn 0.412200 0.909700 -0.051000 +vn 0.545300 -0.008700 0.838200 +vn 0.503900 -0.018100 0.863500 +vn 0.485800 0.039600 0.873200 +vn 0.468900 0.883200 0.000100 +vn 0.469500 -0.882900 -0.008700 +vn 0.539500 -0.004200 -0.841900 +vn 0.482300 0.876000 -0.002500 +vn 0.474500 0.015500 -0.880100 +vn 0.428300 -0.903500 -0.015800 +vn 0.525500 0.850500 -0.023000 +vn 0.543400 -0.009400 0.839400 +vn 0.499100 -0.018900 0.866400 +vn 0.491400 0.037900 0.870100 +vn 0.465600 -0.054500 -0.883300 +vn 0.541400 -0.005200 -0.840700 +vn 0.477400 0.838400 -0.263200 +vn 0.479800 0.014200 -0.877200 +vn 0.521200 0.853000 -0.025700 +vn 0.543000 -0.006100 -0.839700 +vn 0.465400 -0.884300 0.037900 +vn 0.485100 0.012900 -0.874400 +vn 0.532800 0.232300 -0.813700 +vn 0.370500 0.928600 0.018500 +vn 0.364800 -0.929700 0.051700 +vn 0.544100 -0.005500 -0.839000 +vn 0.472400 -0.880600 0.035900 +vn 0.511500 0.859300 -0.007400 +vn 0.490300 0.011600 -0.871500 +vn 0.472900 -0.023100 0.880800 +vn 0.371500 -0.927000 0.051400 +vn 0.406600 -0.912300 0.048600 +vn 0.516300 0.856400 -0.007900 +vn 0.378200 -0.924300 0.051100 +vn 0.539600 0.012800 0.841800 +vn 0.536600 0.252100 0.805300 +vn 0.529300 -0.013100 0.848400 +vn 0.413900 -0.909100 0.047800 +vn 0.404700 0.914400 0.012900 +vn 0.385200 -0.921500 0.050600 +vn 0.542200 0.010000 0.840200 +vn 0.503900 -0.863500 0.023700 +vn 0.525600 -0.013800 0.850600 +vn 0.504900 0.007600 -0.863100 +vn 0.411800 0.911200 0.011600 +vn 0.521700 -0.014700 0.853000 +vn 0.390400 0.919200 -0.052100 +vn 0.513800 -0.857700 0.017900 +vn 0.509100 -0.860500 0.020800 +vn 0.525500 -0.035100 -0.850100 +vn 0.509400 0.006300 -0.860500 +vn 0.517600 -0.015500 0.855500 +vn 0.383400 0.922100 -0.052300 +vn 0.518000 -0.855300 0.014800 +vn 0.450900 -0.891600 0.041400 +vn 0.376500 0.924900 -0.052500 +vn 0.521600 -0.037400 -0.852400 +vn 0.549400 -0.001500 0.835500 +vn 0.507200 0.032300 0.861200 +vn 0.517400 -0.039500 -0.854800 +vn 0.505400 0.862300 -0.033200 +vn 0.528100 0.849100 -0.008500 +vn 0.545600 -0.006500 -0.838000 +vn 0.369800 0.927600 -0.052500 +vn 0.407300 -0.913100 -0.019100 +vn 0.458200 -0.888000 0.039700 +vn 0.527700 -0.849400 -0.002700 +vn 0.549700 -0.004400 0.835400 +vn 0.512200 0.030200 0.858400 +vn 0.513000 -0.041600 -0.857400 +vn 0.499300 0.865700 -0.035400 +vn 0.531100 0.847300 -0.008400 +vn 0.545400 -0.010600 -0.838100 +vn 0.492800 0.869300 -0.037500 +vn 0.400400 -0.916100 -0.020100 +vn 0.528900 0.000100 -0.848700 +vn 0.525800 -0.850600 -0.002500 +vn 0.533600 0.845700 -0.008100 +vn 0.529800 -0.848100 0.000000 +vn 0.449700 0.891900 -0.046800 +vn 0.462900 -0.886400 -0.009800 +vn 0.523400 -0.852100 -0.002400 +vn 0.433400 0.901200 0.007400 +vn 0.549500 -0.007300 0.835500 +vn 0.499300 -0.866400 -0.004100 +vn 0.486100 0.873000 -0.039400 +vn 0.534500 -0.245500 0.808700 +vn 0.532000 -0.001100 -0.846800 +vn 0.535500 0.844500 -0.007700 +vn 0.530200 -0.847900 -0.001700 +vn 0.442200 0.895600 -0.047900 +vn 0.456200 -0.889800 -0.011000 +vn 0.520500 -0.853900 -0.002400 +vn 0.440600 0.897700 0.006000 +vn 0.434600 0.899300 -0.048900 +vn 0.549000 -0.006800 0.835800 +vn 0.493900 -0.869500 -0.004800 +vn 0.468600 0.044000 0.882300 +vn 0.533300 0.018200 0.845800 +vn 0.447800 0.894100 0.004500 +vn 0.538100 -0.025000 -0.842500 +vn 0.488200 -0.872700 -0.005600 +vn 0.536500 0.843800 -0.011100 +vn 0.367200 -0.929800 -0.024300 +vn 0.427100 0.902800 -0.049700 +vn 0.534800 -0.002200 -0.845000 +vn 0.487900 -0.050000 -0.871500 +vn 0.531500 -0.259500 -0.806300 +vn 0.536600 0.015500 0.843700 +vn 0.454900 0.890500 0.003000 +vn 0.535400 -0.027700 -0.844100 +vn 0.482200 -0.876100 -0.006600 +vn 0.534700 0.844900 -0.014200 +vn 0.473600 -0.843400 0.253900 +vn 0.532300 0.846400 -0.017200 +vn 0.537300 -0.003200 -0.843400 +vn 0.469000 0.016700 -0.883000 +vn 0.421300 -0.906800 -0.016900 +vn 0.482500 -0.051300 -0.874400 +vn 0.541200 -0.010100 0.840900 +vn 0.496800 0.036200 0.867100 +vn 0.476900 -0.052500 -0.877400 +vn 0.488700 0.872400 -0.003800 +vn 0.529200 0.848300 -0.020200 +vn 0.467500 -0.853100 -0.231700 +vn 0.414300 -0.910000 -0.018000 +vn 0.494000 -0.019800 0.869200 +vn 0.538600 -0.010800 0.842500 +vn 0.502100 0.034300 0.864100 +vn 0.471300 -0.053500 -0.880300 +vn 0.494900 0.868900 -0.004900 +vn 0.358300 -0.932200 0.051900 +vn 0.488900 -0.020600 0.872100 +vn 0.500800 0.865600 -0.005900 +vn 0.545000 -0.004800 -0.838500 +vn 0.495300 0.010300 -0.868700 +vn 0.483600 -0.021500 0.875000 +vn 0.377100 0.926000 0.017500 +vn 0.535800 -0.011500 0.844300 +vn 0.479300 -0.877000 0.033700 +vn 0.506300 0.862300 -0.006700 +vn 0.545500 -0.005700 -0.838100 +vn 0.500200 0.008900 -0.865900 +vn 0.478300 -0.022300 0.877900 +vn 0.383900 0.923200 0.016500 +vn 0.485900 -0.873400 0.031400 +vn 0.390700 0.920400 0.015300 +vn 0.532700 -0.012300 0.846200 +vn 0.404800 0.912900 -0.051500 +vn 0.392200 -0.918500 0.050100 +vn 0.492200 -0.870000 0.029000 +vn 0.421300 -0.905700 0.046800 +vn 0.397700 0.917400 0.014200 +vn 0.532500 -0.030200 -0.845900 +vn 0.544500 0.007200 0.838700 +vn 0.397600 0.916100 -0.051900 +vn 0.399300 -0.915500 0.049400 +vn 0.498200 -0.866600 0.026400 +vn 0.428700 -0.902300 0.045600 +vn 0.529100 -0.032700 -0.847900 +vn 0.546400 0.004300 0.837500 +vn 0.516400 0.855900 -0.028400 +vn 0.513200 -0.016300 0.858100 +vn 0.436100 -0.898800 0.044400 +vn 0.520700 0.853700 -0.008300 +vn 0.547800 0.001500 0.836600 +vn 0.513800 0.005000 -0.857900 +vn 0.529900 -0.848100 -0.003300 +vn 0.521600 -0.853100 0.011600 +vn 0.511100 0.859000 -0.030800 +vn 0.443500 -0.895200 0.042900 +vn 0.508700 -0.017200 0.860800 +vn 0.524600 0.851300 -0.008500 +vn 0.548800 0.000000 0.835900 +vn 0.363200 0.930200 -0.052400 +vn 0.517900 0.003700 -0.855400 +vn 0.529100 -0.848600 -0.003000 +vn 0.464600 0.884400 -0.044300 +vn 0.524600 -0.851300 0.008400 +vn 0.521800 0.002400 -0.853000 +vn 0.508300 -0.043500 -0.860100 +vn 0.419000 0.907900 0.010300 +vn 0.527000 -0.849800 0.005000 +vn 0.509000 -0.860800 -0.003000 +vn 0.473900 0.849400 0.232200 +vn 0.516900 0.027900 0.855600 +vn 0.858500 -0.053300 -0.510000 +vn 0.841800 0.517000 -0.155200 +vn 0.885600 0.460900 -0.058300 +vn 0.836700 -0.531000 0.133800 +vn 0.847600 0.070400 -0.526000 +vn 0.888100 0.459000 0.024300 +vn 0.852600 -0.512400 -0.102400 +vn 0.863400 -0.059600 0.501100 +vn 0.857500 -0.059600 -0.511000 +vn 0.877400 -0.479300 0.022200 +vn 0.861600 0.006900 -0.507500 +vn 0.804900 -0.578100 -0.133900 +vn 0.849500 0.065800 -0.523500 +vn 0.867800 -0.024900 0.496300 +vn 0.869000 -0.489400 0.072700 +vn 0.862100 -0.064900 0.502500 +vn 0.867900 0.001300 0.496700 +vn 0.878100 -0.478400 0.013000 +vn 0.862000 0.003300 -0.507000 +vn 0.799600 -0.585100 -0.135400 +vn 0.860100 0.491800 -0.135400 +vn 0.867400 -0.031000 0.496700 +vn 0.870900 -0.487100 0.065100 +vn 0.889600 0.456700 -0.010600 +vn 0.868100 -0.006000 0.496400 +vn 0.840500 -0.526000 0.130000 +vn 0.888900 0.457900 0.016500 +vn 0.867100 -0.492200 -0.077300 +vn 0.856800 0.496300 -0.140100 +vn 0.861300 -0.026500 -0.507300 +vn 0.815700 -0.559000 0.148400 +vn 0.889200 0.457100 -0.020400 +vn 0.866300 0.483600 -0.124900 +vn 0.844100 -0.521200 0.125900 +vn 0.889300 0.457200 0.008700 +vn 0.864600 -0.495600 -0.082900 +vn 0.872600 -0.485100 0.057000 +vn 0.860800 -0.033400 -0.507800 +vn 0.820200 -0.553100 0.146100 +vn 0.859100 0.029800 -0.510900 +vn 0.863300 0.487600 -0.130400 +vn 0.794200 -0.592100 -0.136600 +vn 0.866900 -0.036900 0.497200 +vn 0.859700 -0.501000 0.100000 +vn 0.874100 -0.483300 0.048700 +vn 0.866000 0.025200 0.499400 +vn 0.824500 -0.551700 -0.126000 +vn 0.859900 0.024200 -0.509800 +vn 0.834500 -0.117300 0.538400 +vn 0.788700 -0.599200 -0.137600 +vn 0.799400 0.575800 -0.171200 +vn 0.866200 -0.042800 0.497900 +vn 0.862300 -0.497700 0.093700 +vn 0.824600 -0.547300 0.143500 +vn 0.866600 0.018100 0.498600 +vn 0.819800 -0.558100 -0.128300 +vn 0.884500 0.464100 0.046700 +vn 0.848800 -0.231500 0.475300 +vn 0.861900 -0.499300 -0.088200 +vn 0.836600 0.462100 -0.294100 +vn 0.860200 -0.040100 -0.508400 +vn 0.796500 -0.584400 0.155400 +vn 0.828800 -0.541700 0.140500 +vn 0.876700 0.470800 -0.099200 +vn 0.874700 -0.481800 -0.052300 +vn 0.886000 0.462100 0.039400 +vn 0.828500 -0.129400 -0.544900 +vn 0.859000 -0.503400 -0.093200 +vn 0.859400 -0.046800 -0.509200 +vn 0.843400 0.079000 -0.531400 +vn 0.801500 -0.577800 0.154000 +vn 0.815000 -0.564600 -0.130400 +vn 0.874300 0.473600 -0.106200 +vn 0.873100 -0.483900 -0.058900 +vn 0.868100 -0.012700 0.496200 +vn 0.864700 -0.494600 0.087100 +vn 0.843300 -0.236600 -0.482500 +vn 0.867100 0.010900 0.498000 +vn 0.845500 0.074800 -0.528600 +vn 0.841600 -0.527900 -0.114100 +vn 0.810000 -0.571300 -0.132300 +vn 0.845200 -0.104800 0.524100 +vn 0.868000 -0.018900 0.496200 +vn 0.819700 0.548000 -0.166800 +vn 0.867000 -0.491900 0.080100 +vn 0.881000 0.469300 0.060500 +vn 0.867600 0.006100 0.497200 +vn 0.849300 0.098200 0.518600 +vn 0.837600 -0.533600 -0.117500 +vn 0.871300 -0.486300 -0.065300 +vn 0.842700 -0.108200 0.527400 +vn 0.862000 -0.012600 -0.506700 +vn 0.814800 0.554700 -0.168300 +vn 0.806400 -0.571400 0.152400 +vn 0.882900 0.466500 0.053700 +vn 0.851400 0.093200 0.516200 +vn 0.871800 0.476600 -0.112900 +vn 0.878600 -0.477000 -0.023900 +vn 0.869300 -0.489100 -0.071400 +vn 0.838700 -0.116000 -0.532200 +vn 0.861700 -0.019600 -0.507000 +vn 0.833700 0.094200 -0.544200 +vn 0.858500 0.501900 0.105100 +vn 0.811100 -0.565200 0.150600 +vn 0.824700 0.549800 0.132300 +vn 0.869200 0.480000 -0.119100 +vn 0.878000 -0.477700 -0.031200 +vn 0.853900 -0.508300 0.111400 +vn 0.836300 -0.119700 -0.535100 +vn 0.836300 0.090700 -0.540800 +vn 0.864400 0.039100 0.501300 +vn 0.862000 0.496900 0.100600 +vn 0.833400 -0.539400 -0.120600 +vn 0.829500 0.543200 0.129800 +vn 0.840100 -0.111400 0.530900 +vn 0.809900 0.561600 -0.169500 +vn 0.856900 -0.504500 0.105900 +vn 0.871300 0.483300 0.085100 +vn 0.840300 0.115700 0.529700 +vn 0.865300 0.032200 0.500300 +vn 0.862300 0.052400 0.503700 +vn 0.829000 -0.545500 -0.123400 +vn 0.847100 -0.098700 -0.522200 +vn 0.837300 -0.114500 0.534600 +vn 0.804700 0.568600 -0.170500 +vn 0.831500 -0.480000 0.279600 +vn 0.874000 0.479300 0.079400 +vn 0.842700 0.111700 0.526700 +vn 0.880800 0.466000 -0.083900 +vn 0.863400 0.045800 0.502400 +vn 0.877100 -0.478700 -0.038400 +vn 0.845200 -0.103300 -0.524400 +vn 0.833800 -0.123200 -0.538200 +vn 0.838800 0.087000 -0.537500 +vn 0.791400 -0.591000 0.156500 +vn 0.842900 0.524400 0.120800 +vn 0.804400 0.577400 0.140000 +vn 0.878800 0.468300 -0.091700 +vn 0.857000 0.040700 -0.513700 +vn 0.876000 -0.480100 -0.045500 +vn 0.854000 -0.089000 0.512600 +vn 0.831200 -0.126400 -0.541400 +vn 0.841100 0.083100 -0.534400 +vn 0.849100 -0.517300 -0.106600 +vn 0.847000 0.518500 0.117300 +vn 0.809700 0.570300 0.138400 +vn 0.849900 -0.097300 0.518000 +vn 0.858100 0.035300 -0.512200 +vn 0.829000 0.535000 -0.163100 +vn 0.852000 -0.093200 0.515200 +vn 0.876600 0.475600 0.073400 +vn 0.845000 0.107400 0.523800 +vn 0.845500 -0.522500 -0.110500 +vn 0.856700 0.077000 0.510000 +vn 0.853700 -0.077600 -0.514900 +vn 0.847600 -0.101100 0.520900 +vn 0.837700 0.522800 -0.158100 +vn 0.824400 0.541400 -0.165100 +vn 0.884200 0.462300 -0.067100 +vn 0.878900 0.472300 0.067100 +vn 0.847200 0.102900 0.521200 +vn 0.879100 -0.476600 -0.009000 +vn 0.858300 0.071100 0.508200 +vn 0.852300 -0.083200 -0.516500 +vn 0.843100 -0.107800 -0.526800 +vn 0.833400 0.528800 -0.160700 +vn 0.847700 0.211400 -0.486500 +vn 0.882600 0.464100 -0.075700 +vn 0.851000 0.512700 0.113500 +vn 0.814800 0.563400 0.136600 +vn 0.879000 -0.476600 -0.016500 +vn 0.851200 0.061100 -0.521200 +vn 0.860800 -0.070100 0.504100 +vn 0.840900 -0.112000 -0.529400 +vn 0.878600 -0.477500 0.006300 +vn 0.831000 0.097500 -0.547700 +vn 0.862200 -0.000300 -0.506600 +vn 0.854800 0.507200 0.109500 +vn 0.819800 0.556600 0.134600 +vn 0.852900 0.056200 -0.519100 +vn 0.859300 -0.075100 0.506000 +vn 0.865300 0.492100 0.095700 +vn 0.879000 -0.476900 -0.000500 +vn 0.852600 0.223000 0.472700 +vn 0.862200 -0.006200 -0.506600 +vn 0.859700 0.065100 0.506600 +vn 0.850600 -0.088600 -0.518200 +vn 0.853300 0.501100 -0.144400 +vn 0.888600 0.457800 -0.030100 +vn 0.868400 0.487500 0.090500 +vn 0.837800 0.119500 0.532800 +vn 0.847500 -0.516700 0.121400 +vn 0.861100 0.058800 0.505100 +vn 0.889700 0.456600 0.003500 +vn 0.848900 -0.093700 -0.520100 +vn 0.849600 0.506100 -0.148300 +vn 0.834100 0.536800 0.127000 +vn 0.887800 0.458600 -0.039700 +vn 0.839700 0.470300 0.271600 +vn 0.850800 -0.512400 0.116600 +vn 0.854400 0.051200 -0.517100 +vn 0.889800 0.456400 -0.001600 +vn 0.857600 -0.079900 0.508000 +vn 0.875400 -0.481800 0.040100 +vn 0.838600 0.530500 0.124000 +vn 0.860600 0.018500 -0.508900 +vn 0.799000 0.584500 0.141400 +vn 0.783100 -0.606300 -0.138400 +vn 0.855800 0.046000 -0.515300 +vn 0.865400 -0.048500 0.498700 +vn 0.855900 -0.084500 0.510200 +vn 0.876500 -0.480400 0.031300 +vn 0.853300 0.088000 0.514000 +vn 0.861200 0.012700 -0.508100 +vn 0.827000 -0.491500 -0.272800 +vn 0.856400 -0.065800 -0.512200 +vn 0.864400 -0.054100 0.499800 +vn 0.845800 0.511400 -0.151900 +vn 0.886800 0.459600 -0.049100 +vn 0.832800 -0.536200 0.137300 +vn 0.855000 0.082600 0.511900 +vn 0.887200 0.460400 0.032000 +vn 0.855900 -0.507800 -0.097900 +vn 0.855100 -0.071800 -0.513500 +vn 0.002000 0.998200 0.060000 +vn 0.000000 -0.997200 0.075300 +vn 0.000000 0.059300 0.998200 +vn 0.000500 0.996700 -0.081600 +vn 0.000000 -0.999800 -0.020200 +vn 0.000000 -0.997900 -0.065200 +vn 0.000000 -0.062300 -0.998100 +vn 0.000000 0.064500 -0.997900 +vn 0.000000 -0.007300 -1.000000 +vn 0.000000 0.996500 0.083300 +vn 0.000000 -0.997000 0.076800 +vn 0.000000 0.996900 0.078100 +vn 0.000200 0.996600 -0.082500 +vn 0.000000 -0.999600 -0.027900 +vn 0.000000 -0.996600 0.082100 +vn 0.000000 -0.063300 -0.998000 +vn 0.000000 0.063900 -0.998000 +vn 0.000000 0.034200 0.999400 +vn 0.000000 0.996600 0.082700 +vn 0.000000 -0.996500 -0.083600 +vn 0.000000 0.996800 0.079400 +vn 0.000000 -0.064000 0.997900 +vn 0.000000 0.997300 -0.073700 +vn 0.000000 -0.996700 0.080600 +vn 0.000000 0.064400 0.997900 +vn 0.000000 0.030100 0.999500 +vn 0.000000 0.041600 0.999100 +vn 0.000000 -0.996600 -0.083000 +vn 0.000000 -0.055800 -0.998400 +vn 0.000000 -0.064600 0.997900 +vn 0.000000 0.997400 -0.072000 +vn 0.000000 -0.926600 0.376000 +vn 0.000100 0.997100 0.075600 +vn 0.000000 0.063900 0.998000 +vn 0.002700 0.997700 -0.067700 +vn 0.000000 0.038000 0.999300 +vn 0.000000 -0.999400 -0.035300 +vn 0.000000 -0.057800 -0.998300 +vn 0.000000 -0.064100 -0.997900 +vn 0.000000 0.063100 -0.998000 +vn 0.000000 -0.997500 0.070300 +vn 0.000000 0.996600 0.082500 +vn 0.000000 0.997400 0.071900 +vn 0.002100 0.997400 -0.072700 +vn 0.000000 0.041700 -0.999100 +vn 0.000000 -0.999100 -0.042300 +vn 0.000000 -0.055700 0.998400 +vn 0.000000 -0.064700 -0.997900 +vn 0.000000 0.062100 -0.998100 +vn 0.000000 -0.996500 -0.083200 +vn 0.000000 0.996500 0.083100 +vn 0.000000 0.997300 0.073500 +vn 0.000000 -0.059500 0.998200 +vn 0.000000 0.038100 -0.999300 +vn 0.000000 0.996800 -0.079600 +vn 0.000000 -0.057700 0.998300 +vn 0.000500 0.997400 0.072600 +vn 0.000000 0.063100 0.998000 +vn 0.000000 -0.996500 -0.083900 +vn 0.000000 0.053400 0.998600 +vn 0.000000 -0.045100 -0.999000 +vn 0.000000 -0.061000 0.998100 +vn 0.000000 0.996600 -0.081800 +vn 0.000000 0.996900 -0.078300 +vn 0.003900 0.998500 -0.055000 +vn 0.000900 0.997600 0.069000 +vn 0.000000 0.062100 0.998100 +vn 0.000000 -1.000000 -0.004100 +vn 0.000000 0.050800 0.998700 +vn 0.000000 -0.048200 -0.998800 +vn 0.000000 -0.059600 -0.998200 +vn 0.000000 0.996700 -0.080800 +vn 0.000000 0.352600 -0.935800 +vn 0.000000 0.996500 0.083500 +vn 0.003300 0.998100 -0.061800 +vn 0.000000 0.997200 0.075100 +vn 0.000000 -0.999900 -0.012200 +vn 0.000000 0.053500 -0.998600 +vn 0.000000 -0.045000 0.999000 +vn 0.000000 -0.061100 -0.998100 +vn 0.000000 0.064900 -0.997900 +vn 0.000000 -0.999900 0.012300 +vn 0.000000 0.996500 0.083600 +vn 0.000000 0.007300 -1.000000 +vn 0.000000 0.997100 0.076700 +vn 0.000000 0.050900 -0.998700 +vn 0.000000 0.996700 0.081600 +vn 0.000000 -0.048100 0.998800 +vn 0.000000 0.352600 0.935800 +vn 0.000000 -1.000000 0.004100 +vn 0.000000 0.048000 0.998800 +vn 0.000000 0.002400 -1.000000 +vn 0.000000 -0.051000 -0.998700 +vn 0.000000 0.996500 -0.083700 +vn 0.000000 0.996800 0.080100 +vn 0.005400 0.999800 -0.021200 +vn 0.000000 0.064800 0.997900 +vn 0.000000 -0.996500 0.083700 +vn 0.005300 0.999900 0.012200 +vn 0.000000 0.045000 0.999000 +vn 0.000000 -0.053600 -0.998600 +vn 0.000000 0.996700 0.080600 +vn 0.005200 0.999500 -0.030400 +vn 0.000000 -0.996500 0.083100 +vn 0.000000 0.926600 0.375900 +vn 0.005400 1.000000 0.005100 +vn 0.000000 0.048100 -0.998800 +vn 0.000000 -0.050900 0.998700 +vn 0.000000 -0.999100 0.042400 +vn 0.000000 0.025900 -0.999700 +vn 0.000000 0.996700 0.081700 +vn 0.000000 -0.997500 -0.070400 +vn 0.000000 0.997500 0.070200 +vn 0.000000 -0.030100 0.999500 +vn 0.000000 0.045000 -0.999000 +vn 0.000000 -0.053500 0.998600 +vn 0.000000 -0.999400 0.035400 +vn 0.000000 0.057600 0.998300 +vn 0.000000 0.021500 -0.999800 +vn 0.000000 -0.926600 -0.376100 +vn 0.000000 -0.038200 -0.999300 +vn 0.000000 -0.034200 0.999400 +vn 0.000000 0.996500 -0.083300 +vn 0.004800 0.999200 -0.039200 +vn 0.000000 -0.996600 0.082800 +vn 0.000000 0.055600 0.998500 +vn 0.003900 0.999100 0.042200 +vn 0.000000 -0.996700 -0.080700 +vn 0.000000 -0.041800 -0.999100 +vn 0.000000 -0.030200 -0.999500 +vn 0.000000 0.996600 -0.082700 +vn 0.004400 0.998900 -0.047400 +vn 0.000000 -0.996500 0.083500 +vn 0.000000 0.057700 -0.998300 +vn 0.004400 0.999400 0.035300 +vn 0.000000 -0.996600 -0.082200 +vn 0.000000 -0.038100 0.999300 +vn 0.000000 -0.034300 -0.999400 +vn 0.000000 -0.999600 0.028000 +vn 0.000000 0.016800 -0.999900 +vn 0.000000 -0.997000 -0.077000 +vn 0.000000 0.055700 -0.998400 +vn 0.000000 -0.012100 0.999900 +vn 0.000000 -0.997900 0.065200 +vn 0.000000 -0.041700 0.999100 +vn 0.000000 0.007300 1.000000 +vn 0.000000 -0.999800 0.020300 +vn 0.000000 0.012100 -0.999900 +vn 0.000000 -0.997200 -0.075400 +vn 0.000000 0.996600 -0.082800 +vn 0.000000 -0.016800 0.999900 +vn 0.000000 -0.998200 0.060300 +vn 0.005500 1.000000 -0.003700 +vn 0.000000 0.002400 1.000000 +vn 0.000000 -0.996500 0.083900 +vn 0.004800 0.999600 0.027900 +vn 0.000000 -0.997600 -0.069400 +vn 0.000000 0.996500 -0.083400 +vn 0.000000 -0.012200 -0.999900 +vn 0.000000 -0.996900 0.078300 +vn 0.005500 0.999900 -0.011700 +vn 0.000000 0.996600 -0.082300 +vn 0.000000 -0.996500 0.084000 +vn 0.005100 0.999800 0.020200 +vn 0.000000 -0.997300 -0.073100 +vn 0.000000 -0.998500 0.054900 +vn 0.000000 -0.016900 -0.999900 +vn 0.000000 -0.996800 0.079700 +vn 0.000000 0.034300 -0.999400 +vn 0.000000 -0.997300 -0.073800 +vn 0.000000 -0.021400 0.999800 +vn 0.000000 -0.996900 0.078600 +vn 0.000000 -0.998800 0.048900 +vn 0.000000 0.025900 0.999700 +vn 0.000000 -0.996600 -0.082100 +vn 0.000000 0.030200 -0.999500 +vn 0.000000 -0.997400 -0.072100 +vn 0.000000 -0.065000 0.997900 +vn 0.000000 -0.025900 0.999700 +vn 0.000000 0.997500 -0.070400 +vn 0.000000 -0.997100 0.076100 +vn 0.000000 -0.996700 0.080900 +vn 0.000000 0.021400 0.999800 +vn 0.002700 0.998500 0.054600 +vn 0.000000 -0.996700 -0.081000 +vn 0.000000 -0.997100 -0.076200 +vn 0.000000 -0.352700 0.935700 +vn 0.000000 -0.021500 -0.999800 +vn 0.000000 0.926600 -0.376000 +vn 0.000000 -0.997400 0.072000 +vn 0.000000 -0.996600 0.081900 +vn 0.001500 0.997100 -0.076700 +vn 0.003300 0.998800 0.048700 +vn 0.000000 -0.998800 -0.048900 +vn 0.000000 -0.996900 -0.078700 +vn 0.000000 -0.065000 -0.997900 +vn 0.000000 -0.026000 -0.999700 +vn 0.000000 0.060900 -0.998100 +vn 0.000000 -0.997300 0.073700 +vn 0.000000 -0.996800 -0.079800 +vn 0.000900 0.996800 -0.079700 +vn 0.000000 -0.002400 1.000000 +vn 0.000000 -0.998500 -0.054900 +vn 0.000000 -0.352700 -0.935700 +vn 0.000000 -0.997300 0.073000 +vn 0.000000 0.059400 -0.998200 +vn 0.000000 0.016800 0.999900 +vn 0.000000 -0.996500 -0.084100 +vn 0.000000 -0.996900 -0.078400 +vn 0.000000 -0.062200 0.998100 +vn 0.000000 0.997000 -0.076800 +vn 0.000000 -0.007300 1.000000 +vn 0.001400 0.997900 0.064800 +vn 0.000000 -0.997600 0.069400 +vn 0.000000 0.060800 0.998100 +vn 0.000000 0.012100 0.999900 +vn 0.000000 -0.996500 -0.084000 +vn 0.000000 -0.998200 -0.060300 +vn 0.000000 -0.063200 0.998000 +vn 0.000000 0.997200 -0.075300 +vn 0.000000 -0.002500 -1.000000 +vn -0.999600 0.028800 0.004100 +vn 0.995600 -0.077600 0.052500 +vn 0.999500 0.033100 0.000100 +vn -0.997200 0.074900 -0.008900 +vn 0.995300 -0.094000 -0.024500 +vn -0.990500 0.098700 0.095600 +vn 0.998500 0.051800 -0.016900 +vn -0.997900 0.061600 0.018300 +vn -0.999700 0.023700 0.004600 +vn 0.995100 -0.080000 0.058500 +vn 0.984600 -0.117100 -0.129800 +vn -1.000000 0.000000 0.004800 +vn 0.995100 -0.075900 -0.063800 +vn -0.991300 0.096000 0.090500 +vn 0.998200 0.056900 -0.019000 +vn -0.998300 0.056600 0.016900 +vn -0.999500 0.030300 0.012000 +vn 0.994000 -0.108000 0.018600 +vn 0.985500 -0.113700 -0.126200 +vn -1.000000 -0.002600 0.004500 +vn 0.995600 -0.073900 -0.058100 +vn -0.999900 0.008400 0.010900 +vn 0.988300 -0.109700 0.105600 +vn -0.998300 0.058700 -0.001900 +vn -0.999600 0.024900 0.011400 +vn 0.994400 -0.104700 0.016400 +vn 0.999600 0.029000 -0.006300 +vn -0.996200 0.077500 0.040100 +vn 0.999800 0.019500 -0.007400 +vn -0.999900 0.002800 0.011100 +vn 0.987400 -0.113600 0.110000 +vn -0.998500 0.053900 -0.000600 +vn -0.997000 0.075800 -0.015100 +vn 0.992900 -0.113000 -0.035900 +vn 0.999400 0.034200 -0.004900 +vn -0.996500 0.076300 0.034100 +vn 0.999600 0.025100 -0.008600 +vn -0.998800 0.049000 0.000600 +vn 0.994500 -0.082500 0.064400 +vn -0.977600 0.156100 -0.141300 +vn -0.996800 0.077000 -0.021300 +vn 0.993400 -0.109500 -0.033500 +vn 0.999500 0.030500 -0.010000 +vn -0.996400 0.080600 0.025100 +vn 0.999800 -0.018500 -0.011700 +vn -0.999000 0.044100 0.001700 +vn 0.993900 -0.085300 0.070300 +vn -0.993100 0.082000 -0.084300 +vn -1.000000 -0.007900 0.003800 +vn 0.992700 -0.085400 -0.085600 +vn 0.999300 0.035900 -0.011500 +vn -0.996800 0.076000 0.023200 +vn 0.999800 -0.013200 -0.011800 +vn -0.998600 0.051500 0.015600 +vn 0.994800 -0.101100 0.014100 +vn -0.994000 -0.097600 0.048600 +vn -0.999900 -0.013100 0.003000 +vn 0.993300 -0.082800 -0.080300 +vn 0.991700 -0.095000 0.086300 +vn -0.997000 0.076900 -0.008500 +vn 0.999800 -0.019500 -0.004300 +vn -0.998800 0.046300 0.014400 +vn 0.995200 -0.097500 0.012000 +vn -0.998800 -0.047800 0.012700 +vn -0.996800 0.075300 0.028100 +vn 1.000000 0.000000 -0.004500 +vn 0.990900 -0.098600 0.091400 +vn -0.999000 -0.041800 0.014700 +vn -0.997300 0.072500 -0.006700 +vn 0.999900 -0.013900 -0.004200 +vn -0.997300 0.073800 0.003300 +vn 0.993900 -0.105800 -0.031200 +vn -0.995200 -0.093200 -0.031000 +vn 1.000000 0.002900 -0.004800 +vn -0.997000 0.074600 0.022000 +vn 0.996500 -0.073300 0.040400 +vn -0.999100 -0.041500 0.008900 +vn -0.981600 0.141100 -0.128700 +vn 0.997200 -0.069800 0.028000 +vn 0.994400 -0.102000 -0.029000 +vn -0.997300 0.073900 0.000300 +vn -0.998900 -0.045900 0.003100 +vn 0.999200 -0.039200 -0.009400 +vn -0.997200 0.071300 0.021400 +vn 0.996100 -0.075400 0.046500 +vn -0.992400 -0.073500 0.098800 +vn -0.980600 0.145000 -0.132100 +vn 0.996900 -0.071400 0.034200 +vn 0.993900 -0.080400 -0.074900 +vn -1.000000 0.008000 0.005100 +vn -0.981900 0.132100 0.135600 +vn 0.999400 -0.034100 -0.010200 +vn -0.997600 0.066500 0.019800 +vn 0.997600 -0.068500 -0.010100 +vn -0.993000 -0.070400 0.094400 +vn -0.996000 -0.080500 0.037700 +vn 0.999800 0.018600 -0.008800 +vn 0.994500 -0.078100 -0.069400 +vn -1.000000 0.002700 0.004900 +vn -0.982800 0.128700 0.132400 +vn 0.999100 -0.041200 -0.006700 +vn -0.997700 0.068000 -0.005000 +vn 0.993600 -0.111300 0.020900 +vn -0.983300 -0.123000 -0.134000 +vn -0.995600 -0.085000 0.040300 +vn 0.999700 0.023800 -0.007600 +vn 0.999900 0.008400 -0.005500 +vn -0.995400 0.080500 0.051900 +vn -0.998300 -0.045100 0.037900 +vn 0.999300 -0.035800 -0.005900 +vn -0.998000 0.063400 -0.003400 +vn 0.997500 -0.071100 -0.005400 +vn -0.995400 -0.052700 -0.080100 +vn -0.996800 -0.076800 -0.020500 +vn 0.997700 -0.065400 -0.016000 +vn 0.999900 0.014000 -0.006400 +vn -0.995800 0.078900 0.046000 +vn -0.998500 -0.043900 0.032200 +vn 0.997900 -0.065400 0.003000 +vn -0.979600 0.148700 -0.135300 +vn 0.992500 -0.116400 -0.038200 +vn -0.995400 -0.065300 -0.070300 +vn -0.996400 -0.081100 -0.023000 +vn 0.997800 -0.065100 -0.009600 +vn 0.999500 -0.029000 -0.010900 +vn -0.995600 0.089400 0.029100 +vn -0.989600 -0.086500 0.114900 +vn 0.997800 -0.066100 0.009300 +vn -0.978600 0.152400 -0.138400 +vn 0.991200 -0.090800 -0.095900 +vn -0.994800 -0.068400 -0.075400 +vn -0.978500 0.145000 0.146900 +vn 0.998000 -0.061900 -0.011500 +vn 0.999700 -0.023800 -0.011400 +vn -0.996000 0.085000 0.027000 +vn -0.990300 -0.083200 0.111100 +vn 0.999900 0.000000 -0.011500 +vn -0.995100 -0.089300 0.043000 +vn 0.992000 -0.088000 -0.090800 +vn -0.996900 -0.051900 0.059900 +vn -0.979300 0.141900 0.144300 +vn 0.998300 -0.056800 -0.010100 +vn 0.999500 -0.030400 -0.005200 +vn -0.996300 0.085300 -0.012300 +vn -0.986600 -0.108400 -0.121800 +vn 0.999900 0.002700 -0.011300 +vn -0.994600 -0.093500 0.045800 +vn 1.000000 -0.008300 -0.004200 +vn -0.997300 -0.049900 0.054500 +vn -0.998700 -0.043000 0.026400 +vn 0.998200 -0.058900 -0.004800 +vn 0.999700 -0.025000 -0.004700 +vn -0.996600 0.081100 -0.010400 +vn -0.985800 -0.112100 -0.125100 +vn 0.996800 -0.068900 -0.040500 +vn -0.996000 -0.085300 -0.025700 +vn 1.000000 -0.002800 -0.004300 +vn -0.986700 -0.099900 0.128400 +vn -0.998900 -0.042200 0.020600 +vn 0.998500 -0.054100 -0.006100 +vn 0.997600 -0.067100 0.015500 +vn -0.983600 0.133400 -0.121400 +vn -0.997300 -0.054200 -0.049000 +vn 0.997100 -0.067700 -0.034500 +vn -0.995600 -0.089300 -0.028300 +vn 0.998800 -0.049200 -0.007400 +vn -0.987400 -0.096600 0.125300 +vn -0.991000 -0.079900 0.107100 +vn 0.978800 -0.147900 0.142000 +vn 0.997400 -0.068300 0.021800 +vn -0.982600 0.137300 -0.125200 +vn -0.996900 -0.056700 -0.054500 +vn 0.996500 -0.081000 -0.018400 +vn -0.980200 0.138700 0.141600 +vn 0.999000 -0.044300 -0.008500 +vn -0.989900 -0.093200 -0.107000 +vn -0.991700 -0.076700 0.103000 +vn 0.993300 -0.076000 0.086700 +vn 0.999900 0.008000 -0.010600 +vn -0.996900 -0.071300 0.032600 +vn -0.994900 -0.061700 0.080400 +vn 0.996900 -0.076400 -0.016500 +vn -0.981000 0.135400 0.138700 +vn 0.998600 -0.051700 -0.008800 +vn -0.989100 -0.097000 -0.110900 +vn -0.985000 -0.115800 -0.128200 +vn 0.994300 0.098100 -0.042000 +vn 0.999900 0.013300 -0.009800 +vn -0.996500 -0.075900 0.035100 +vn -0.995400 -0.059000 0.075400 +vn 0.997000 -0.077200 0.001800 +vn -0.997600 -0.048100 0.049100 +vn 0.998900 -0.046500 -0.007700 +vn -0.998600 -0.046300 -0.026300 +vn -0.984100 -0.119400 -0.131200 +vn 0.998700 0.049800 -0.007200 +vn 0.997400 -0.066700 -0.028300 +vn -0.997600 -0.067900 -0.015600 +vn -0.983800 -0.112500 0.139400 +vn 0.999300 0.033200 -0.014900 +vn 0.997300 -0.072800 -0.000000 +vn -0.998000 -0.046500 0.043500 +vn 0.997900 -0.065100 -0.003200 +vn -0.998300 -0.047900 -0.032100 +vn -0.996400 -0.059400 -0.059900 +vn 0.995300 0.093700 0.024400 +vn 0.997600 -0.065900 -0.022200 +vn -0.997200 -0.072400 -0.018000 +vn -0.984500 -0.109500 0.136900 +vn 0.999400 0.033000 -0.008900 +vn 0.982600 -0.133000 0.129500 +vn -0.988100 -0.093200 0.122000 +vn 0.997900 -0.065200 -0.000100 +vn -0.988900 0.104900 0.104900 +vn -0.995900 -0.062300 -0.065100 +vn 0.998800 0.048000 -0.008600 +vn 0.997300 -0.071600 -0.014800 +vn -0.992500 0.077300 0.095000 +vn -0.992900 -0.078600 -0.089800 +vn 0.992900 0.065200 -0.099500 +vn -0.988900 -0.089900 0.118500 +vn 0.981600 -0.136800 0.132900 +vn 0.999900 -0.007900 -0.011800 +vn -0.989700 0.101700 0.100400 +vn 0.049700 0.994800 -0.088400 +vn 0.004600 0.996500 0.084000 +vn 0.007400 0.996400 0.084300 +vn 0.018200 0.996400 0.083200 +vn 0.009500 0.992500 -0.122200 +vn 0.058100 0.997900 -0.026800 +vn 0.022400 0.996400 0.081900 +vn 0.058300 0.998100 0.021400 +vn 0.006500 0.993100 -0.117500 +vn 0.057200 0.997500 -0.040500 +vn 0.058500 0.998300 0.007200 +vn 0.000100 0.996700 0.081700 +vn 0.003900 0.993700 -0.111600 +vn 0.055900 0.997000 -0.053700 +vn 0.053100 0.997300 0.051000 +vn 0.001900 0.994500 -0.104500 +vn 0.054200 0.996300 -0.066100 +vn 0.055000 0.997600 0.042900 +vn 0.016900 0.991600 -0.127900 +vn 0.058600 0.998300 -0.003200 +vn 0.056500 0.997800 0.034100 +vn 0.013000 0.992000 -0.125700 +vn 0.058600 0.998200 -0.012800 +vn 0.025300 0.991400 -0.128400 +vn 0.057600 0.998000 0.024800 +vn 0.021000 0.991400 -0.128800 +vn 0.048300 0.996700 0.064700 +vn 0.040700 0.992700 -0.113300 +vn 0.050900 0.997000 0.058300 +vn 0.037100 0.992200 -0.119100 +vn 0.042100 0.996300 0.074500 +vn 0.045300 0.996500 0.070100 +vn 0.033300 0.991800 -0.123600 +vn 0.010600 0.996400 0.084300 +vn 0.029400 0.991500 -0.126700 +vn 0.014200 0.996400 0.084000 +vn 0.026700 0.996400 0.080600 +vn 0.030900 0.996300 0.080600 +vn 0.047000 0.994100 -0.097900 +vn 0.000900 0.996600 0.082600 +vn 0.044000 0.993400 -0.106200 +vn 0.002500 0.996500 0.083400 +vn 0.000000 0.996800 -0.079800 +vn 0.034800 0.996200 0.079800 +vn 0.000600 0.995300 -0.096400 +vn 0.052200 0.995600 -0.077700 +vn 0.038600 0.996200 0.077700 +vn 0.000000 0.996200 -0.087100 +vn 0.041600 0.998900 -0.019700 +vn 0.002600 0.997500 0.069900 +vn -0.000100 -0.997400 0.072100 +vn 0.000300 0.055700 0.998400 +vn 0.041400 0.999000 0.013700 +vn -0.000100 0.038800 0.999200 +vn 0.000500 -0.046300 -0.998900 +vn -0.000200 0.997400 -0.071900 +vn 0.040900 0.998800 -0.028500 +vn -0.000200 0.997600 0.069100 +vn -0.000200 -0.997400 0.071700 +vn 0.000400 0.930000 0.367600 +vn 0.041700 0.999100 0.004700 +vn 0.000200 0.041600 -0.999100 +vn 0.000200 -0.044000 0.999000 +vn -0.001000 -0.999300 0.036900 +vn 0.000200 0.022400 -0.999700 +vn -0.000200 0.997500 0.070000 +vn 0.000600 -0.998200 -0.060200 +vn 0.000200 0.998200 0.060000 +vn -0.000100 -0.026100 0.999700 +vn 0.000200 0.038900 -0.999200 +vn 0.000300 -0.046200 0.998900 +vn -0.001100 -0.999500 0.030900 +vn 0.000100 0.049700 0.998800 +vn 0.000200 0.018600 -0.999800 +vn 0.000800 -0.929900 -0.367800 +vn 0.000400 -0.033000 -0.999500 +vn -0.000000 -0.029600 0.999600 +vn -0.000100 0.997400 -0.071600 +vn 0.039700 0.998500 -0.036800 +vn 0.000100 -0.997500 0.071100 +vn 0.000100 0.048000 0.998800 +vn 0.035900 0.998300 0.046100 +vn -0.000200 -0.997600 -0.069700 +vn 0.000400 -0.036100 -0.999300 +vn 0.000400 -0.026200 -0.999700 +vn -0.000000 0.997500 -0.071000 +vn 0.038100 0.998300 -0.044700 +vn 0.000100 -0.997400 0.071700 +vn 0.000400 0.049800 -0.998800 +vn 0.037900 0.998500 0.038800 +vn -0.000100 -0.997500 -0.071000 +vn 0.000000 -0.032900 0.999500 +vn 0.000400 -0.029700 -0.999600 +vn -0.001100 -0.999700 0.024400 +vn 0.000200 0.014600 -0.999900 +vn 0.000500 -0.997800 -0.065900 +vn 0.000400 0.048100 -0.998800 +vn -0.000200 -0.010500 0.999900 +vn -0.000800 -0.998400 0.056500 +vn 0.000000 -0.036000 0.999400 +vn -0.000200 0.006300 1.000000 +vn -0.001200 -0.999800 0.017700 +vn 0.000200 0.010500 -0.999900 +vn 0.000500 -0.997900 -0.064600 +vn -0.000500 0.997300 -0.072900 +vn -0.000200 -0.014600 0.999900 +vn -0.000800 -0.998600 0.052400 +vn 0.041800 0.999100 -0.003600 +vn -0.000200 0.002100 1.000000 +vn 0.000000 -0.997400 0.072100 +vn 0.039500 0.998700 0.030900 +vn -0.000600 -0.998200 -0.060200 +vn -0.000400 0.997400 -0.071900 +vn 0.000300 -0.010500 -0.999900 +vn 0.000300 -0.997700 0.067100 +vn 0.041900 0.999100 -0.010700 +vn 0.008100 0.997000 -0.076900 +vn -0.000000 -0.997400 0.072300 +vn 0.040700 0.998900 0.022500 +vn -0.000500 -0.998000 -0.063300 +vn -0.000900 -0.998900 0.047700 +vn 0.000300 -0.014600 -0.999900 +vn 0.000200 0.029700 -0.999600 +vn 0.000300 -0.997700 0.068300 +vn 0.000600 -0.998000 -0.063100 +vn 0.003400 0.997200 -0.075400 +vn -0.000100 -0.018600 0.999800 +vn -0.000400 -0.997700 0.068000 +vn -0.001000 -0.999100 0.042600 +vn -0.000200 0.022400 0.999700 +vn 0.000200 0.026100 -0.999700 +vn 0.000300 -0.997500 -0.070500 +vn 0.000600 -0.998100 -0.061700 +vn 0.000600 -0.055900 0.998400 +vn -0.000100 -0.022400 0.999700 +vn 0.000400 0.998200 -0.060100 +vn -0.000500 -0.997800 0.065900 +vn 0.000200 -0.997600 0.069400 +vn -0.000200 0.018600 0.999800 +vn 0.030800 0.997800 0.058300 +vn 0.000400 -0.997600 -0.069500 +vn -0.000400 -0.997800 -0.065900 +vn 0.000700 -0.347700 0.937600 +vn 0.000600 0.929900 -0.367700 +vn 0.000300 -0.018600 -0.999800 +vn 0.000400 -0.998100 0.061600 +vn 0.000200 -0.997500 0.070300 +vn 0.024600 0.997100 -0.072300 +vn -0.000900 -0.999100 -0.042500 +vn 0.033500 0.998100 0.052600 +vn 0.000700 -0.055900 -0.998400 +vn -0.000300 -0.997700 -0.068100 +vn 0.000400 0.052500 -0.998600 +vn 0.000300 -0.022500 -0.999700 +vn 0.000400 -0.998000 0.063000 +vn 0.000400 -0.997700 -0.068400 +vn 0.020900 0.997000 -0.075000 +vn -0.000800 -0.998900 -0.047700 +vn -0.000200 -0.002100 1.000000 +vn 0.000900 -0.347800 -0.937600 +vn -0.000600 -0.998000 0.063300 +vn 0.000400 0.051200 -0.998700 +vn -0.000200 0.014600 0.999900 +vn 0.000100 -0.997400 -0.072400 +vn 0.000500 -0.997700 -0.067200 +vn 0.000400 -0.053600 0.998600 +vn 0.000300 0.997800 -0.065800 +vn -0.000200 -0.006300 1.000000 +vn 0.024200 0.997500 0.066800 +vn -0.000700 -0.998200 0.060200 +vn 0.000200 0.052400 0.998600 +vn -0.000200 0.010500 0.999900 +vn 0.000200 -0.997400 -0.072300 +vn -0.000800 -0.998600 -0.052400 +vn 0.000500 -0.054400 0.998500 +vn 0.000300 0.997900 -0.064400 +vn 0.000300 -0.002100 -1.000000 +vn 0.027600 0.997600 0.063000 +vn 0.000400 -0.997900 0.064400 +vn 0.000200 0.051100 0.998700 +vn 0.016900 0.996900 -0.076700 +vn -0.001100 -0.999800 -0.017600 +vn -0.000700 -0.998400 -0.056600 +vn 0.000700 -0.053700 -0.998600 +vn 0.000500 0.055500 -0.998500 +vn 0.000200 -0.006400 -1.000000 +vn -0.000700 0.997400 0.071700 +vn 0.000400 -0.997800 0.065800 +vn -0.000000 0.997800 0.066900 +vn 0.012600 0.996900 -0.077300 +vn -0.001100 -0.999700 -0.024300 +vn -0.000300 -0.997500 0.070800 +vn 0.000700 -0.054500 -0.998500 +vn 0.000400 0.055000 -0.998500 +vn -0.000200 0.029600 0.999600 +vn -0.000800 0.997500 0.071200 +vn 0.000200 -0.997400 -0.071900 +vn -0.000100 0.997700 0.068000 +vn 0.000500 -0.055100 0.998500 +vn 0.000400 0.998000 -0.063000 +vn -0.000300 -0.997600 0.069600 +vn 0.007500 0.997400 0.071300 +vn 0.000300 0.055400 0.998500 +vn -0.000200 0.026100 0.999700 +vn -0.000100 0.036000 0.999400 +vn 0.000300 -0.997500 -0.071300 +vn 0.000600 -0.048200 -0.998800 +vn 0.000500 -0.055600 0.998500 +vn 0.000400 0.998100 -0.061600 +vn 0.000600 -0.930000 0.367700 +vn 0.012000 0.997300 0.071800 +vn 0.000300 0.054900 0.998500 +vn 0.031100 0.997500 -0.063900 +vn -0.000100 0.032900 0.999500 +vn -0.001000 -0.999500 -0.030800 +vn 0.000600 -0.049900 -0.998800 +vn 0.000700 -0.055100 -0.998500 +vn 0.000500 0.054300 -0.998500 +vn 0.000500 -0.998200 0.060100 +vn -0.000300 0.997500 0.070800 +vn 0.000200 0.998100 0.061400 +vn 0.028000 0.997300 -0.068500 +vn 0.000200 0.036100 -0.999300 +vn -0.001000 -0.999300 -0.036800 +vn 0.000300 -0.048100 0.998800 +vn 0.000800 -0.055600 -0.998500 +vn 0.000500 0.053500 -0.998600 +vn -0.000100 -0.997400 -0.071800 +vn -0.000400 0.997400 0.071400 +vn 0.000100 0.998000 0.062900 +vn 0.000300 -0.051300 0.998700 +vn 0.000300 0.033000 -0.999500 +vn 0.000200 0.997700 -0.068200 +vn 0.016400 0.997300 0.071200 +vn 0.000300 -0.049800 0.998800 +vn 0.000300 0.054300 0.998500 +vn 0.000000 -0.997400 -0.072300 +vn 0.000100 0.046000 0.998900 +vn 0.000500 -0.039000 -0.999200 +vn 0.000400 -0.052500 0.998600 +vn 0.000200 0.997800 -0.067000 +vn 0.000000 0.997500 -0.070200 +vn 0.020400 0.997400 0.069500 +vn 0.036100 0.998000 -0.051800 +vn 0.000200 0.053400 0.998600 +vn -0.001200 -1.000000 -0.003500 +vn 0.000000 0.043900 0.999000 +vn 0.000600 -0.051400 -0.998700 +vn 0.000500 -0.041700 -0.999100 +vn 0.000600 0.347600 -0.937600 +vn 0.000100 0.997600 -0.069300 +vn -0.000500 0.997400 0.071800 +vn 0.033800 0.997700 -0.058300 +vn 0.000100 0.997900 0.064300 +vn -0.001200 -0.999900 -0.010600 +vn 0.000300 0.046100 -0.998900 +vn 0.000700 -0.052600 -0.998600 +vn 0.000100 -0.038900 0.999200 +vn 0.000600 0.055800 -0.998400 +vn -0.001200 -0.999900 0.010700 +vn 0.000200 0.006300 -1.000000 +vn -0.000600 0.997400 0.071900 +vn 0.000000 0.997800 0.065600 +vn 0.000300 0.044000 -0.999000 +vn -0.000900 0.997500 0.070400 +vn 0.000100 -0.041600 0.999100 +vn -0.001200 -1.000000 0.003600 +vn 0.000400 0.347600 0.937600 +vn 0.000200 0.002100 -1.000000 +vn -0.000100 0.041500 0.999100 +vn 0.000500 -0.044100 -0.999000 +vn -0.000300 0.997400 -0.072100 +vn -0.997200 0.073800 0.009500 +vn 0.998500 0.054200 0.002300 +vn -0.992200 0.115900 0.044800 +vn 0.994800 -0.098100 -0.026700 +vn -0.997200 0.074100 -0.002700 +vn 0.999500 0.033000 -0.002900 +vn 0.989200 -0.105900 0.101000 +vn -0.999800 -0.013800 0.013100 +vn -0.997100 0.074100 0.015800 +vn -0.997600 0.069100 0.010900 +vn 0.998800 0.049300 0.000300 +vn 0.995900 -0.089700 0.007700 +vn -0.999300 0.035700 0.012600 +vn 0.994100 0.066800 0.085800 +vn -0.999900 -0.008300 0.012200 +vn 0.990100 -0.102200 0.096300 +vn -0.999700 -0.023600 0.000900 +vn -0.993500 0.110800 -0.027500 +vn 0.988900 -0.100000 -0.110200 +vn 0.995600 -0.093700 0.009800 +vn -0.999100 0.041000 0.013500 +vn 0.994700 0.063400 0.081000 +vn -0.993900 0.086300 0.068900 +vn 0.998800 0.046600 -0.015000 +vn -0.999800 -0.018400 0.002000 +vn -0.997800 0.066500 0.004600 +vn 0.988000 -0.103400 -0.114400 +vn 0.992500 -0.091600 0.081200 +vn -0.999400 0.034000 0.003500 +vn 0.984000 0.107200 -0.142400 +vn -0.993300 0.088600 0.074400 +vn 0.999100 0.041300 -0.013200 +vn -0.996200 0.080100 -0.033600 +vn -0.995400 0.084000 -0.045700 +vn 0.999100 0.036300 0.020900 +vn 0.993200 -0.088300 0.075800 +vn -0.999200 0.039000 0.002700 +vn 0.994700 0.042600 -0.093100 +vn -0.994200 0.101600 0.035600 +vn 0.999000 0.044300 -0.001500 +vn -0.996500 0.078500 -0.027500 +vn -0.995800 0.081900 -0.039700 +vn 0.999300 0.035100 0.015000 +vn 0.985500 -0.121300 0.118300 +vn -0.999900 -0.002700 0.011500 +vn 0.994700 0.056100 -0.085900 +vn -0.993700 0.105400 0.037900 +vn 0.999200 0.039300 -0.003300 +vn -0.999800 0.013900 0.010900 +vn -0.990100 0.106800 -0.090600 +vn 0.991300 0.081200 0.103700 +vn 0.986500 -0.117400 0.114200 +vn -0.999900 0.000000 0.011300 +vn 0.994100 0.059000 -0.090600 +vn -0.995100 0.097000 -0.018600 +vn 0.987200 -0.106800 -0.118500 +vn -0.999700 0.019400 0.011100 +vn -0.991000 0.103300 -0.085600 +vn 0.992000 0.077500 0.099400 +vn 0.997500 0.066800 -0.023500 +vn -0.992600 0.090900 0.079900 +vn 0.998100 0.043500 0.044000 +vn -0.994700 0.100700 -0.020800 +vn 0.986300 -0.110200 -0.122400 +vn -0.999900 0.013200 0.005100 +vn -0.999200 -0.035600 0.018200 +vn 0.986700 0.094900 -0.132200 +vn 0.997900 0.061900 -0.021200 +vn -0.992000 0.093400 0.085200 +vn 0.998400 0.041400 0.038300 +vn -0.993200 0.093700 -0.069300 +vn 0.999400 0.034100 0.009000 +vn -0.999800 0.018500 0.004900 +vn -0.999400 -0.030300 0.016700 +vn 0.986000 0.098100 -0.135000 +vn 0.997900 0.063700 0.006600 +vn -0.993200 0.109100 0.040100 +vn 0.988200 0.096300 0.119100 +vn -0.993800 0.091100 -0.063500 +vn 0.999400 0.033300 0.003100 +vn -0.999600 -0.024800 0.015300 +vn -0.999400 -0.033900 -0.001800 +vn 0.996800 0.045700 -0.065800 +vn 0.998200 0.059000 0.004400 +vn -0.992700 0.112600 0.042500 +vn 0.989000 0.092600 0.115500 +vn -0.986500 0.121800 -0.109200 +vn 0.992700 0.073800 0.095000 +vn -0.999700 -0.019300 0.014100 +vn 0.978700 -0.139900 -0.150000 +vn -0.999600 -0.028800 -0.000400 +vn 0.996300 0.048100 -0.071000 +vn 0.990500 -0.093600 -0.101000 +vn -0.994300 0.104200 -0.023000 +vn 0.989500 0.081600 -0.119200 +vn -0.987500 0.117900 -0.104800 +vn 0.993400 0.070300 0.090500 +vn -0.994900 0.082300 0.057600 +vn 0.992700 -0.071300 -0.097500 +vn -0.984600 0.121900 0.125400 +vn 0.996400 0.053900 0.065800 +vn 0.989700 -0.096700 -0.105700 +vn -0.993900 0.107600 -0.025200 +vn 0.988800 0.085000 -0.122700 +vn -0.998100 -0.056500 0.025700 +vn 0.985300 0.101200 -0.137600 +vn -0.994400 0.084200 0.063300 +vn 0.997300 0.072800 0.011400 +vn -0.983700 0.125300 0.129000 +vn 0.996900 0.051000 0.060500 +vn 0.998700 0.039500 0.032600 +vn -0.994400 0.088500 -0.057600 +vn 0.998300 0.038000 -0.043900 +vn -0.998400 -0.051400 0.023600 +vn 0.984600 0.104300 -0.140100 +vn -0.995100 0.093600 0.031200 +vn 0.997600 0.068300 0.008900 +vn -0.999100 -0.041600 0.000000 +vn 0.985000 0.111100 0.131900 +vn 0.998900 0.037800 0.026800 +vn -0.994900 0.086200 -0.051700 +vn 0.998000 0.039600 -0.049600 +vn -0.998500 -0.053800 -0.009000 +vn 0.995800 0.050600 -0.076100 +vn -0.994700 0.097700 0.033400 +vn 0.996700 0.076400 -0.028400 +vn -0.999100 -0.041500 0.003000 +vn 0.985800 0.107500 0.128900 +vn 0.989800 0.088800 0.111700 +vn -0.988400 0.114200 -0.100200 +vn 0.982000 -0.127300 -0.139500 +vn -0.998800 -0.049000 -0.007000 +vn 0.995300 0.053300 -0.081100 +vn -0.995900 0.089300 -0.014300 +vn 0.997100 0.071700 -0.025900 +vn -0.993500 -0.075100 -0.085100 +vn 0.992200 0.068400 -0.103800 +vn 0.990500 0.085000 0.107800 +vn -0.989300 0.110500 -0.095500 +vn 0.981200 -0.130500 -0.142400 +vn -0.988100 0.108200 0.109400 +vn 0.997300 0.048300 0.055100 +vn -0.995500 0.093300 -0.016400 +vn 0.983600 -0.129100 0.125900 +vn 0.991600 0.071600 -0.107900 +vn -0.994200 -0.071700 -0.080300 +vn 0.988100 0.088300 -0.126000 +vn -0.998700 -0.046200 0.021700 +vn 0.995700 0.089700 0.021700 +vn 0.997700 0.045800 0.049600 +vn -0.987200 0.111600 0.113600 +vn -0.991700 0.099900 -0.080400 +vn 0.984600 -0.125200 0.122200 +vn 0.999200 0.033700 -0.020800 +vn -0.983100 -0.115500 0.141700 +vn 0.987400 0.091600 -0.129200 +vn -0.999000 -0.041000 0.019900 +vn 0.996100 0.085700 0.019000 +vn 0.986600 0.103800 0.125800 +vn -0.998800 -0.044800 -0.020500 +vn -0.992500 0.096600 -0.075000 +vn 0.996700 -0.081500 0.003700 +vn 0.999100 0.034400 -0.026700 +vn -0.994700 -0.048700 0.090600 +vn 0.997600 0.041500 -0.055100 +vn -0.999000 -0.044000 -0.005200 +vn 0.994800 0.094000 -0.039200 +vn 0.987400 0.100100 0.122500 +vn -0.998900 -0.043600 -0.014700 +vn 0.996300 -0.085700 0.005700 +vn -0.984600 0.129500 -0.117500 +vn 0.980300 -0.133800 -0.145100 +vn -0.994300 -0.064400 0.085200 +vn 0.997200 0.043500 -0.060500 +vn -0.999200 -0.039000 -0.003400 +vn 0.995300 0.089800 -0.036400 +vn 0.990900 0.074900 -0.111800 +vn -0.990700 -0.089500 -0.102900 +vn 0.996100 -0.085400 -0.020400 +vn -0.985600 0.125600 -0.113400 +vn 0.979500 -0.136900 -0.147700 +vn -0.993700 -0.067400 0.089800 +vn 0.995300 0.060100 0.076100 +vn -0.986400 0.115000 0.117700 +vn 0.979700 -0.144300 0.139100 +vn 0.990200 0.078300 -0.115600 +vn -0.991400 -0.085800 -0.098700 +vn 0.995700 -0.089800 -0.022400 +vn -0.997300 -0.066400 0.030200 +vn 0.996500 0.081500 0.016400 +vn -0.997700 -0.051900 -0.043400 +vn 0.995800 0.056900 0.071000 +vn -0.985500 0.118400 0.121600 +vn 0.980700 -0.140600 0.136100 +vn 0.998800 0.035400 -0.032500 +vn -0.985900 -0.103100 0.131400 +vn 0.996400 -0.070400 -0.046400 +vn -0.997700 -0.061500 0.027900 +vn 0.996900 0.077200 0.013800 +vn -0.998000 -0.049800 -0.037800 +vn 0.995500 0.046700 0.082600 +vn -0.999100 -0.042600 -0.008800 +vn 0.998000 -0.063700 -0.003300 +vn 0.998600 0.036600 -0.038300 +vn -0.985200 -0.106400 0.134200 +vn 0.996000 -0.072000 -0.052300 +vn -0.997900 -0.063300 -0.013300 +vn 0.995800 0.085400 -0.033700 +vn -0.987400 -0.104600 -0.118300 +vn 0.984200 0.114700 0.134700 +vn -0.999100 -0.041900 -0.002900 +vn 0.997700 -0.068300 -0.001700 +vn 0.983700 -0.120500 -0.133200 +vn -0.996400 -0.054100 0.065200 +vn -0.998200 -0.058600 -0.011100 +vn 0.999900 -0.002600 -0.011700 +vn 0.996200 0.081000 -0.031000 +vn -0.988300 -0.100800 -0.114700 +vn 0.993500 0.062100 -0.095100 +vn -0.992200 -0.082100 -0.094300 +vn -0.977600 0.148100 0.149300 +vn 0.997700 -0.066800 -0.013100 +vn 0.982900 -0.123900 -0.136400 +vn -0.995900 -0.056500 0.070400 +vn -0.221500 -0.974500 0.036600 +vn -0.744300 0.102600 -0.659900 +vn -0.810300 0.586000 -0.004300 +vn -0.785300 0.618700 0.025200 +vn -0.496600 -0.864900 0.073200 +vn -0.817800 0.575500 0.002600 +vn -0.410200 -0.911100 0.040400 +vn -0.819500 0.573000 0.002400 +vn -0.329900 -0.935300 0.127900 +vn -0.746300 0.023900 0.665200 +vn -0.733200 0.029900 0.679300 +vn -0.508200 -0.860900 0.025100 +vn -0.768000 0.637600 0.060400 +vn -0.752400 -0.032700 -0.657900 +vn -0.117200 -0.988900 0.091200 +vn -0.798600 0.600300 -0.042500 +vn -0.759100 0.015900 0.650800 +vn -0.312700 -0.941300 0.127500 +vn -0.743400 0.025300 0.668400 +vn -0.729500 0.031400 0.683300 +vn -0.512800 -0.858200 0.022100 +vn -0.756600 -0.024900 -0.653400 +vn -0.766100 0.639600 0.063700 +vn -0.364800 -0.911200 -0.191600 +vn -0.801600 0.596500 -0.039800 +vn -0.757600 0.017100 0.652500 +vn -0.523200 -0.852100 0.010000 +vn -0.816900 0.576700 0.000600 +vn -0.345000 -0.937800 0.039500 +vn -0.729600 0.115000 -0.674100 +vn -0.814500 0.579900 -0.019900 +vn -0.779000 0.134300 -0.612500 +vn -0.364400 -0.922600 0.126600 +vn -0.775700 0.628400 -0.058800 +vn -0.767400 0.060300 -0.638300 +vn -0.521900 -0.852700 0.023700 +vn -0.815900 0.578200 -0.001100 +vn -0.358600 -0.932700 0.039800 +vn -0.724300 0.118400 -0.679300 +vn -0.816300 0.577500 -0.014800 +vn -0.630400 -0.117400 -0.767300 +vn -0.347200 -0.929100 0.127600 +vn -0.778200 0.625400 -0.056700 +vn -0.765300 0.067400 -0.640100 +vn -0.760400 -0.016900 -0.649300 +vn -0.170500 -0.979700 0.105500 +vn -0.786600 0.615300 -0.051100 +vn -0.762500 0.011300 0.646900 +vn -0.792100 0.178300 0.583800 +vn -0.482100 -0.875400 0.034500 +vn -0.740500 -0.002700 0.672100 +vn -0.761600 0.006800 0.648100 +vn -0.763100 -0.010800 -0.646200 +vn -0.156600 -0.982400 0.102000 +vn -0.789600 0.611700 -0.049200 +vn -0.762000 0.012400 0.647400 +vn -0.686700 -0.022400 0.726600 +vn -0.489800 -0.871200 0.032600 +vn -0.743900 -0.001100 0.668200 +vn -0.762200 0.007900 0.647300 +vn -0.817700 0.575600 -0.009300 +vn -0.430800 -0.895300 0.113600 +vn -0.766400 0.638500 -0.069600 +vn -0.770700 0.029100 -0.636500 +vn -0.815700 0.571100 0.092500 +vn -0.289700 -0.956400 0.038000 +vn -0.717700 -0.073900 -0.692400 +vn -0.799600 0.600500 0.003100 +vn -0.818800 0.574100 -0.003700 +vn -0.414800 -0.902200 0.118300 +vn -0.768600 0.636300 -0.066400 +vn -0.770700 0.037200 -0.636100 +vn -0.745100 0.659000 -0.102200 +vn -0.724400 -0.067800 -0.686000 +vn -0.303600 -0.952000 0.038400 +vn -0.797000 0.603900 0.006300 +vn -0.761300 0.013500 0.648200 +vn -0.724000 -0.009700 0.689800 +vn -0.444600 -0.894900 0.039300 +vn -0.762800 0.074200 -0.642400 +vn -0.757200 0.006200 0.653200 +vn -0.782000 0.622500 0.031400 +vn -0.230200 -0.965900 0.118200 +vn -0.695900 0.133200 0.705600 +vn -0.756200 0.649700 0.077700 +vn -0.760300 0.014700 0.649400 +vn -0.728500 -0.007900 0.685000 +vn -0.454900 -0.889700 0.038500 +vn -0.759800 0.080600 -0.645100 +vn -0.759000 0.007500 0.651100 +vn -0.778500 0.626500 0.038200 +vn -0.214700 -0.969900 0.115300 +vn -0.708000 -0.203000 0.676400 +vn -0.823500 0.554400 -0.120100 +vn -0.770100 0.045200 -0.636300 +vn -0.688100 -0.094600 -0.719400 +vn -0.234900 -0.971300 0.036800 +vn -0.755800 0.018400 0.654500 +vn -0.808500 0.588500 -0.003900 +vn -0.516500 -0.856100 0.018900 +vn -0.485900 -0.870000 0.083500 +vn -0.708600 0.034400 -0.704700 +vn -0.672100 -0.102800 -0.733300 +vn -0.769000 0.052900 -0.637000 +vn -0.695900 -0.089900 -0.712500 +vn -0.248400 -0.967900 0.037000 +vn -0.753800 0.019700 0.656800 +vn -0.806500 0.591300 -0.003000 +vn -0.519500 -0.854300 0.015400 +vn -0.473800 -0.875700 0.092700 +vn -0.712500 -0.145500 -0.686500 +vn -0.680200 -0.098900 -0.726300 +vn -0.760500 0.008700 0.649300 +vn -0.794300 0.607400 0.010100 +vn -0.295700 -0.946900 0.126500 +vn -0.819400 0.573200 0.006600 +vn -0.725500 0.032900 0.687400 +vn -0.371900 -0.927400 0.040100 +vn -0.764200 0.641600 0.066700 +vn -0.804500 0.592800 -0.036600 +vn -0.714300 -0.013300 0.699700 +vn -0.761100 0.007800 0.648500 +vn -0.791400 0.611100 0.014600 +vn -0.278900 -0.952200 0.125000 +vn -0.819000 0.573700 0.006900 +vn -0.721400 0.034400 0.691700 +vn -0.385000 -0.922000 0.040300 +vn -0.762200 0.643500 0.069700 +vn -0.807300 0.589200 -0.033100 +vn -0.719200 -0.011500 0.694700 +vn -0.804400 0.594200 -0.001500 +vn -0.496700 -0.867400 0.030400 +vn -0.518400 -0.854300 0.037000 +vn -0.742400 -0.047600 -0.668200 +vn -0.718800 0.121500 -0.684500 +vn -0.638800 -0.115200 -0.760700 +vn -0.143000 -0.984800 0.098400 +vn -0.780900 0.622200 -0.054800 +vn -0.761700 0.643300 -0.076900 +vn -0.802100 0.597200 0.000500 +vn -0.502800 -0.863900 0.027900 +vn -0.513000 -0.856900 0.049900 +vn -0.713100 0.124200 -0.689900 +vn -0.747600 -0.040300 -0.662900 +vn -0.647200 -0.112600 -0.753900 +vn -0.129900 -0.987000 0.094800 +vn -0.783700 0.618800 -0.052900 +vn -0.764200 0.640900 -0.073100 +vn -0.717100 0.035900 0.696100 +vn -0.317500 -0.947500 0.038800 +vn -0.760300 0.645600 0.072500 +vn -0.792600 0.608000 -0.047200 +vn -0.809900 0.585800 -0.029100 +vn -0.692500 -0.020600 0.721100 +vn -0.398400 -0.909100 0.122000 +vn -0.747200 0.000500 0.664700 +vn -0.739600 0.107100 -0.664400 +vn -0.701800 0.131300 0.700200 +vn -0.331300 -0.942700 0.039100 +vn -0.758300 0.647600 0.075200 +vn -0.795600 0.604100 -0.045000 +vn -0.812300 0.582700 -0.024700 +vn -0.698200 -0.018800 0.715600 +vn -0.381500 -0.915900 0.124800 +vn -0.750100 0.002000 0.661300 +vn -0.734700 0.111200 -0.669200 +vn -0.718000 0.031700 -0.695300 +vn -0.199600 -0.973400 0.112200 +vn -0.655600 -0.109700 -0.747100 +vn -0.770800 0.633800 -0.063600 +vn -0.762600 0.009100 0.646800 +vn -0.749200 0.655300 -0.096300 +vn -0.464700 -0.884700 0.037500 +vn -0.730800 -0.061400 -0.679800 +vn -0.740200 0.026800 0.671900 +vn -0.713400 0.033000 -0.700000 +vn -0.184800 -0.976700 0.108900 +vn -0.663900 -0.106400 -0.740200 +vn -0.773200 0.631200 -0.061100 +vn -0.762700 0.010200 0.646700 +vn -0.752800 0.651900 -0.090800 +vn -0.473800 -0.879900 0.036100 +vn -0.736800 -0.054700 -0.673900 +vn -0.736800 0.028300 0.675500 +vn -0.460500 -0.881900 0.100800 +vn -0.703800 -0.017000 0.710200 +vn -0.732700 -0.006100 0.680500 +vn -0.769100 0.012300 -0.639000 +vn -0.262100 -0.964300 0.037300 +vn -0.756500 0.086700 -0.648300 +vn -0.775000 0.630400 0.045600 +vn -0.814700 0.579800 -0.002500 +vn -0.446100 -0.888500 0.107700 +vn -0.709100 -0.015200 0.704900 +vn -0.770200 0.020700 -0.637500 +vn -0.736700 -0.004400 0.676200 +vn -0.275900 -0.960500 0.037600 +vn -0.752700 0.092400 -0.651800 +vn -0.771200 0.634300 0.053600 +vn -0.813400 0.581700 -0.003500 +vn -0.422100 -0.905600 0.040200 +vn -0.756100 0.648800 -0.085800 +vn -0.752700 0.003400 0.658300 +vn -0.703400 -0.084900 -0.705700 +vn -0.262300 -0.957100 0.123100 +vn -0.751500 0.021000 0.659400 +vn -0.521500 -0.853200 0.010200 +vn -0.765300 -0.004500 -0.643700 +vn -0.433600 -0.900200 0.039900 +vn -0.759000 0.646000 -0.081100 +vn -0.755100 0.004800 0.655600 +vn -0.710700 -0.079600 -0.699000 +vn -0.246100 -0.961700 0.120800 +vn -0.749000 0.022400 0.662100 +vn -0.522800 -0.852500 0.005000 +vn -0.767500 0.003900 -0.641100 +vn -0.442300 -0.845900 0.298100 +vn -0.748700 0.097600 -0.655700 +vn -0.811900 0.583800 -0.004100 +vn -0.788400 0.614800 0.019600 +vn -0.505700 -0.860500 0.062000 +vn -0.818500 0.574500 0.004700 +vn -0.397800 -0.916600 0.040400 +vn -0.819300 0.573300 -0.000600 +vn 0.462300 0.886700 -0.007900 +vn 0.544100 -0.008100 -0.839000 +vn 0.385800 -0.920900 -0.054700 +vn 0.525700 0.021600 -0.850400 +vn 0.505000 -0.019200 -0.862900 +vn 0.419200 0.906800 0.045400 +vn 0.527700 -0.849400 -0.007400 +vn 0.503900 -0.863200 -0.032600 +vn 0.482500 0.875900 -0.004700 +vn 0.521700 0.002400 0.853100 +vn 0.537600 0.843200 0.000000 +vn 0.537700 0.843100 -0.002900 +vn 0.542900 -0.008900 -0.839800 +vn 0.379000 -0.923800 -0.054900 +vn 0.525700 0.001200 0.850700 +vn 0.517900 -0.855100 -0.024400 +vn 0.541300 -0.009700 -0.840800 +vn 0.372200 -0.926500 -0.055000 +vn 0.500300 -0.020200 -0.865600 +vn 0.476000 0.879500 -0.005700 +vn 0.443800 -0.894800 -0.049300 +vn 0.538000 0.842900 -0.001600 +vn 0.536900 0.843700 -0.002400 +vn 0.548800 -0.013000 0.835900 +vn 0.477900 0.013500 0.878300 +vn 0.529300 0.000200 0.848400 +vn 0.513700 -0.857500 -0.027200 +vn 0.539400 -0.010500 -0.842000 +vn 0.426700 0.904300 -0.013800 +vn 0.365600 -0.929100 -0.055000 +vn 0.495500 -0.021100 -0.868300 +vn 0.436500 -0.898300 -0.050400 +vn 0.457000 0.888600 0.039300 +vn 0.472600 -0.880200 -0.043400 +vn 0.547700 -0.015800 0.836500 +vn 0.471900 0.880900 0.035900 +vn 0.429100 -0.901800 -0.051300 +vn 0.483300 0.012200 0.875400 +vn 0.419500 0.907600 -0.014900 +vn 0.546200 -0.018600 0.837500 +vn 0.502000 -0.045100 0.863700 +vn 0.488600 0.011000 0.872400 +vn 0.464500 0.884800 0.037700 +vn 0.465600 -0.883900 -0.045100 +vn 0.540500 0.007500 -0.841300 +vn 0.479100 0.877100 0.034000 +vn 0.471000 0.044400 -0.881000 +vn 0.421700 -0.905200 -0.052200 +vn 0.524700 0.851300 -0.000600 +vn 0.544300 -0.021300 0.838600 +vn 0.496800 -0.046600 0.866600 +vn 0.493800 0.009800 0.869500 +vn 0.469600 -0.025400 -0.882500 +vn 0.542400 0.004500 -0.840100 +vn 0.472700 0.848900 -0.236500 +vn 0.476700 0.042900 -0.878000 +vn 0.520700 0.853700 -0.000600 +vn 0.543800 0.001500 -0.839200 +vn 0.469200 -0.883100 0.001400 +vn 0.482300 0.041300 -0.875000 +vn 0.533300 0.249100 -0.808400 +vn 0.362400 0.930700 0.049500 +vn 0.372700 -0.927700 0.020400 +vn 0.544800 0.000000 -0.838600 +vn 0.475700 -0.879600 0.000100 +vn 0.511200 0.859200 0.022400 +vn 0.487800 0.039500 -0.872100 +vn 0.468900 -0.052400 0.881700 +vn 0.379300 -0.925100 0.019400 +vn 0.413600 -0.910300 0.013200 +vn 0.516500 0.856100 0.019700 +vn 0.386000 -0.922300 0.018300 +vn 0.538800 -0.002900 0.842500 +vn 0.536100 0.235300 0.810700 +vn 0.529400 -0.033700 0.847700 +vn 0.420700 -0.907100 0.011800 +vn 0.397000 0.916600 0.047700 +vn 0.392800 -0.919500 0.017100 +vn 0.541300 -0.003800 0.840800 +vn 0.504200 -0.863600 -0.005500 +vn 0.525400 -0.035900 0.850100 +vn 0.503500 0.033600 -0.863300 +vn 0.404300 0.913400 0.047000 +vn 0.521200 -0.037900 0.852600 +vn 0.398300 0.917100 -0.018100 +vn 0.513200 -0.858200 -0.006800 +vn 0.508900 -0.860800 -0.006200 +vn 0.525400 -0.014700 -0.850700 +vn 0.508400 0.031400 -0.860500 +vn 0.516700 -0.039900 0.855200 +vn 0.391400 0.920000 -0.019000 +vn 0.517100 -0.855900 -0.007200 +vn 0.455700 -0.890100 0.004400 +vn 0.384600 0.922900 -0.019900 +vn 0.521800 -0.015600 -0.852900 +vn 0.549000 -0.004800 0.835800 +vn 0.508600 0.006000 0.861000 +vn 0.517900 -0.016500 -0.855300 +vn 0.506400 0.862300 -0.001600 +vn 0.529300 0.848400 0.011000 +vn 0.545500 -0.007600 -0.838100 +vn 0.377900 0.925600 -0.020600 +vn 0.399900 -0.915000 -0.054000 +vn 0.462500 -0.886600 0.002900 +vn 0.528700 -0.848700 -0.011800 +vn 0.549500 -0.005500 0.835500 +vn 0.513200 0.004800 0.858300 +vn 0.513800 -0.017400 -0.857700 +vn 0.500900 0.865500 -0.002100 +vn 0.532400 0.846500 0.007900 +vn 0.545000 -0.007300 -0.838400 +vn 0.495000 0.868900 -0.002900 +vn 0.392800 -0.918000 -0.054400 +vn 0.529400 0.018900 -0.848200 +vn 0.527000 -0.849800 -0.015000 +vn 0.534800 0.844900 0.004800 +vn 0.529100 -0.848600 -0.005500 +vn 0.455300 0.890300 -0.009100 +vn 0.458400 -0.887500 -0.046600 +vn 0.524600 -0.851200 -0.018200 +vn 0.426700 0.903300 0.044500 +vn 0.549700 -0.006100 0.835400 +vn 0.498300 -0.866300 -0.035100 +vn 0.488900 0.872300 -0.003700 +vn 0.534900 -0.262200 0.803200 +vn 0.532700 0.016200 -0.846200 +vn 0.536600 0.843800 0.001600 +vn 0.529900 -0.848100 -0.003600 +vn 0.448200 0.893900 -0.010300 +vn 0.451200 -0.891100 -0.048000 +vn 0.521500 -0.853000 -0.021300 +vn 0.434300 0.899700 0.043400 +vn 0.441000 0.897400 -0.011500 +vn 0.549400 -0.010200 0.835500 +vn 0.492300 -0.869600 -0.037400 +vn 0.472400 0.014700 0.881300 +vn 0.532800 -0.000900 0.846300 +vn 0.441900 0.896100 0.042100 +vn 0.537200 -0.011300 -0.843400 +vn 0.486000 -0.873100 -0.039500 +vn 0.535500 0.844500 -0.001800 +vn 0.359100 -0.931700 -0.054900 +vn 0.433800 0.900900 -0.012700 +vn 0.535600 0.013400 -0.844300 +vn 0.490500 -0.022000 -0.871100 +vn 0.531100 -0.242900 -0.811700 +vn 0.535900 -0.001900 0.844300 +vn 0.449500 0.892300 0.040800 +vn 0.534700 -0.012100 -0.844900 +vn 0.479400 -0.876600 -0.041500 +vn 0.533600 0.845800 -0.001400 +vn 0.468800 -0.853500 0.227400 +vn 0.531100 0.847300 -0.001000 +vn 0.538300 0.010500 -0.842700 +vn 0.465200 0.045800 -0.884000 +vn 0.414400 -0.908600 -0.052900 +vn 0.485400 -0.022900 -0.874000 +vn 0.542000 -0.024000 0.840000 +vn 0.498900 0.008500 0.866600 +vn 0.480200 -0.023800 -0.876800 +vn 0.486100 0.873300 0.031900 +vn 0.528100 0.849200 -0.000700 +vn 0.472200 -0.842900 -0.258100 +vn 0.407100 -0.911800 -0.053500 +vn 0.491400 -0.048000 0.869600 +vn 0.539400 -0.026500 0.841700 +vn 0.503800 0.007200 0.863800 +vn 0.474900 -0.024600 -0.879700 +vn 0.492800 0.869600 0.029700 +vn 0.366200 -0.930300 0.021300 +vn 0.485900 -0.049300 0.872600 +vn 0.499300 0.866000 0.027400 +vn 0.545400 -0.001500 -0.838200 +vn 0.493200 0.037700 -0.869100 +vn 0.480300 -0.050400 0.875600 +vn 0.369100 0.928100 0.049300 +vn 0.536400 -0.029000 0.843500 +vn 0.481900 -0.876200 -0.001300 +vn 0.505400 0.862500 0.025000 +vn 0.545600 -0.004600 -0.838000 +vn 0.498400 0.035700 -0.866200 +vn 0.474600 -0.051500 0.878700 +vn 0.375900 0.925400 0.049000 +vn 0.487900 -0.872900 -0.002500 +vn 0.382800 0.922600 0.048700 +vn 0.533000 -0.031400 0.845500 +vn 0.412400 0.910900 -0.016000 +vn 0.399700 -0.916500 0.015900 +vn 0.493700 -0.869600 -0.003600 +vn 0.427800 -0.903800 0.010400 +vn 0.389900 0.919600 0.048200 +vn 0.531900 -0.012900 -0.846700 +vn 0.543500 -0.004700 0.839400 +vn 0.405300 0.914000 -0.017100 +vn 0.406600 -0.913500 0.014600 +vn 0.499100 -0.866500 -0.004600 +vn 0.434800 -0.900500 0.008900 +vn 0.528800 -0.013800 -0.848600 +vn 0.545400 -0.005500 0.838100 +vn 0.516300 0.856400 -0.000800 +vn 0.512000 -0.041800 0.857900 +vn 0.441900 -0.897100 0.007400 +vn 0.521300 0.853200 0.016900 +vn 0.547000 -0.006200 0.837100 +vn 0.513100 0.029100 -0.857800 +vn 0.530100 -0.847900 -0.005100 +vn 0.520500 -0.853800 -0.007400 +vn 0.511600 0.859200 -0.001100 +vn 0.448800 -0.893600 0.005900 +vn 0.507100 -0.043500 0.860800 +vn 0.525600 0.850600 0.014000 +vn 0.548100 -0.005500 0.836400 +vn 0.371400 0.928200 -0.021400 +vn 0.517600 0.026700 -0.855200 +vn 0.529800 -0.848100 -0.008400 +vn 0.469200 0.883100 -0.006800 +vn 0.523400 -0.852100 -0.007600 +vn 0.521800 0.024200 -0.852700 +vn 0.509500 -0.018300 -0.860300 +vn 0.411700 0.910100 0.046300 +vn 0.525800 -0.850600 -0.007600 +vn 0.509000 -0.860200 -0.030000 +vn 0.478600 0.839000 0.259000 +vn 0.517600 0.003600 0.855600 +vn 0.859400 -0.046300 -0.509200 +vn 0.840600 0.525600 -0.131200 +vn 0.886700 0.459700 -0.048400 +vn 0.835300 -0.538600 0.110200 +vn 0.847100 0.084700 -0.524700 +vn 0.887200 0.460300 0.032500 +vn 0.852400 -0.508100 -0.123700 +vn 0.862400 -0.068500 0.501600 +vn 0.858400 -0.051600 -0.510300 +vn 0.878200 -0.478100 0.015800 +vn 0.861100 0.010700 -0.508300 +vn 0.808100 -0.567400 -0.158000 +vn 0.848900 0.079500 -0.522600 +vn 0.867300 -0.027700 0.496900 +vn 0.870100 -0.489600 0.057100 +vn 0.861100 -0.074800 0.502900 +vn 0.868200 -0.000400 0.496300 +vn 0.878700 -0.477400 0.008400 +vn 0.861600 0.006100 -0.507600 +vn 0.803200 -0.574000 -0.159400 +vn 0.860300 0.497000 -0.113300 +vn 0.866800 -0.034800 0.497400 +vn 0.872000 -0.486900 0.050700 +vn 0.889700 0.456400 -0.009700 +vn 0.868200 -0.006600 0.496200 +vn 0.839400 -0.532900 0.106700 +vn 0.888100 0.459100 0.023000 +vn 0.865900 -0.491300 -0.094100 +vn 0.856700 0.502200 -0.117500 +vn 0.861800 -0.023700 -0.506700 +vn 0.812700 -0.569300 0.124300 +vn 0.889600 0.456400 -0.017600 +vn 0.867000 0.487300 -0.104200 +vn 0.843300 -0.527500 0.102900 +vn 0.888700 0.458200 0.013300 +vn 0.863600 -0.494100 -0.100800 +vn 0.873700 -0.484500 0.044100 +vn 0.861400 -0.029500 -0.507100 +vn 0.817500 -0.562900 0.122000 +vn 0.858300 0.037800 -0.511700 +vn 0.863800 0.492000 -0.108900 +vn 0.798200 -0.580700 -0.160500 +vn 0.866200 -0.041900 0.498000 +vn 0.860200 -0.503700 0.080100 +vn 0.875200 -0.482400 0.037300 +vn 0.866700 0.019200 0.498500 +vn 0.826400 -0.542800 -0.149900 +vn 0.859200 0.031200 -0.510700 +vn 0.834600 -0.134800 0.534100 +vn 0.793000 -0.587500 -0.161400 +vn 0.795100 0.588300 -0.147300 +vn 0.865400 -0.048800 0.498700 +vn 0.863000 -0.499700 0.074700 +vn 0.822200 -0.556600 0.119400 +vn 0.867200 0.013100 0.497700 +vn 0.822000 -0.548700 -0.152400 +vn 0.883400 0.464800 0.059700 +vn 0.848300 -0.240100 0.471900 +vn 0.861000 -0.497200 -0.107100 +vn 0.835900 0.472300 -0.279500 +vn 0.860900 -0.035200 -0.507600 +vn 0.792100 -0.596000 0.131500 +vn 0.826700 -0.550400 0.116600 +vn 0.877900 0.471700 -0.082200 +vn 0.873500 -0.482700 -0.063700 +vn 0.884800 0.463100 0.050900 +vn 0.828200 -0.112100 -0.549100 +vn 0.858300 -0.500500 -0.113100 +vn 0.860200 -0.040800 -0.508300 +vn 0.843100 0.094500 -0.529400 +vn 0.797400 -0.589200 0.130000 +vn 0.817500 -0.554800 -0.154500 +vn 0.875500 0.475100 -0.088200 +vn 0.871900 -0.484400 -0.071800 +vn 0.868000 -0.013300 0.496300 +vn 0.865500 -0.496100 0.069100 +vn 0.843800 -0.228000 -0.485800 +vn 0.867600 0.007000 0.497200 +vn 0.845100 0.089700 -0.527000 +vn 0.842200 -0.521500 -0.137000 +vn 0.812900 -0.561000 -0.156400 +vn 0.844700 -0.120700 0.521400 +vn 0.867700 -0.020500 0.496600 +vn 0.816700 0.559100 -0.142500 +vn 0.867900 -0.492700 0.063200 +vn 0.879900 0.469000 0.076300 +vn 0.868000 0.003300 0.496600 +vn 0.849700 0.082600 0.520700 +vn 0.838400 -0.526500 -0.140700 +vn 0.870100 -0.486500 -0.079600 +vn 0.842400 -0.124600 0.524300 +vn 0.862100 -0.012100 -0.506600 +vn 0.811500 0.566300 -0.144000 +vn 0.802700 -0.582500 0.128300 +vn 0.881700 0.466800 0.068200 +vn 0.851800 0.078200 0.518000 +vn 0.872900 0.478900 -0.093800 +vn 0.877900 -0.478000 -0.028500 +vn 0.868100 -0.488700 -0.087100 +vn 0.839000 -0.100100 -0.534800 +vn 0.862000 -0.017900 -0.506600 +vn 0.834000 0.111300 -0.540500 +vn 0.858800 0.496200 0.127800 +vn 0.807700 -0.575800 0.126400 +vn 0.827500 0.539100 0.156700 +vn 0.870000 0.482900 -0.099100 +vn 0.877100 -0.478800 -0.037600 +vn 0.854000 -0.512500 0.090000 +vn 0.836500 -0.103400 -0.538100 +vn 0.836400 0.107400 -0.537500 +vn 0.865200 0.031000 0.500500 +vn 0.862000 0.491800 0.122700 +vn 0.834600 -0.531700 -0.144100 +vn 0.831900 0.533100 0.154200 +vn 0.839900 -0.128200 0.527400 +vn 0.806200 0.573500 -0.145300 +vn 0.857200 -0.507900 0.085200 +vn 0.870700 0.480500 0.105100 +vn 0.840100 0.098500 0.533400 +vn 0.866000 0.025100 0.499400 +vn 0.863100 0.042500 0.503200 +vn 0.830500 -0.537200 -0.147200 +vn 0.847900 -0.085000 -0.523300 +vn 0.837300 -0.131600 0.530600 +vn 0.800700 0.580900 -0.146400 +vn 0.830500 -0.490000 0.265000 +vn 0.873300 0.477200 0.098500 +vn 0.842700 0.094800 0.530000 +vn 0.882100 0.465900 -0.069500 +vn 0.864200 0.036800 0.501700 +vn 0.876100 -0.479900 -0.046600 +vn 0.845900 -0.089100 -0.525900 +vn 0.833900 -0.106500 -0.541600 +vn 0.838700 0.103300 -0.534600 +vn 0.786700 -0.602900 0.132800 +vn 0.844300 0.515900 0.144800 +vn 0.808500 0.565200 0.164200 +vn 0.880100 0.468600 -0.076000 +vn 0.856200 0.050600 -0.514100 +vn 0.874900 -0.481200 -0.055300 +vn 0.853100 -0.102700 0.511500 +vn 0.831100 -0.109400 -0.545300 +vn 0.841000 0.099000 -0.531900 +vn 0.849100 -0.512300 -0.128500 +vn 0.848200 0.510600 0.141000 +vn 0.813400 0.558400 0.162700 +vn 0.849100 -0.112200 0.516100 +vn 0.857300 0.044300 -0.512900 +vn 0.826700 0.545200 -0.138700 +vn 0.851200 -0.107600 0.513700 +vn 0.875600 0.474200 0.091500 +vn 0.845100 0.091000 0.526800 +vn 0.845700 -0.516800 -0.132900 +vn 0.857400 0.063900 0.510600 +vn 0.854700 -0.066900 -0.514700 +vn 0.847000 -0.116600 0.518700 +vn 0.836100 0.532000 -0.134000 +vn 0.821800 0.552100 -0.140700 +vn 0.885400 0.461400 -0.055700 +vn 0.877900 0.471500 0.084100 +vn 0.847500 0.086900 0.523700 +vn 0.878900 -0.476900 -0.009900 +vn 0.859100 0.058700 0.508500 +vn 0.853200 -0.071700 -0.516600 +vn 0.843700 -0.092900 -0.528700 +vn 0.831500 0.538500 -0.136500 +vn 0.847300 0.220100 -0.483300 +vn 0.883900 0.463500 -0.062700 +vn 0.851900 0.505600 0.137000 +vn 0.818300 0.551900 0.160900 +vn 0.878500 -0.477300 -0.019200 +vn 0.850600 0.074100 -0.520600 +vn 0.859700 -0.080800 0.504300 +vn 0.841400 -0.096600 -0.531600 +vn 0.879000 -0.476800 0.003500 +vn 0.831400 0.114900 -0.543600 +vn 0.861900 0.001400 -0.507100 +vn 0.855400 0.500700 0.132600 +vn 0.823000 0.545400 0.158900 +vn 0.852100 0.068500 -0.518800 +vn 0.858300 -0.086600 0.505900 +vn 0.865100 0.487800 0.117200 +vn 0.879100 -0.476600 -0.001400 +vn 0.853000 0.214300 0.475900 +vn 0.862100 -0.005600 -0.506800 +vn 0.860500 0.053500 0.506600 +vn 0.851600 -0.076300 -0.518600 +vn 0.852900 0.507700 -0.121300 +vn 0.889200 0.456700 -0.025500 +vn 0.868000 0.484000 0.111300 +vn 0.837400 0.102000 0.537000 +vn 0.847000 -0.522200 0.098900 +vn 0.861900 0.048000 0.504800 +vn 0.889300 0.457300 0.006300 +vn 0.849800 -0.080700 -0.520900 +vn 0.849000 0.513400 -0.124900 +vn 0.836200 0.527100 0.151300 +vn 0.888600 0.457400 -0.033300 +vn 0.840500 0.460100 0.286200 +vn 0.850600 -0.517200 0.094600 +vn 0.853600 0.062700 -0.517100 +vn 0.889600 0.456700 -0.000700 +vn 0.856700 -0.092200 0.507600 +vn 0.876400 -0.480600 0.030300 +vn 0.840300 0.521400 0.148200 +vn 0.860000 0.024500 -0.509800 +vn 0.803400 0.572000 0.165400 +vn 0.787700 -0.594400 -0.162000 +vn 0.855000 0.056700 -0.515600 +vn 0.864500 -0.055500 0.499500 +vn 0.854900 -0.097600 0.509500 +vn 0.877400 -0.479200 0.023100 +vn 0.853800 0.073600 0.515400 +vn 0.860600 0.017600 -0.509000 +vn 0.828000 -0.481600 -0.287300 +vn 0.857300 -0.056900 -0.511600 +vn 0.863500 -0.062100 0.500500 +vn 0.844900 0.519400 -0.128200 +vn 0.887800 0.458400 -0.041000 +vn 0.831100 -0.544400 0.113500 +vn 0.855700 0.068800 0.512900 +vn 0.886100 0.461600 0.041900 +vn 0.855400 -0.504200 -0.118600 +vn 0.856100 -0.062000 -0.513100 +vn 0.001400 0.997700 0.067400 +vn 0.001000 0.997100 -0.075700 +vn 0.000500 0.996900 -0.078200 +vn 0.000000 0.996900 0.078200 +vn 0.000000 -0.996600 -0.082900 +vn 0.000000 0.997000 0.077500 +vn 0.003300 0.998200 -0.060000 +vn 0.002700 0.997900 -0.064800 +vn 0.000000 0.997300 0.073600 +vn 0.000100 0.997100 0.076600 +vn 0.004400 0.998800 -0.048600 +vn 0.000500 0.997200 0.074600 +vn 0.003900 0.998500 -0.054600 +vn 0.005500 0.999800 -0.020100 +vn 0.005100 0.999900 0.014800 +vn 0.005400 0.999600 -0.027800 +vn 0.005300 1.000000 0.004100 +vn 0.005200 0.999400 -0.035200 +vn 0.003300 0.998800 0.049300 +vn 0.004800 0.999100 -0.042100 +vn 0.003900 0.999100 0.041600 +vn 0.005400 1.000000 -0.004000 +vn 0.004400 0.999400 0.033200 +vn 0.005500 0.999900 -0.012100 +vn 0.000200 0.996800 -0.080200 +vn 0.004800 0.999700 0.024300 +vn 0.000000 0.996700 -0.081700 +vn 0.002000 0.998100 0.062300 +vn 0.002100 0.997600 -0.069100 +vn 0.002700 0.998400 0.056300 +vn 0.001500 0.997400 -0.072700 +vn 0.000900 0.997400 0.071600 +vn 0.995600 -0.077800 0.052300 +vn -0.997200 0.074800 -0.009000 +vn -0.990500 0.098900 0.095300 +vn 0.995100 -0.080200 0.058200 +vn 0.995100 -0.075800 -0.063900 +vn -0.991300 0.096300 0.090100 +vn 0.995600 -0.073800 -0.058200 +vn -0.996200 0.077600 0.040100 +vn -0.997000 0.075700 -0.015200 +vn -0.996500 0.076400 0.034100 +vn 0.994500 -0.082800 0.064100 +vn -0.996800 0.076900 -0.021400 +vn 0.993900 -0.085500 0.069900 +vn 0.992700 -0.085200 -0.085900 +vn 0.993300 -0.082600 -0.080500 +vn -0.996800 0.075400 0.028100 +vn 1.000000 0.002800 -0.004800 +vn 0.996500 -0.073500 0.040200 +vn -0.981600 0.141200 -0.128700 +vn 0.997200 -0.069900 0.027900 +vn 0.996100 -0.075500 0.046300 +vn 0.996900 -0.071600 0.034100 +vn 0.993900 -0.080200 -0.075100 +vn -1.000000 0.007900 0.005100 +vn 0.994500 -0.077900 -0.069600 +vn -0.983300 -0.122900 -0.134000 +vn -0.995400 0.080600 0.051800 +vn -0.995800 0.079000 0.046000 +vn 0.997900 -0.065500 0.002900 +vn 0.997800 -0.066200 0.009200 +vn 0.991200 -0.090500 -0.096300 +vn 0.999900 0.000100 -0.011500 +vn 0.992000 -0.087800 -0.091200 +vn 0.997600 -0.067200 0.015500 +vn 0.997400 -0.068400 0.021700 +vn -0.996900 -0.071200 0.032600 +vn 0.996900 -0.076300 -0.016500 +vn 0.997400 -0.066700 -0.028400 +vn 0.997900 -0.065100 -0.003300 +vn 0.997900 -0.065200 -0.000200 +vn -0.988900 0.105000 0.105000 +vn -0.989700 0.101800 0.100300 +vn 0.052200 0.996500 -0.065000 +vn 0.002500 0.994300 0.107000 +vn 0.004600 0.993600 0.113100 +vn 0.014200 0.992200 0.123900 +vn 0.013100 0.996300 -0.085300 +vn 0.058600 0.998000 -0.022500 +vn 0.018100 0.992000 0.124900 +vn 0.057600 0.998200 0.015000 +vn 0.009600 0.996300 -0.084800 +vn 0.058100 0.997800 -0.032100 +vn 0.058300 0.998300 0.005000 +vn 0.000000 0.996600 0.082900 +vn 0.006500 0.996400 -0.084100 +vn 0.057200 0.997500 -0.041300 +vn 0.050800 0.996000 0.072900 +vn 0.003900 0.996500 -0.083200 +vn 0.055900 0.997200 -0.050000 +vn 0.053100 0.996700 0.061100 +vn 0.021100 0.996200 -0.085100 +vn 0.058500 0.998300 -0.004200 +vn 0.055000 0.997300 0.048500 +vn 0.017000 0.996200 -0.085400 +vn 0.058600 0.998200 -0.012600 +vn 0.029500 0.995800 -0.086200 +vn 0.056500 0.997800 0.035200 +vn 0.025400 0.996100 -0.084900 +vn 0.045200 0.994600 0.093400 +vn 0.000000 0.926600 -0.376100 +vn 0.044100 0.995800 -0.080600 +vn 0.048200 0.995300 0.083700 +vn 0.040800 0.995700 -0.083700 +vn 0.038500 0.993300 0.109100 +vn 0.042000 0.993900 0.101900 +vn 0.037200 0.995600 -0.085600 +vn 0.007400 0.993000 0.118000 +vn 0.033500 0.995700 -0.086500 +vn 0.010600 0.992500 0.121600 +vn 0.022300 0.992000 0.124500 +vn 0.026600 0.992100 0.122700 +vn 0.049800 0.996200 -0.071200 +vn 0.000100 0.995800 0.091400 +vn 0.047100 0.996000 -0.076400 +vn 0.000900 0.995000 0.099800 +vn 0.030700 0.992300 0.119600 +vn 0.000000 -0.996500 -0.083800 +vn 0.001900 0.996600 -0.082100 +vn 0.054300 0.996800 -0.057900 +vn 0.034700 0.992800 0.115000 +vn 0.000600 0.996700 -0.080900 +vn 0.041900 0.998900 -0.019700 +vn -0.000200 -0.997400 0.072100 +vn 0.000400 0.055700 0.998400 +vn 0.040700 0.999100 0.013900 +vn -0.000100 0.038900 0.999200 +vn 0.000600 -0.046300 -0.998900 +vn -0.000300 0.997400 -0.071900 +vn 0.041600 0.998700 -0.028300 +vn -0.000100 0.997600 0.069100 +vn -0.000300 -0.997400 0.071700 +vn 0.041400 0.999100 0.004600 +vn 0.000300 0.041600 -0.999100 +vn -0.001100 -0.999300 0.036900 +vn 0.000300 0.998200 0.060000 +vn -0.000000 -0.026100 0.999700 +vn 0.000300 0.038900 -0.999200 +vn 0.000200 -0.046200 0.998900 +vn 0.000300 -0.033000 -0.999500 +vn -0.000200 0.997400 -0.071600 +vn 0.040900 0.998500 -0.036600 +vn 0.033500 0.998400 0.046500 +vn -0.000100 -0.997600 -0.069700 +vn 0.000400 -0.036200 -0.999300 +vn 0.000300 -0.026200 -0.999700 +vn -0.000100 0.997500 -0.071000 +vn 0.039700 0.998200 -0.044400 +vn 0.000000 -0.997400 0.071800 +vn 0.035900 0.998600 0.039200 +vn 0.000300 -0.029700 -0.999600 +vn -0.001200 -0.999700 0.024400 +vn -0.000100 -0.010500 0.999900 +vn -0.000800 -0.998400 0.056600 +vn 0.000100 -0.036000 0.999400 +vn 0.000600 -0.997900 -0.064600 +vn 0.003400 0.997400 -0.072400 +vn -0.000100 -0.014600 0.999900 +vn -0.000900 -0.998600 0.052400 +vn 0.041700 0.999100 -0.003600 +vn 0.037900 0.998800 0.031300 +vn -0.000500 -0.998200 -0.060200 +vn -0.000500 0.997400 -0.071900 +vn 0.000200 -0.010500 -0.999900 +vn 0.041800 0.999100 -0.010700 +vn 0.012600 0.997000 -0.076300 +vn -0.000100 -0.997400 0.072300 +vn 0.039500 0.999000 0.022800 +vn -0.000400 -0.998000 -0.063300 +vn -0.001000 -0.998900 0.047700 +vn 0.000200 -0.014600 -0.999900 +vn 0.000200 0.029600 -0.999600 +vn 0.000200 -0.997700 0.068300 +vn 0.008100 0.997200 -0.074800 +vn -0.000100 -0.018500 0.999800 +vn -0.000500 -0.997700 0.068000 +vn 0.000400 -0.997500 -0.070500 +vn -0.000600 -0.997800 0.065900 +vn 0.027700 0.997900 0.058800 +vn -0.000300 -0.997800 -0.065900 +vn 0.000100 -0.997500 0.070300 +vn 0.028000 0.997000 -0.071800 +vn -0.000800 -0.999100 -0.042500 +vn 0.030800 0.998100 0.053100 +vn 0.000800 -0.055900 -0.998400 +vn -0.000200 -0.997700 -0.068100 +vn 0.000500 0.052500 -0.998600 +vn 0.000500 -0.997700 -0.068400 +vn 0.024600 0.996900 -0.074500 +vn -0.000700 -0.998000 0.063300 +vn 0.000200 -0.997400 -0.072400 +vn 0.000500 -0.053600 0.998600 +vn 0.000200 0.997800 -0.065800 +vn 0.020400 0.997500 0.067400 +vn -0.000800 -0.998200 0.060200 +vn 0.000100 0.052400 0.998600 +vn -0.000700 -0.998600 -0.052400 +vn 0.000200 -0.002100 -1.000000 +vn 0.024200 0.997700 0.063600 +vn 0.000100 0.051100 0.998700 +vn 0.020900 0.996900 -0.076200 +vn -0.000600 -0.998400 -0.056500 +vn -0.000600 0.997400 0.071700 +vn 0.000300 -0.997800 0.065800 +vn 0.016900 0.996900 -0.076800 +vn -0.001000 -0.999700 -0.024300 +vn -0.000300 -0.997500 0.070900 +vn 0.000600 0.055000 -0.998500 +vn -0.000100 0.029600 0.999600 +vn -0.000700 0.997500 0.071200 +vn 0.000300 -0.997400 -0.071900 +vn -0.000000 0.997700 0.068000 +vn 0.000600 -0.055100 0.998500 +vn 0.000300 0.998000 -0.063000 +vn -0.000400 -0.997600 0.069600 +vn 0.002600 0.997400 0.071900 +vn -0.000100 0.026100 0.999700 +vn 0.000600 -0.055600 0.998500 +vn 0.007400 0.997300 0.072500 +vn 0.000200 0.054900 0.998500 +vn 0.033800 0.997400 -0.063400 +vn 0.000400 -0.998200 0.060100 +vn -0.000200 0.997500 0.070800 +vn 0.031000 0.997200 -0.068100 +vn 0.000300 0.036100 -0.999300 +vn -0.000900 -0.999300 -0.036800 +vn 0.000400 0.053500 -0.998600 +vn 0.000000 -0.997400 -0.071800 +vn -0.000300 0.997400 0.071400 +vn 0.000200 0.998000 0.062900 +vn 0.000400 -0.051300 0.998700 +vn 0.000200 0.033000 -0.999500 +vn 0.000100 0.997700 -0.068200 +vn 0.012000 0.997300 0.071900 +vn 0.000400 -0.049800 0.998800 +vn 0.000200 0.054300 0.998500 +vn 0.000100 -0.997400 -0.072300 +vn 0.000000 0.046100 0.998900 +vn 0.000400 -0.039000 -0.999200 +vn 0.016400 0.997400 0.070200 +vn 0.038100 0.997900 -0.051500 +vn 0.000000 0.997600 -0.069300 +vn -0.000400 0.997400 0.071800 +vn 0.036100 0.997700 -0.057900 +vn -0.001100 -0.999900 -0.010600 +vn 0.000400 0.046100 -0.998900 +vn 0.000600 -0.052600 -0.998600 +vn -0.000500 0.997400 0.071900 +vn 0.000100 0.997800 0.065600 +vn -0.000800 0.997500 0.070400 +vn 0.000200 -0.041600 0.999100 +vn -0.000400 0.997400 -0.072100 +vn -0.997200 0.073800 0.009600 +vn -0.997200 0.074100 -0.002800 +vn -0.997100 0.074100 0.015900 +vn -0.993900 0.086500 0.068700 +vn 0.992500 -0.091600 0.081100 +vn -0.993300 0.088800 0.074200 +vn -0.996200 0.079900 -0.033700 +vn -0.995400 0.083800 -0.045900 +vn 0.993200 -0.088400 0.075700 +vn -0.996500 0.078300 -0.027600 +vn -0.995900 0.081800 -0.039800 +vn -0.993700 0.105400 0.037800 +vn 0.986500 -0.117500 0.114200 +vn -0.992600 0.091200 0.079600 +vn -0.992000 0.093700 0.084900 +vn -0.993200 0.093500 -0.069600 +vn -0.993800 0.090800 -0.063800 +vn 0.990500 -0.093500 -0.101100 +vn -0.994900 0.082400 0.057500 +vn -0.984600 0.121800 0.125400 +vn -0.994400 0.084400 0.063200 +vn -0.994400 0.088300 -0.057900 +vn -0.994900 0.085900 -0.051900 +vn 0.981200 -0.130600 -0.142400 +vn -0.992500 0.096600 -0.075100 +vn 0.996400 -0.070300 -0.046500 +vn 0.998600 0.036600 -0.038200 +vn 0.996000 -0.071900 -0.052400 +vn -0.987500 -0.104600 -0.118300 +vn -0.117000 -0.989000 -0.090100 +vn -0.748800 0.022500 -0.662400 +vn -0.802100 0.594300 0.058500 +vn -0.772800 0.630800 0.069900 +vn -0.508200 -0.861100 -0.016200 +vn -0.816500 0.576100 0.036100 +vn -0.329800 -0.936000 -0.123100 +vn -0.410800 -0.911100 -0.034600 +vn -0.743100 0.099400 0.661700 +vn -0.724200 0.117100 0.679600 +vn -0.496900 -0.865400 -0.064700 +vn -0.761800 0.643100 0.078200 +vn -0.763300 0.006800 -0.646000 +vn -0.222500 -0.974300 -0.034900 +vn -0.807300 0.589800 0.017400 +vn -0.761700 0.061400 0.645100 +vn -0.398400 -0.916500 -0.035000 +vn -0.738800 0.104400 0.665800 +vn -0.718900 0.120600 0.684500 +vn -0.506000 -0.860900 -0.053300 +vn -0.765100 0.007900 -0.643900 +vn -0.759900 0.645000 0.080900 +vn -0.444100 -0.846300 -0.294200 +vn -0.809300 0.587100 0.019400 +vn -0.759600 0.068700 0.646700 +vn -0.522800 -0.852500 0.001300 +vn -0.814800 0.578300 0.040800 +vn -0.245800 -0.962100 -0.117600 +vn -0.738600 0.026700 -0.673600 +vn -0.816500 0.577000 0.020800 +vn -0.797300 0.181200 -0.575800 +vn -0.434100 -0.900200 -0.033400 +vn -0.785800 0.618100 -0.020900 +vn -0.764800 0.014200 -0.644200 +vn -0.521500 -0.853200 -0.002400 +vn -0.812700 0.580900 0.045200 +vn -0.262100 -0.957600 -0.119600 +vn -0.734800 0.028100 -0.677700 +vn -0.817400 0.575700 0.019700 +vn -0.693600 -0.019500 -0.720100 +vn -0.422700 -0.905600 -0.034100 +vn -0.789100 0.614100 -0.013900 +vn -0.763200 0.015300 -0.646000 +vn -0.766500 0.008900 -0.642100 +vn -0.276800 -0.960300 -0.035000 +vn -0.797900 0.602800 0.003200 +vn -0.764900 0.029700 0.643500 +vn -0.773700 0.132000 0.619600 +vn -0.446300 -0.889200 -0.100400 +vn -0.711000 -0.075100 0.699200 +vn -0.759300 -0.004400 0.650800 +vn -0.767200 0.007800 -0.641400 +vn -0.263100 -0.964100 -0.034900 +vn -0.800500 0.599300 0.007700 +vn -0.764900 0.038000 0.643100 +vn -0.623700 -0.118900 0.772600 +vn -0.460700 -0.882600 -0.093100 +vn -0.717800 -0.069000 0.692900 +vn -0.761500 0.004200 0.648100 +vn -0.818200 0.574700 0.018200 +vn -0.474000 -0.880100 -0.028400 +vn -0.773000 0.632400 -0.049300 +vn -0.768300 0.010400 -0.640000 +vn -0.823200 0.553300 0.127100 +vn -0.184500 -0.977000 -0.106800 +vn -0.747000 -0.001100 -0.664900 +vn -0.786700 0.613700 0.066000 +vn -0.818800 0.573900 0.016400 +vn -0.465000 -0.884800 -0.030000 +vn -0.775300 0.629900 -0.044900 +vn -0.767800 0.011300 -0.640600 +vn -0.757400 0.649000 -0.072300 +vn -0.750400 0.000400 -0.661000 +vn -0.199200 -0.973800 -0.109800 +vn -0.783800 0.617500 0.066800 +vn -0.764300 0.046100 0.643200 +vn -0.681200 -0.096100 0.725800 +vn -0.381600 -0.916700 -0.118900 +vn -0.761400 0.016300 -0.648100 +vn -0.746100 -0.033200 0.665000 +vn -0.770400 0.633600 0.071000 +vn -0.332200 -0.942600 -0.035300 +vn -0.703600 0.038000 0.709600 +vn -0.746800 0.657400 0.100300 +vn -0.763200 0.053900 0.643900 +vn -0.689000 -0.091400 0.719000 +vn -0.398500 -0.909800 -0.115800 +vn -0.759400 0.017500 -0.650400 +vn -0.750400 -0.025200 0.660500 +vn -0.768000 0.636300 0.072400 +vn -0.318400 -0.947300 -0.035300 +vn -0.707900 -0.142400 0.691800 +vn -0.817200 0.569100 -0.091600 +vn -0.767100 0.012200 -0.641400 +vn -0.730700 -0.007500 -0.682700 +vn -0.129700 -0.987100 -0.093600 +vn -0.757100 0.075600 0.648900 +vn -0.799100 0.598200 0.060700 +vn -0.513300 -0.857200 -0.041000 +vn -0.502900 -0.864100 -0.019200 +vn -0.701100 0.130700 -0.701000 +vn -0.721100 -0.010900 -0.692800 +vn -0.766000 0.013200 -0.642700 +vn -0.735100 -0.005800 -0.677900 +vn -0.142800 -0.985000 -0.097000 +vn -0.754200 0.082100 0.651500 +vn -0.796000 0.602100 0.062500 +vn -0.518700 -0.854500 -0.028000 +vn -0.496800 -0.867600 -0.021900 +vn -0.712300 -0.206600 -0.670800 +vn -0.726000 -0.009200 -0.687600 +vn -0.754300 -0.017000 0.656300 +vn -0.780900 0.621000 0.067500 +vn -0.385700 -0.922000 -0.035200 +vn -0.819500 0.573000 0.011100 +vn -0.713500 0.123700 0.689700 +vn -0.278700 -0.952700 -0.121200 +vn -0.757800 0.647100 0.084000 +vn -0.811100 0.584600 0.020700 +vn -0.665200 -0.104400 0.739400 +vn -0.757000 -0.010800 0.653300 +vn -0.778100 0.624500 0.068200 +vn -0.372600 -0.927300 -0.035400 +vn -0.819000 0.573400 0.022800 +vn -0.707900 0.126500 0.694900 +vn -0.295500 -0.947500 -0.122400 +vn -0.755500 0.649300 0.087400 +vn -0.812700 0.582300 0.021600 +vn -0.673200 -0.100400 0.732600 +vn -0.792900 0.606000 0.063900 +vn -0.474100 -0.876400 -0.084700 +vn -0.519400 -0.854500 -0.006100 +vn -0.759000 0.004400 -0.651100 +vn -0.730800 0.029600 -0.682000 +vn -0.699500 -0.017800 -0.714500 +vn -0.249400 -0.967800 -0.034900 +vn -0.792200 0.610200 -0.007600 +vn -0.768900 0.636900 -0.056500 +vn -0.789800 0.609900 0.065100 +vn -0.486200 -0.870600 -0.075200 +vn -0.516500 -0.856200 -0.009600 +vn -0.726600 0.031000 -0.686300 +vn -0.761300 0.005600 -0.648400 +vn -0.705100 -0.016100 -0.708900 +vn -0.235900 -0.971200 -0.034900 +vn -0.795100 0.606500 -0.001900 +vn -0.771000 0.634700 -0.052900 +vn -0.702100 0.128900 0.700300 +vn -0.214400 -0.970200 -0.112700 +vn -0.752900 0.651800 0.091300 +vn -0.802900 0.595900 0.011500 +vn -0.814100 0.580300 0.021800 +vn -0.632000 -0.116700 0.766100 +vn -0.455300 -0.889800 -0.031400 +vn -0.724200 -0.062400 0.686700 +vn -0.745600 0.023900 -0.665900 +vn -0.708300 0.036600 0.705000 +vn -0.229900 -0.966400 -0.115300 +vn -0.750000 0.654500 0.095600 +vn -0.805200 0.592800 0.014800 +vn -0.815400 0.578500 0.021600 +vn -0.640400 -0.114100 0.759500 +vn -0.445000 -0.894900 -0.032500 +vn -0.730300 -0.055600 0.680900 +vn -0.742200 0.025300 -0.669700 +vn -0.712800 0.126700 -0.689800 +vn -0.304500 -0.951900 -0.035200 +vn -0.710600 -0.014400 -0.703400 +vn -0.778900 0.626100 -0.036700 +vn -0.763200 0.012800 0.646000 +vn -0.759900 0.646400 -0.069400 +vn -0.415000 -0.902900 -0.111700 +vn -0.753500 0.001800 -0.657400 +vn -0.734200 0.109000 0.670200 +vn -0.707000 0.128800 -0.695400 +vn -0.290700 -0.956200 -0.035100 +vn -0.716000 -0.012600 -0.698000 +vn -0.782400 0.622100 -0.028500 +vn -0.764300 0.021300 0.644500 +vn -0.762200 0.643900 -0.066400 +vn -0.431000 -0.896000 -0.106600 +vn -0.756400 0.003100 -0.654100 +vn -0.729300 0.113200 0.674800 +vn -0.490000 -0.871400 -0.024400 +vn -0.648700 -0.111200 0.752900 +vn -0.696500 -0.086400 0.712300 +vn -0.768500 0.008600 -0.639800 +vn -0.156300 -0.982600 -0.100400 +vn -0.757100 0.018700 -0.653100 +vn -0.765800 0.638700 0.074000 +vn -0.810400 0.583800 0.049200 +vn -0.482300 -0.875600 -0.026500 +vn -0.657000 -0.108000 0.746200 +vn -0.768600 0.009500 -0.639700 +vn -0.703900 -0.080900 0.705700 +vn -0.170200 -0.979900 -0.103700 +vn -0.754600 0.019900 -0.655900 +vn -0.763800 0.641000 0.075900 +vn -0.807800 0.587100 0.052800 +vn -0.347100 -0.929800 -0.122400 +vn -0.764500 0.641500 -0.063200 +vn -0.736000 -0.048400 0.675200 +vn -0.739300 -0.004200 -0.673300 +vn -0.359300 -0.932500 -0.035400 +vn -0.750800 0.088300 0.654600 +vn -0.522000 -0.852800 -0.016100 +vn -0.767600 0.006800 -0.640900 +vn -0.364400 -0.923300 -0.121100 +vn -0.766700 0.639200 -0.059900 +vn -0.741300 -0.040900 0.669900 +vn -0.743300 -0.002600 -0.669000 +vn -0.345800 -0.937600 -0.035400 +vn -0.747100 0.094000 0.658000 +vn -0.523300 -0.852200 -0.003900 +vn -0.768200 0.007700 -0.640200 +vn -0.363800 -0.910800 0.195200 +vn -0.751800 0.021200 -0.659100 +vn -0.805000 0.590600 0.055900 +vn -0.775400 0.627700 0.069000 +vn -0.512800 -0.858400 -0.013000 +vn -0.817900 0.574500 0.031200 +vn -0.312600 -0.941900 -0.123000 +vn -0.819200 0.573400 0.011600 +vn 0.986800 -0.093200 -0.132500 +vn 0.986500 -0.097900 -0.131200 +vn 0.986400 -0.095300 -0.133700 +vn 0.986700 -0.090700 -0.135000 +vn 0.984000 -0.082900 -0.157600 +vn 0.983900 -0.087100 -0.156300 +vn 0.983900 -0.084400 -0.157300 +vn 0.984100 -0.080300 -0.158700 +vn 0.996600 -0.061800 -0.054600 +vn 0.996200 -0.068400 -0.054000 +vn 0.995900 -0.067200 -0.060100 +vn 0.996300 -0.060700 -0.060700 +vn 0.988500 -0.144800 -0.044600 +vn 0.987900 -0.148500 -0.043900 +vn 0.987900 -0.147100 -0.048800 +vn 0.988400 -0.143500 -0.049500 +vn 0.992800 -0.109200 -0.049800 +vn 0.992200 -0.114300 -0.049200 +vn 0.992100 -0.113000 -0.054700 +vn 0.992600 -0.107900 -0.055400 +vn 0.990100 -0.102400 -0.096200 +vn 0.989600 -0.107400 -0.095200 +vn 0.989500 -0.105300 -0.099200 +vn 0.989900 -0.100300 -0.100300 +vn 0.985100 -0.045000 -0.165800 +vn 0.985000 -0.050100 -0.165000 +vn 0.984800 -0.048400 -0.166600 +vn 0.984900 -0.043500 -0.167500 +vn 0.998000 -0.063800 -0.000000 +vn 0.997500 -0.070400 0.000000 +vn 0.997500 -0.070400 -0.003700 +vn 0.998000 -0.063800 -0.003700 +vn 0.998400 -0.003800 -0.057000 +vn 0.998300 -0.011400 -0.057000 +vn 0.997900 -0.011200 -0.063600 +vn 0.998000 -0.003700 -0.063800 +vn 0.989100 -0.147100 -0.000000 +vn 0.988600 -0.150700 -0.000000 +vn 0.988600 -0.150700 -0.002900 +vn 0.989100 -0.147000 -0.003000 +vn 0.986700 -0.137400 0.087200 +vn 0.986500 -0.139900 0.084800 +vn 0.986800 -0.141100 0.080000 +vn 0.986900 -0.138600 0.082300 +vn 0.994300 -0.003400 -0.106100 +vn 0.994300 -0.010300 -0.106100 +vn 0.993700 -0.010100 -0.111300 +vn 0.993800 -0.003400 -0.111400 +vn 0.998700 0.050000 0.000000 +vn 0.999100 0.042800 0.000000 +vn 0.999100 0.042800 -0.003900 +vn 0.998700 0.050000 -0.003800 +vn 0.993600 0.043400 0.104000 +vn 0.993800 0.036900 0.104500 +vn 0.994300 0.037900 0.099500 +vn 0.994100 0.044500 0.099000 +vn 0.993000 -0.056800 0.103300 +vn 0.992800 -0.062300 0.101900 +vn 0.993300 -0.063100 0.096400 +vn 0.993500 -0.057500 0.097800 +vn 0.985500 0.034100 -0.166500 +vn 0.985400 0.029500 -0.167500 +vn 0.985000 0.029000 -0.169900 +vn 0.985100 0.033500 -0.168900 +vn 0.993600 0.043400 -0.104000 +vn 0.993800 0.037400 -0.105000 +vn 0.993200 0.036900 -0.110300 +vn 0.993100 0.042900 -0.109200 +vn 0.993000 -0.056800 -0.103300 +vn 0.992700 -0.063000 -0.102600 +vn 0.992300 -0.061500 -0.107100 +vn 0.992600 -0.055400 -0.107900 +vn 0.982900 -0.113300 -0.145400 +vn 0.982700 -0.116500 -0.143700 +vn 0.982900 -0.114700 -0.144000 +vn 0.983200 -0.109900 -0.146000 +vn 0.986700 -0.137400 -0.087200 +vn 0.986300 -0.141000 -0.086000 +vn 0.986300 -0.138600 -0.089500 +vn 0.986700 -0.135000 -0.090700 +vn 0.984500 -0.126400 -0.121300 +vn 0.984300 -0.129900 -0.119800 +vn 0.984400 -0.126800 -0.121800 +vn 0.984700 -0.123400 -0.123400 +vn 0.991100 0.091000 -0.097300 +vn 0.991300 0.086500 -0.099200 +vn 0.990900 0.085500 -0.104400 +vn 0.990700 0.090000 -0.102500 +vn 0.993900 0.097900 -0.050500 +vn 0.994300 0.092800 -0.051700 +vn 0.994000 0.092200 -0.058200 +vn 0.993600 0.097200 -0.056800 +vn 0.997300 0.047700 -0.055100 +vn 0.997600 0.041100 -0.055900 +vn 0.997200 0.040700 -0.062700 +vn 0.997000 0.047200 -0.061800 +vn 0.984600 0.072900 -0.159000 +vn 0.984500 0.069400 -0.161200 +vn 0.984200 0.068300 -0.163600 +vn 0.984300 0.071700 -0.161300 +vn 0.987600 0.082300 -0.133700 +vn 0.987600 0.078300 -0.135900 +vn 0.987200 0.077200 -0.139700 +vn 0.987200 0.081200 -0.137500 +vn 0.989200 0.038800 -0.141100 +vn 0.989300 0.033400 -0.142100 +vn 0.988700 0.032900 -0.145900 +vn 0.988700 0.038200 -0.144900 +vn 0.994300 -0.003400 0.106100 +vn 0.994300 -0.010200 0.106000 +vn 0.994900 -0.010300 0.100500 +vn 0.994900 -0.003500 0.100700 +vn 0.989700 -0.003100 0.143300 +vn 0.989700 -0.009100 0.143100 +vn 0.990200 -0.009200 0.139100 +vn 0.990200 -0.003100 0.139300 +vn 0.988800 -0.051000 0.140300 +vn 0.988700 -0.055900 0.138800 +vn 0.989200 -0.056700 0.134800 +vn 0.989300 -0.051700 0.136400 +vn 0.991100 0.091000 0.097300 +vn 0.991500 0.085600 0.098300 +vn 0.991700 0.087400 0.093800 +vn 0.991300 0.092900 0.092900 +vn 0.987600 0.082300 0.133700 +vn 0.987800 0.077300 0.134900 +vn 0.988100 0.079400 0.131900 +vn 0.987800 0.084500 0.130900 +vn 0.989200 0.038800 0.141100 +vn 0.989400 0.033000 0.141600 +vn 0.989800 0.033900 0.138100 +vn 0.989700 0.040000 0.137600 +vn 0.994900 0.100700 0.000000 +vn 0.995500 0.095000 0.000000 +vn 0.995500 0.095000 -0.003500 +vn 0.994900 0.100600 -0.003400 +vn 0.993900 0.097900 0.050500 +vn 0.994400 0.092200 0.051100 +vn 0.994600 0.093400 0.045100 +vn 0.994100 0.099000 0.044500 +vn 0.997300 0.047700 0.055100 +vn 0.997600 0.040700 0.055500 +vn 0.997900 0.041500 0.049000 +vn 0.997600 0.048600 0.048600 +vn 0.990100 -0.102400 0.096200 +vn 0.989900 -0.106400 0.094200 +vn 0.990200 -0.107500 0.089000 +vn 0.990500 -0.103400 0.091000 +vn 0.986800 -0.093200 0.132500 +vn 0.986800 -0.096600 0.130000 +vn 0.987200 -0.097900 0.126100 +vn 0.987200 -0.094400 0.128500 +vn 0.984500 -0.126400 0.121300 +vn 0.984600 -0.128400 0.118300 +vn 0.984900 -0.130000 0.114600 +vn 0.984800 -0.128000 0.117600 +vn 0.993800 -0.111400 0.000000 +vn 0.993200 -0.116500 0.000000 +vn 0.993200 -0.116500 -0.003300 +vn 0.993800 -0.111400 -0.003400 +vn 0.992800 -0.109200 0.049800 +vn 0.992300 -0.113700 0.048600 +vn 0.992500 -0.114300 0.042300 +vn 0.993000 -0.109800 0.043400 +vn 0.988500 -0.144800 0.044600 +vn 0.988100 -0.147800 0.043300 +vn 0.988200 -0.148500 0.037600 +vn 0.988600 -0.145400 0.038800 +vn 1.000000 -0.004100 0.000000 +vn 0.999900 -0.012200 -0.000000 +vn 0.999900 -0.012200 -0.004100 +vn 1.000000 -0.004100 -0.004100 +vn 0.998400 -0.003800 0.057000 +vn 0.998300 -0.011300 0.056800 +vn 0.998700 -0.011400 0.049800 +vn 0.998700 -0.003900 0.050000 +vn 0.996600 -0.061800 0.054600 +vn 0.996300 -0.067800 0.053500 +vn 0.996600 -0.068400 0.046700 +vn 0.996900 -0.062300 0.047700 +vn 0.985700 -0.002700 -0.168700 +vn 0.985600 -0.008100 -0.168600 +vn 0.985300 -0.007800 -0.170900 +vn 0.985300 -0.002600 -0.171000 +vn 0.989700 -0.003100 -0.143300 +vn 0.989600 -0.009200 -0.143200 +vn 0.989100 -0.008900 -0.146900 +vn 0.989100 -0.003000 -0.147000 +vn 0.988800 -0.051000 -0.140300 +vn 0.988600 -0.056700 -0.139600 +vn 0.988200 -0.055100 -0.142600 +vn 0.988400 -0.049500 -0.143500 +vn 0.989400 -0.027500 -0.142500 +vn 0.989300 -0.033400 -0.142100 +vn 0.988800 -0.032500 -0.145400 +vn 0.988900 -0.026600 -0.145900 +vn 0.991700 -0.029100 -0.125400 +vn 0.991500 -0.035400 -0.125000 +vn 0.991000 -0.034500 -0.129100 +vn 0.991200 -0.028300 -0.129600 +vn 0.990900 -0.053900 -0.123300 +vn 0.990700 -0.059900 -0.122600 +vn 0.990300 -0.058300 -0.126300 +vn 0.990500 -0.052500 -0.127100 +vn 0.989600 0.015100 -0.142900 +vn 0.989600 0.009200 -0.143200 +vn 0.989100 0.009100 -0.147000 +vn 0.989100 0.014900 -0.146700 +vn 0.991900 0.016000 -0.125800 +vn 0.992000 0.009800 -0.126100 +vn 0.991400 0.009600 -0.130700 +vn 0.991300 0.015800 -0.130300 +vn 0.992000 -0.003300 -0.126200 +vn 0.992000 -0.009800 -0.126100 +vn 0.991400 -0.009500 -0.130600 +vn 0.991400 -0.003200 -0.130700 +vn 0.985600 0.013300 -0.168300 +vn 0.985600 0.008100 -0.168700 +vn 0.985200 0.008000 -0.171000 +vn 0.985200 0.013000 -0.170700 +vn 0.987500 0.014200 -0.157000 +vn 0.987500 0.008600 -0.157400 +vn 0.987000 0.008500 -0.160500 +vn 0.987000 0.013900 -0.160100 +vn 0.987500 -0.002900 -0.157400 +vn 0.987500 -0.008600 -0.157400 +vn 0.987000 -0.008400 -0.160300 +vn 0.987000 -0.002800 -0.160500 +vn 0.997800 -0.033900 0.056300 +vn 0.997600 -0.040700 0.055500 +vn 0.998000 -0.041100 0.048600 +vn 0.998200 -0.034200 0.049300 +vn 0.996100 -0.032300 0.082300 +vn 0.995900 -0.038900 0.081500 +vn 0.996400 -0.039300 0.075300 +vn 0.996600 -0.032700 0.076100 +vn 0.995000 -0.059500 0.080400 +vn 0.994700 -0.065200 0.079100 +vn 0.995200 -0.065900 0.072900 +vn 0.995400 -0.060100 0.074200 +vn 0.998200 0.018800 0.056600 +vn 0.998300 0.011300 0.056800 +vn 0.998700 0.011600 0.050000 +vn 0.998600 0.019200 0.049800 +vn 0.996400 0.017900 0.082700 +vn 0.996500 0.010800 0.082900 +vn 0.997000 0.011000 0.076800 +vn 0.996900 0.018300 0.076700 +vn 0.996500 -0.003600 0.083100 +vn 0.996500 -0.010800 0.082900 +vn 0.997000 -0.010900 0.076700 +vn 0.997000 -0.003700 0.076900 +vn 0.999800 0.020200 0.000000 +vn 0.999900 0.012200 0.000000 +vn 0.999900 0.012200 -0.004100 +vn 0.999800 0.020100 -0.004000 +vn 0.999400 0.019700 0.027500 +vn 0.999500 0.011900 0.027700 +vn 0.999700 0.012100 0.020100 +vn 0.999600 0.020000 0.020000 +vn 0.999600 -0.004000 0.027900 +vn 0.999500 -0.011900 0.027700 +vn 0.999700 -0.012000 0.020000 +vn 0.999800 -0.004100 0.020200 +vn 0.990600 -0.128500 0.047200 +vn 0.990200 -0.132200 0.045900 +vn 0.990300 -0.132900 0.040000 +vn 0.990800 -0.129100 0.041100 +vn 0.989600 -0.125400 0.070500 +vn 0.989300 -0.128900 0.068700 +vn 0.989500 -0.129800 0.063200 +vn 0.989900 -0.126300 0.064900 +vn 0.987700 -0.141700 0.066800 +vn 0.987400 -0.144400 0.064900 +vn 0.987600 -0.145400 0.059600 +vn 0.987900 -0.142600 0.061400 +vn 0.994800 -0.087000 0.052300 +vn 0.994400 -0.092200 0.051100 +vn 0.994700 -0.092800 0.044600 +vn 0.995100 -0.087500 0.045600 +vn 0.993400 -0.084200 0.077500 +vn 0.993100 -0.089200 0.075900 +vn 0.993500 -0.090000 0.069900 +vn 0.993800 -0.085000 0.071400 +vn 0.991600 -0.106200 0.074200 +vn 0.991200 -0.110500 0.072400 +vn 0.991500 -0.111300 0.066700 +vn 0.991900 -0.107100 0.068300 +vn 0.996000 -0.089100 0.000000 +vn 0.995500 -0.095000 0.000000 +vn 0.995500 -0.094900 -0.003500 +vn 0.996000 -0.089100 -0.003500 +vn 0.995700 -0.088700 0.024900 +vn 0.995200 -0.094300 0.024300 +vn 0.995400 -0.094600 0.017400 +vn 0.995900 -0.088900 0.017900 +vn 0.993500 -0.111000 0.023700 +vn 0.993000 -0.115800 0.023000 +vn 0.993100 -0.116100 0.016500 +vn 0.993600 -0.111200 0.017000 +vn 0.985600 -0.111100 0.127200 +vn 0.985700 -0.113800 0.124400 +vn 0.986000 -0.115200 0.120600 +vn 0.986000 -0.112400 0.123300 +vn 0.984400 -0.105200 0.140900 +vn 0.984600 -0.107700 0.138000 +vn 0.984800 -0.109200 0.134800 +vn 0.984700 -0.106700 0.137700 +vn 0.983600 -0.120100 0.134700 +vn 0.983800 -0.121800 0.131400 +vn 0.984000 -0.123500 0.128400 +vn 0.983800 -0.121700 0.131600 +vn 0.987900 -0.073100 0.136900 +vn 0.987800 -0.077300 0.134900 +vn 0.988300 -0.078300 0.130900 +vn 0.988400 -0.074100 0.132900 +vn 0.986100 -0.068900 0.151000 +vn 0.986200 -0.072800 0.148900 +vn 0.986600 -0.074000 0.145700 +vn 0.986500 -0.070000 0.147800 +vn 0.985300 -0.088100 0.146400 +vn 0.985400 -0.091300 0.143900 +vn 0.985700 -0.092700 0.140700 +vn 0.985600 -0.089400 0.143200 +vn 0.991700 -0.080800 0.100100 +vn 0.991500 -0.085600 0.098300 +vn 0.991900 -0.086500 0.093000 +vn 0.992100 -0.081700 0.094700 +vn 0.989800 -0.077100 0.120000 +vn 0.989700 -0.081500 0.118000 +vn 0.990100 -0.082600 0.113300 +vn 0.990300 -0.078000 0.115300 +vn 0.988400 -0.098000 0.115700 +vn 0.988300 -0.101700 0.113400 +vn 0.988700 -0.102900 0.108800 +vn 0.988900 -0.099100 0.111100 +vn 0.995800 0.074200 0.052900 +vn 0.996300 0.067800 0.053500 +vn 0.996500 0.068900 0.047200 +vn 0.996100 0.075300 0.046700 +vn 0.994400 0.071500 0.078300 +vn 0.994700 0.065200 0.079100 +vn 0.995100 0.066600 0.073500 +vn 0.994700 0.072900 0.072900 +vn 0.995700 0.045700 0.081000 +vn 0.995900 0.038900 0.081500 +vn 0.996300 0.039800 0.075700 +vn 0.996100 0.046700 0.075300 +vn 0.991800 0.118600 0.047900 +vn 0.992300 0.113700 0.048600 +vn 0.992500 0.114900 0.042800 +vn 0.991900 0.119800 0.042300 +vn 0.990800 0.115300 0.071500 +vn 0.991200 0.110500 0.072400 +vn 0.991400 0.112100 0.067500 +vn 0.990900 0.117000 0.066600 +vn 0.992700 0.094800 0.075100 +vn 0.993100 0.089200 0.075900 +vn 0.993400 0.090800 0.070700 +vn 0.992900 0.096400 0.069900 +vn 0.992600 0.121500 0.000000 +vn 0.993200 0.116500 0.000000 +vn 0.993200 0.116500 -0.003400 +vn 0.992600 0.121400 -0.003300 +vn 0.992400 0.120700 0.022700 +vn 0.993000 0.115800 0.023000 +vn 0.993100 0.116300 0.016700 +vn 0.992500 0.121300 0.016500 +vn 0.994700 0.099900 0.024000 +vn 0.995300 0.094300 0.024300 +vn 0.995300 0.094800 0.017600 +vn 0.994800 0.100500 0.017400 +vn 0.988500 0.061400 0.137900 +vn 0.988700 0.055900 0.138800 +vn 0.989100 0.057500 0.135600 +vn 0.988900 0.063100 0.134800 +vn 0.986700 0.057800 0.152100 +vn 0.986800 0.052600 0.153000 +vn 0.987100 0.054200 0.150500 +vn 0.986900 0.059600 0.149600 +vn 0.987200 0.036500 0.155200 +vn 0.987300 0.031000 0.155800 +vn 0.987700 0.031900 0.153000 +vn 0.987600 0.037600 0.152500 +vn 0.986500 0.101100 0.128700 +vn 0.986800 0.096600 0.130000 +vn 0.986900 0.099200 0.127300 +vn 0.986600 0.103700 0.126000 +vn 0.985200 0.095600 0.142500 +vn 0.985400 0.091300 0.143900 +vn 0.985400 0.093900 0.141900 +vn 0.985200 0.098300 0.140600 +vn 0.986000 0.077600 0.147800 +vn 0.986200 0.072800 0.148900 +vn 0.986300 0.075000 0.146700 +vn 0.986100 0.079900 0.145600 +vn 0.989400 0.111200 0.093100 +vn 0.989900 0.106400 0.094200 +vn 0.990000 0.108400 0.089900 +vn 0.989600 0.113300 0.088900 +vn 0.988000 0.106400 0.112200 +vn 0.988300 0.101700 0.113400 +vn 0.988500 0.104000 0.109900 +vn 0.988100 0.108800 0.108800 +vn 0.989300 0.086800 0.116900 +vn 0.989700 0.081500 0.118000 +vn 0.989900 0.083500 0.114300 +vn 0.989600 0.088900 0.113300 +vn 0.989400 -0.027500 0.142500 +vn 0.989400 -0.033000 0.141600 +vn 0.989900 -0.033500 0.137600 +vn 0.990000 -0.027900 0.138500 +vn 0.987300 -0.025800 0.156700 +vn 0.987300 -0.031000 0.155800 +vn 0.987800 -0.031500 0.152500 +vn 0.987800 -0.026200 0.153400 +vn 0.986800 -0.048000 0.154500 +vn 0.986800 -0.052600 0.153000 +vn 0.987300 -0.053400 0.149700 +vn 0.987300 -0.048800 0.151200 +vn 0.989600 0.015100 0.142900 +vn 0.989700 0.009100 0.143100 +vn 0.990200 0.009300 0.139200 +vn 0.990200 0.015600 0.139100 +vn 0.987500 0.014200 0.157000 +vn 0.987500 0.008500 0.157200 +vn 0.988000 0.008800 0.154100 +vn 0.988000 0.014600 0.154000 +vn 0.987500 -0.002900 0.157400 +vn 0.987500 -0.008500 0.157200 +vn 0.988000 -0.008700 0.154000 +vn 0.988000 -0.002900 0.154200 +vn 0.994200 0.017000 0.105700 +vn 0.994300 0.010200 0.106000 +vn 0.994900 0.010500 0.100600 +vn 0.994800 0.017400 0.100500 +vn 0.991900 0.016000 0.125800 +vn 0.992000 0.009600 0.126000 +vn 0.992600 0.009900 0.121400 +vn 0.992500 0.016500 0.121300 +vn 0.992000 -0.003300 0.126200 +vn 0.992000 -0.009600 0.126000 +vn 0.992600 -0.009800 0.121300 +vn 0.992600 -0.003300 0.121500 +vn 0.988500 0.061400 -0.137900 +vn 0.988600 0.056700 -0.139600 +vn 0.988100 0.055900 -0.143400 +vn 0.988100 0.060500 -0.141700 +vn 0.990500 0.064900 -0.120900 +vn 0.990700 0.059900 -0.122600 +vn 0.990100 0.059100 -0.127100 +vn 0.990000 0.064100 -0.125500 +vn 0.991400 0.041100 -0.124000 +vn 0.991500 0.035400 -0.125000 +vn 0.991000 0.034900 -0.129600 +vn 0.990900 0.040600 -0.128500 +vn 0.986500 0.101100 -0.128700 +vn 0.986500 0.097900 -0.131200 +vn 0.986100 0.096600 -0.135000 +vn 0.986200 0.099800 -0.132400 +vn 0.988000 0.106400 -0.112200 +vn 0.988100 0.102900 -0.114500 +vn 0.987700 0.101600 -0.119000 +vn 0.987600 0.105100 -0.116500 +vn 0.989300 0.086800 -0.116900 +vn 0.989500 0.082500 -0.119000 +vn 0.989000 0.081500 -0.123500 +vn 0.988900 0.085700 -0.121400 +vn 0.984000 0.089900 -0.153500 +vn 0.983900 0.087100 -0.156300 +vn 0.983600 0.085700 -0.158600 +vn 0.983800 0.088400 -0.155900 +vn 0.985200 0.095600 -0.142500 +vn 0.985100 0.092600 -0.145100 +vn 0.984700 0.091300 -0.148200 +vn 0.984900 0.094200 -0.145500 +vn 0.986000 0.077600 -0.147800 +vn 0.985900 0.073900 -0.150000 +vn 0.985500 0.072800 -0.153100 +vn 0.985600 0.076500 -0.150800 +vn 0.995800 0.074200 -0.052900 +vn 0.996200 0.068400 -0.054000 +vn 0.995900 0.067800 -0.060700 +vn 0.995500 0.073600 -0.059500 +vn 0.996800 0.076100 -0.025300 +vn 0.997200 0.070000 -0.025900 +vn 0.997000 0.069700 -0.033100 +vn 0.996600 0.075700 -0.032400 +vn 0.998400 0.049300 -0.026500 +vn 0.998700 0.042400 -0.027100 +vn 0.998500 0.042200 -0.034500 +vn 0.998200 0.049000 -0.033900 +vn 0.991800 0.118600 -0.047900 +vn 0.992200 0.114300 -0.049200 +vn 0.992000 0.113700 -0.055400 +vn 0.991600 0.117900 -0.054000 +vn 0.992400 0.120700 -0.022700 +vn 0.993000 0.116100 -0.023300 +vn 0.992800 0.115800 -0.029900 +vn 0.992300 0.120300 -0.029100 +vn 0.994700 0.099900 -0.024000 +vn 0.995200 0.094600 -0.024600 +vn 0.995000 0.094200 -0.031500 +vn 0.994600 0.099500 -0.030800 +vn 0.989400 0.111200 -0.093100 +vn 0.989600 0.107400 -0.095200 +vn 0.989300 0.106300 -0.100300 +vn 0.989100 0.110000 -0.098100 +vn 0.990800 0.115300 -0.071500 +vn 0.991100 0.111300 -0.073300 +vn 0.990700 0.110400 -0.079000 +vn 0.990400 0.114400 -0.077100 +vn 0.992700 0.094800 -0.075100 +vn 0.993000 0.090000 -0.076700 +vn 0.992600 0.089200 -0.082600 +vn 0.992300 0.093900 -0.080900 +vn 0.985600 -0.111100 -0.127200 +vn 0.985400 -0.115100 -0.125800 +vn 0.985400 -0.112300 -0.128000 +vn 0.985600 -0.108300 -0.129500 +vn 0.987000 -0.116500 -0.110800 +vn 0.986600 -0.120700 -0.109500 +vn 0.986600 -0.118000 -0.112500 +vn 0.986900 -0.113900 -0.113900 +vn 0.985600 -0.132300 -0.105400 +vn 0.985300 -0.135800 -0.104000 +vn 0.985300 -0.133000 -0.106800 +vn 0.985600 -0.129500 -0.108300 +vn 0.988400 -0.121300 -0.091900 +vn 0.987900 -0.125600 -0.090700 +vn 0.987900 -0.123300 -0.094500 +vn 0.988300 -0.119000 -0.095700 +vn 0.989600 -0.125400 -0.070500 +vn 0.989100 -0.129700 -0.069600 +vn 0.989000 -0.127800 -0.074100 +vn 0.989500 -0.123500 -0.075100 +vn 0.987700 -0.141700 -0.066800 +vn 0.987200 -0.145300 -0.065800 +vn 0.987200 -0.143400 -0.070000 +vn 0.987600 -0.139700 -0.071100 +vn 0.983400 -0.099200 -0.152000 +vn 0.983300 -0.102900 -0.150400 +vn 0.983500 -0.099700 -0.151200 +vn 0.983600 -0.096100 -0.152800 +vn 0.984400 -0.105200 -0.140900 +vn 0.984200 -0.109200 -0.139400 +vn 0.984300 -0.106100 -0.140900 +vn 0.984500 -0.102300 -0.142500 +vn 0.983600 -0.120100 -0.134700 +vn 0.983400 -0.123400 -0.133000 +vn 0.983600 -0.120100 -0.134300 +vn 0.983800 -0.116800 -0.136000 +vn 0.994000 -0.030700 -0.105400 +vn 0.993800 -0.037400 -0.105000 +vn 0.993300 -0.036400 -0.109800 +vn 0.993400 -0.029900 -0.110300 +vn 0.996100 -0.032300 -0.082300 +vn 0.995900 -0.039300 -0.081900 +vn 0.995400 -0.038400 -0.087500 +vn 0.995600 -0.031600 -0.088000 +vn 0.995000 -0.059500 -0.080400 +vn 0.994600 -0.065900 -0.079700 +vn 0.994300 -0.064500 -0.085000 +vn 0.994600 -0.058200 -0.085700 +vn 0.992500 0.068300 -0.101100 +vn 0.992700 0.063000 -0.102600 +vn 0.992200 0.062300 -0.107800 +vn 0.992000 0.067500 -0.106300 +vn 0.994400 0.071500 -0.078300 +vn 0.994600 0.065900 -0.079700 +vn 0.994200 0.065200 -0.085700 +vn 0.993900 0.070700 -0.084300 +vn 0.995700 0.045700 -0.081000 +vn 0.995900 0.039300 -0.081900 +vn 0.995400 0.038800 -0.088000 +vn 0.995200 0.045100 -0.087000 +vn 0.985100 0.054100 -0.163300 +vn 0.985000 0.050100 -0.165000 +vn 0.984700 0.049200 -0.167400 +vn 0.984700 0.053200 -0.165700 +vn 0.986700 0.057800 -0.152100 +vn 0.986700 0.053400 -0.153700 +vn 0.986200 0.052500 -0.156800 +vn 0.986300 0.056900 -0.155200 +vn 0.987200 0.036500 -0.155200 +vn 0.987200 0.031400 -0.156300 +vn 0.986700 0.030900 -0.159300 +vn 0.986700 0.035900 -0.158300 +vn 0.994000 -0.030700 0.105400 +vn 0.993800 -0.036900 0.104500 +vn 0.994400 -0.037400 0.099100 +vn 0.994500 -0.031100 0.099900 +vn 0.991700 -0.029100 0.125400 +vn 0.991600 -0.035000 0.124600 +vn 0.992200 -0.035500 0.119800 +vn 0.992200 -0.029500 0.120700 +vn 0.990900 -0.053900 0.123300 +vn 0.990800 -0.059100 0.121800 +vn 0.991300 -0.059900 0.117100 +vn 0.991400 -0.054700 0.118600 +vn 0.992500 0.068300 0.101100 +vn 0.992800 0.062300 0.101900 +vn 0.993200 0.063800 0.097100 +vn 0.992900 0.069900 0.096400 +vn 0.990500 0.064900 0.120900 +vn 0.990800 0.059100 0.121800 +vn 0.991200 0.060700 0.117800 +vn 0.990900 0.066600 0.117000 +vn 0.991400 0.041100 0.124000 +vn 0.991600 0.035000 0.124600 +vn 0.992100 0.035900 0.120300 +vn 0.991900 0.042300 0.119800 +vn 0.997000 0.076900 0.000000 +vn 0.997500 0.070400 0.000000 +vn 0.997500 0.070400 -0.003700 +vn 0.997000 0.076800 -0.003600 +vn 0.996800 0.076100 0.025300 +vn 0.997200 0.069700 0.025600 +vn 0.997400 0.070200 0.018600 +vn 0.996900 0.076700 0.018300 +vn 0.998400 0.049300 0.026500 +vn 0.998800 0.042200 0.026800 +vn 0.998900 0.042600 0.019400 +vn 0.998600 0.049800 0.019200 +vn 0.994300 0.017000 -0.105700 +vn 0.994300 0.010300 -0.106100 +vn 0.993700 0.010200 -0.111400 +vn 0.993700 0.016700 -0.111000 +vn 0.996400 0.017900 -0.082700 +vn 0.996500 0.010900 -0.083000 +vn 0.996000 0.010700 -0.089100 +vn 0.995900 0.017700 -0.088700 +vn 0.996500 -0.003600 -0.083100 +vn 0.996500 -0.010900 -0.083000 +vn 0.996000 -0.010600 -0.089000 +vn 0.996000 -0.003500 -0.089100 +vn 0.988400 -0.121300 0.091900 +vn 0.988200 -0.124500 0.089600 +vn 0.988500 -0.125700 0.084600 +vn 0.988700 -0.122400 0.086700 +vn 0.987000 -0.116500 0.110800 +vn 0.986900 -0.119400 0.108200 +vn 0.987200 -0.120700 0.103800 +vn 0.987300 -0.117700 0.106300 +vn 0.985600 -0.132300 0.105400 +vn 0.985600 -0.134500 0.102700 +vn 0.985800 -0.135900 0.098400 +vn 0.985900 -0.133600 0.101100 +vn 0.991400 -0.130700 -0.000000 +vn 0.990800 -0.135100 -0.000000 +vn 0.990800 -0.135100 -0.003100 +vn 0.991400 -0.130700 -0.003200 +vn 0.991200 -0.130300 0.022400 +vn 0.990700 -0.134400 0.021700 +vn 0.990800 -0.134700 0.015600 +vn 0.991300 -0.130500 0.016000 +vn 0.989000 -0.146700 0.021100 +vn 0.988500 -0.150000 0.020500 +vn 0.988500 -0.150300 0.014600 +vn 0.989000 -0.146900 0.015100 +vn 0.998200 0.018800 -0.056600 +vn 0.998300 0.011400 -0.057000 +vn 0.997900 0.011300 -0.063800 +vn 0.997800 0.018600 -0.063400 +vn 0.999400 0.019600 -0.027500 +vn 0.999500 0.012000 -0.027900 +vn 0.999300 0.011800 -0.035400 +vn 0.999200 0.019400 -0.035100 +vn 0.999600 -0.004000 -0.027900 +vn 0.999500 -0.012000 -0.027900 +vn 0.999300 -0.011700 -0.035300 +vn 0.999400 -0.003900 -0.035400 +vn 0.999400 -0.035500 -0.000000 +vn 0.999100 -0.042800 0.000000 +vn 0.999100 -0.042800 -0.003900 +vn 0.999400 -0.035400 -0.003900 +vn 0.999000 -0.035100 0.027300 +vn 0.998800 -0.042200 0.026800 +vn 0.998900 -0.042400 0.019200 +vn 0.999200 -0.035300 0.019600 +vn 0.997600 -0.063400 0.026200 +vn 0.997200 -0.069700 0.025600 +vn 0.997400 -0.070000 0.018300 +vn 0.997800 -0.063600 0.018800 +vn 0.985500 -0.024200 -0.168000 +vn 0.985400 -0.029500 -0.167500 +vn 0.985100 -0.028500 -0.169500 +vn 0.985200 -0.023400 -0.169900 +vn 0.987300 -0.025800 -0.156700 +vn 0.987200 -0.031400 -0.156300 +vn 0.986800 -0.030500 -0.158900 +vn 0.986900 -0.025000 -0.159400 +vn 0.986800 -0.048000 -0.154500 +vn 0.986700 -0.053400 -0.153700 +vn 0.986400 -0.051800 -0.156100 +vn 0.986500 -0.046500 -0.156900 +vn 0.991700 -0.080800 -0.100100 +vn 0.991300 -0.086500 -0.099200 +vn 0.991000 -0.084600 -0.103500 +vn 0.991400 -0.079000 -0.104500 +vn 0.993400 -0.084200 -0.077500 +vn 0.993000 -0.090000 -0.076700 +vn 0.992700 -0.088400 -0.081800 +vn 0.993100 -0.082600 -0.082600 +vn 0.991600 -0.106200 -0.074200 +vn 0.991100 -0.111300 -0.073300 +vn 0.990900 -0.109500 -0.078100 +vn 0.991400 -0.104500 -0.079000 +vn 0.994800 -0.087000 -0.052300 +vn 0.994300 -0.092800 -0.051700 +vn 0.994100 -0.091500 -0.057500 +vn 0.994600 -0.085700 -0.058200 +vn 0.995700 -0.088700 -0.024900 +vn 0.995200 -0.094600 -0.024600 +vn 0.995100 -0.093900 -0.031200 +vn 0.995600 -0.088000 -0.031600 +vn 0.993500 -0.111000 -0.023700 +vn 0.993000 -0.116100 -0.023300 +vn 0.992900 -0.115400 -0.029500 +vn 0.993400 -0.110300 -0.029900 +vn 0.990600 -0.128500 -0.047200 +vn 0.990000 -0.132800 -0.046500 +vn 0.990000 -0.131500 -0.051800 +vn 0.990500 -0.127100 -0.052500 +vn 0.991200 -0.130300 -0.022400 +vn 0.990600 -0.134700 -0.022100 +vn 0.990600 -0.134000 -0.027900 +vn 0.991200 -0.129600 -0.028300 +vn 0.989000 -0.146700 -0.021100 +vn 0.988400 -0.150300 -0.020800 +vn 0.988400 -0.149600 -0.026200 +vn 0.988900 -0.145900 -0.026600 +vn 0.997800 -0.033900 -0.056300 +vn 0.997600 -0.041100 -0.055900 +vn 0.997200 -0.040200 -0.062300 +vn 0.997500 -0.033100 -0.062700 +vn 0.999000 -0.035100 -0.027300 +vn 0.998700 -0.042400 -0.027100 +vn 0.998500 -0.041800 -0.034200 +vn 0.998800 -0.034500 -0.034500 +vn 0.997600 -0.063400 -0.026200 +vn 0.997200 -0.070000 -0.025900 +vn 0.997100 -0.069300 -0.032700 +vn 0.997500 -0.062700 -0.033100 +vn 0.984600 -0.064700 -0.162300 +vn 0.984500 -0.069400 -0.161200 +vn 0.984400 -0.067200 -0.162500 +vn 0.984500 -0.062600 -0.163700 +vn 0.986100 -0.068900 -0.151000 +vn 0.985900 -0.073900 -0.150000 +vn 0.985800 -0.071700 -0.152000 +vn 0.985900 -0.066900 -0.153100 +vn 0.985300 -0.088100 -0.146400 +vn 0.985100 -0.092600 -0.145100 +vn 0.985100 -0.089900 -0.146900 +vn 0.985200 -0.085600 -0.148300 +vn 0.987900 -0.073100 -0.136900 +vn 0.987600 -0.078300 -0.135900 +vn 0.987400 -0.076200 -0.138700 +vn 0.987600 -0.071100 -0.139700 +vn 0.989800 -0.077100 -0.120000 +vn 0.989500 -0.082500 -0.119000 +vn 0.989200 -0.080500 -0.122500 +vn 0.989500 -0.075100 -0.123500 +vn 0.988400 -0.098000 -0.115700 +vn 0.988100 -0.102900 -0.114500 +vn 0.987900 -0.100500 -0.117800 +vn 0.988300 -0.095700 -0.119000 +vn 0.989100 -0.087800 -0.117900 +vn 0.988800 -0.093000 -0.116800 +vn 0.988600 -0.090800 -0.120200 +vn 0.988900 -0.085700 -0.121400 +vn 0.990000 -0.089900 -0.108400 +vn 0.989600 -0.095200 -0.107400 +vn 0.989400 -0.093100 -0.111200 +vn 0.989800 -0.087900 -0.112300 +vn 0.989300 -0.100300 -0.106300 +vn 0.988900 -0.105200 -0.105200 +vn 0.988700 -0.102900 -0.108800 +vn 0.989100 -0.098100 -0.110000 +vn 0.990400 -0.065800 -0.121800 +vn 0.990100 -0.071500 -0.120900 +vn 0.989800 -0.069700 -0.124500 +vn 0.990000 -0.064100 -0.125500 +vn 0.991400 -0.067500 -0.112100 +vn 0.991100 -0.073300 -0.111300 +vn 0.990800 -0.071500 -0.115300 +vn 0.991000 -0.065800 -0.116200 +vn 0.990700 -0.079000 -0.110400 +vn 0.990400 -0.084500 -0.109400 +vn 0.990100 -0.082600 -0.113300 +vn 0.990400 -0.077100 -0.114400 +vn 0.988400 -0.062200 -0.138800 +vn 0.988100 -0.067700 -0.137900 +vn 0.987900 -0.065800 -0.140800 +vn 0.988100 -0.060500 -0.141700 +vn 0.989400 -0.064000 -0.130600 +vn 0.989100 -0.069600 -0.129700 +vn 0.988800 -0.067800 -0.133000 +vn 0.989000 -0.062300 -0.134000 +vn 0.988800 -0.075100 -0.128800 +vn 0.988500 -0.080400 -0.127800 +vn 0.988300 -0.078300 -0.130900 +vn 0.988600 -0.073100 -0.132000 +vn 0.985700 -0.078800 -0.148900 +vn 0.985500 -0.083500 -0.147700 +vn 0.985400 -0.081100 -0.149600 +vn 0.985600 -0.076500 -0.150800 +vn 0.986500 -0.081100 -0.142200 +vn 0.986300 -0.086000 -0.141000 +vn 0.986100 -0.083600 -0.143300 +vn 0.986400 -0.078800 -0.144500 +vn 0.986000 -0.090700 -0.139800 +vn 0.985800 -0.095300 -0.138500 +vn 0.985700 -0.092700 -0.140700 +vn 0.985900 -0.088200 -0.142000 +vn 0.986500 -0.058700 -0.152900 +vn 0.986300 -0.063800 -0.152000 +vn 0.986100 -0.061900 -0.154200 +vn 0.986300 -0.056900 -0.155200 +vn 0.987400 -0.060500 -0.146200 +vn 0.987200 -0.065800 -0.145300 +vn 0.986900 -0.063900 -0.147800 +vn 0.987100 -0.058700 -0.148800 +vn 0.987000 -0.071000 -0.144300 +vn 0.986700 -0.076100 -0.143300 +vn 0.986600 -0.074000 -0.145700 +vn 0.986800 -0.069000 -0.146800 +vn 0.984900 -0.055000 -0.164200 +vn 0.984800 -0.059900 -0.163300 +vn 0.984600 -0.058000 -0.164700 +vn 0.984700 -0.053200 -0.165700 +vn 0.985700 -0.056800 -0.158900 +vn 0.985500 -0.061900 -0.158000 +vn 0.985300 -0.060000 -0.159800 +vn 0.985500 -0.055100 -0.160800 +vn 0.985300 -0.066800 -0.157000 +vn 0.985200 -0.071700 -0.156000 +vn 0.985100 -0.069500 -0.157600 +vn 0.985200 -0.064800 -0.158700 +vn 0.998400 -0.049600 -0.026800 +vn 0.998000 -0.056600 -0.026500 +vn 0.997900 -0.055900 -0.033500 +vn 0.998200 -0.049000 -0.033900 +vn 0.998700 -0.050000 -0.011600 +vn 0.998300 -0.057000 -0.011400 +vn 0.998200 -0.056600 -0.018800 +vn 0.998600 -0.049600 -0.019000 +vn 0.997900 -0.063800 -0.011300 +vn 0.997500 -0.070400 -0.011200 +vn 0.997400 -0.070000 -0.018300 +vn 0.997800 -0.063400 -0.018600 +vn 0.999400 -0.019800 -0.027700 +vn 0.999200 -0.027500 -0.027500 +vn 0.999000 -0.027100 -0.034800 +vn 0.999200 -0.019400 -0.035100 +vn 0.999700 -0.020100 -0.012100 +vn 0.999500 -0.027900 -0.012000 +vn 0.999400 -0.027500 -0.019700 +vn 0.999600 -0.019800 -0.019800 +vn 0.999300 -0.035400 -0.011800 +vn 0.999000 -0.042800 -0.011700 +vn 0.998900 -0.042400 -0.019200 +vn 0.999200 -0.035100 -0.019400 +vn 0.998200 -0.019000 -0.056800 +vn 0.998000 -0.026500 -0.056600 +vn 0.997700 -0.025900 -0.063100 +vn 0.997800 -0.018600 -0.063400 +vn 0.998900 -0.019400 -0.042600 +vn 0.998700 -0.027100 -0.042400 +vn 0.998400 -0.026500 -0.049300 +vn 0.998600 -0.019000 -0.049600 +vn 0.998500 -0.034500 -0.042200 +vn 0.998200 -0.041800 -0.041800 +vn 0.998000 -0.041100 -0.048600 +vn 0.998200 -0.033900 -0.049000 +vn 0.990100 -0.138800 -0.021700 +vn 0.989500 -0.142800 -0.021400 +vn 0.989500 -0.142100 -0.027100 +vn 0.990000 -0.138100 -0.027500 +vn 0.990200 -0.139200 -0.009300 +vn 0.989600 -0.143200 -0.009200 +vn 0.989600 -0.142900 -0.015100 +vn 0.990200 -0.138900 -0.015300 +vn 0.989100 -0.147000 -0.009100 +vn 0.988500 -0.150700 -0.008900 +vn 0.988500 -0.150300 -0.014600 +vn 0.989100 -0.146700 -0.014900 +vn 0.992400 -0.121000 -0.023000 +vn 0.991800 -0.125800 -0.022700 +vn 0.991700 -0.125100 -0.028700 +vn 0.992300 -0.120300 -0.029100 +vn 0.992600 -0.121400 -0.009900 +vn 0.992000 -0.126100 -0.009800 +vn 0.991900 -0.125800 -0.016000 +vn 0.992500 -0.121000 -0.016300 +vn 0.991400 -0.130700 -0.009600 +vn 0.990800 -0.135100 -0.009500 +vn 0.990800 -0.134700 -0.015600 +vn 0.991300 -0.130300 -0.015800 +vn 0.991700 -0.119200 -0.048500 +vn 0.991100 -0.123900 -0.047900 +vn 0.991000 -0.122600 -0.053200 +vn 0.991600 -0.117900 -0.054000 +vn 0.992100 -0.120300 -0.035900 +vn 0.991500 -0.125000 -0.035400 +vn 0.991400 -0.124000 -0.041100 +vn 0.992000 -0.119300 -0.041700 +vn 0.991000 -0.129600 -0.034900 +vn 0.990400 -0.133900 -0.034400 +vn 0.990300 -0.132900 -0.040000 +vn 0.990900 -0.128500 -0.040600 +vn 0.994700 -0.100200 -0.024300 +vn 0.994100 -0.105700 -0.024000 +vn 0.994000 -0.105000 -0.030300 +vn 0.994600 -0.099500 -0.030800 +vn 0.994900 -0.100600 -0.010500 +vn 0.994300 -0.106100 -0.010300 +vn 0.994200 -0.105700 -0.017000 +vn 0.994800 -0.100300 -0.017200 +vn 0.993700 -0.111400 -0.010200 +vn 0.993100 -0.116500 -0.010000 +vn 0.993100 -0.116100 -0.016500 +vn 0.993700 -0.111000 -0.016700 +vn 0.996700 -0.076400 -0.025600 +vn 0.996300 -0.082700 -0.025300 +vn 0.996100 -0.082000 -0.032000 +vn 0.996600 -0.075700 -0.032400 +vn 0.997000 -0.076800 -0.011000 +vn 0.996500 -0.083000 -0.010900 +vn 0.996400 -0.082700 -0.017900 +vn 0.996900 -0.076400 -0.018100 +vn 0.996000 -0.089100 -0.010700 +vn 0.995400 -0.094900 -0.010600 +vn 0.995400 -0.094600 -0.017400 +vn 0.995900 -0.088700 -0.017700 +vn 0.995800 -0.074700 -0.053500 +vn 0.995300 -0.080900 -0.052900 +vn 0.995100 -0.079700 -0.058900 +vn 0.995500 -0.073600 -0.059500 +vn 0.996300 -0.075700 -0.039800 +vn 0.995900 -0.081900 -0.039300 +vn 0.995700 -0.081000 -0.045700 +vn 0.996100 -0.074800 -0.046200 +vn 0.995400 -0.088000 -0.038800 +vn 0.994800 -0.093800 -0.038400 +vn 0.994700 -0.092800 -0.044600 +vn 0.995200 -0.087000 -0.045100 +vn 0.992500 -0.095600 -0.075900 +vn 0.992100 -0.101000 -0.075000 +vn 0.991800 -0.099300 -0.080000 +vn 0.992300 -0.093900 -0.080900 +vn 0.993200 -0.097100 -0.063800 +vn 0.992700 -0.102600 -0.063000 +vn 0.992500 -0.101100 -0.068300 +vn 0.993000 -0.095600 -0.069100 +vn 0.992200 -0.107800 -0.062300 +vn 0.991700 -0.112900 -0.061500 +vn 0.991500 -0.111400 -0.066700 +vn 0.992000 -0.106300 -0.067500 +vn 0.994300 -0.072200 -0.079000 +vn 0.993900 -0.078300 -0.078300 +vn 0.993500 -0.076800 -0.083500 +vn 0.993900 -0.070700 -0.084300 +vn 0.995100 -0.073500 -0.066600 +vn 0.994600 -0.079700 -0.065900 +vn 0.994400 -0.078300 -0.071500 +vn 0.994800 -0.072200 -0.072200 +vn 0.994200 -0.085700 -0.065200 +vn 0.993700 -0.091500 -0.064500 +vn 0.993500 -0.090000 -0.069900 +vn 0.993900 -0.084300 -0.070700 +vn 0.992400 -0.069100 -0.101800 +vn 0.992100 -0.075000 -0.101000 +vn 0.991700 -0.073300 -0.105400 +vn 0.992000 -0.067500 -0.106300 +vn 0.993400 -0.070700 -0.090800 +vn 0.993000 -0.076700 -0.090000 +vn 0.992700 -0.075100 -0.094800 +vn 0.993000 -0.069100 -0.095600 +vn 0.992600 -0.082600 -0.089200 +vn 0.992200 -0.088300 -0.088300 +vn 0.991900 -0.086500 -0.093000 +vn 0.992300 -0.080900 -0.093900 +vn 0.987100 -0.037000 -0.155800 +vn 0.987000 -0.042600 -0.155200 +vn 0.986600 -0.041200 -0.157600 +vn 0.986700 -0.035900 -0.158300 +vn 0.988100 -0.038200 -0.149000 +vn 0.987900 -0.043900 -0.148500 +vn 0.987600 -0.042600 -0.151300 +vn 0.987700 -0.037100 -0.151900 +vn 0.987800 -0.049500 -0.147800 +vn 0.987600 -0.055000 -0.147000 +vn 0.987300 -0.053400 -0.149700 +vn 0.987400 -0.048000 -0.150500 +vn 0.987500 -0.014400 -0.157200 +vn 0.987400 -0.020100 -0.157000 +vn 0.987000 -0.019500 -0.159800 +vn 0.987000 -0.013900 -0.160100 +vn 0.988500 -0.014900 -0.150500 +vn 0.988400 -0.020800 -0.150300 +vn 0.988000 -0.020100 -0.153400 +vn 0.988000 -0.014400 -0.153700 +vn 0.988300 -0.026600 -0.150000 +vn 0.988200 -0.032400 -0.149500 +vn 0.987800 -0.031500 -0.152500 +vn 0.987900 -0.025800 -0.153000 +vn 0.985600 -0.013500 -0.168500 +vn 0.985600 -0.018800 -0.168300 +vn 0.985200 -0.018200 -0.170400 +vn 0.985200 -0.013000 -0.170700 +vn 0.986500 -0.013900 -0.163200 +vn 0.986400 -0.019500 -0.163000 +vn 0.986000 -0.018800 -0.165400 +vn 0.986100 -0.013500 -0.165700 +vn 0.986400 -0.025000 -0.162700 +vn 0.986300 -0.030500 -0.162300 +vn 0.985900 -0.029500 -0.164500 +vn 0.986000 -0.024200 -0.165000 +vn 0.998400 -0.049600 0.026800 +vn 0.998100 -0.056300 0.026200 +vn 0.998200 -0.056600 0.018800 +vn 0.998600 -0.049800 0.019200 +vn 0.997900 -0.049000 0.041500 +vn 0.997600 -0.055500 0.040700 +vn 0.997900 -0.055900 0.033500 +vn 0.998200 -0.049300 0.034200 +vn 0.997200 -0.062700 0.040700 +vn 0.996800 -0.068900 0.039800 +vn 0.997100 -0.069300 0.032700 +vn 0.997400 -0.063100 0.033500 +vn 0.999400 -0.019800 0.027700 +vn 0.999300 -0.027300 0.027300 +vn 0.999400 -0.027500 0.019700 +vn 0.999600 -0.020000 0.020000 +vn 0.998900 -0.019400 0.042600 +vn 0.998800 -0.026800 0.042200 +vn 0.999000 -0.027100 0.034800 +vn 0.999200 -0.019600 0.035300 +vn 0.998500 -0.034500 0.042200 +vn 0.998300 -0.041500 0.041500 +vn 0.998500 -0.041800 0.034200 +vn 0.998800 -0.034800 0.034800 +vn 0.999800 -0.020200 -0.000000 +vn 0.999600 -0.027900 -0.000000 +vn 0.999600 -0.027900 -0.004000 +vn 0.999800 -0.020100 -0.004000 +vn 0.999700 -0.020100 0.012100 +vn 0.999500 -0.027700 0.011900 +vn 0.999600 -0.027900 0.004000 +vn 0.999800 -0.020200 0.004000 +vn 0.999300 -0.035400 0.011800 +vn 0.999000 -0.042700 0.011600 +vn 0.999100 -0.042800 0.003900 +vn 0.999400 -0.035500 0.004000 +vn 0.999600 0.004000 -0.027900 +vn 0.999600 -0.000000 -0.027900 +vn 0.999400 0.000000 -0.035500 +vn 0.999400 0.003900 -0.035400 +vn 0.999900 0.004100 -0.012200 +vn 0.999900 0.000000 -0.012200 +vn 0.999800 0.000000 -0.020200 +vn 0.999800 0.004000 -0.020100 +vn 0.999900 -0.004100 -0.012200 +vn 0.999900 -0.012200 -0.012200 +vn 0.999700 -0.012000 -0.020000 +vn 0.999800 -0.004000 -0.020100 +vn 0.999000 0.034800 -0.027100 +vn 0.999200 0.027500 -0.027500 +vn 0.999000 0.027300 -0.035100 +vn 0.998800 0.034500 -0.034500 +vn 0.999300 0.035300 -0.011700 +vn 0.999500 0.027900 -0.012000 +vn 0.999400 0.027700 -0.019800 +vn 0.999200 0.035100 -0.019400 +vn 0.999700 0.020000 -0.012000 +vn 0.999900 0.012200 -0.012200 +vn 0.999700 0.012100 -0.020100 +vn 0.999600 0.019800 -0.019800 +vn 0.997900 0.033500 -0.055900 +vn 0.998000 0.026500 -0.056600 +vn 0.997600 0.026200 -0.063400 +vn 0.997500 0.033100 -0.062700 +vn 0.998500 0.034200 -0.041800 +vn 0.998700 0.027100 -0.042400 +vn 0.998400 0.026800 -0.049600 +vn 0.998200 0.033900 -0.049000 +vn 0.998900 0.019200 -0.042400 +vn 0.999000 0.011700 -0.042800 +vn 0.998700 0.011600 -0.050000 +vn 0.998600 0.019000 -0.049600 +vn 0.990100 -0.138900 0.021700 +vn 0.989600 -0.142500 0.021100 +vn 0.989600 -0.142900 0.015100 +vn 0.990200 -0.139100 0.015600 +vn 0.989800 -0.138100 0.033900 +vn 0.989400 -0.141600 0.033000 +vn 0.989500 -0.142100 0.027100 +vn 0.990000 -0.138500 0.027900 +vn 0.988700 -0.145900 0.032900 +vn 0.988300 -0.149100 0.032000 +vn 0.988400 -0.149600 0.026200 +vn 0.988900 -0.146300 0.027000 +vn 0.992400 -0.121000 0.023000 +vn 0.991800 -0.125500 0.022400 +vn 0.991900 -0.125800 0.016000 +vn 0.992500 -0.121300 0.016500 +vn 0.992100 -0.120300 0.035900 +vn 0.991600 -0.124600 0.035000 +vn 0.991700 -0.125000 0.028700 +vn 0.992200 -0.120700 0.029500 +vn 0.991000 -0.129600 0.034900 +vn 0.990500 -0.133500 0.034000 +vn 0.990600 -0.134000 0.027900 +vn 0.991100 -0.130000 0.028700 +vn 0.992600 -0.121500 -0.000000 +vn 0.992000 -0.126200 -0.000000 +vn 0.992000 -0.126100 -0.003200 +vn 0.992600 -0.121400 -0.003300 +vn 0.992600 -0.121400 0.009900 +vn 0.992000 -0.126000 0.009600 +vn 0.992000 -0.126100 0.003200 +vn 0.992600 -0.121500 0.003300 +vn 0.991400 -0.130700 0.009600 +vn 0.990800 -0.134900 0.009400 +vn 0.990800 -0.135100 0.003100 +vn 0.991400 -0.130700 0.003200 +vn 0.986300 -0.124700 0.108200 +vn 0.986200 -0.127300 0.105500 +vn 0.986500 -0.128700 0.101100 +vn 0.986600 -0.126000 0.103700 +vn 0.985700 -0.122000 0.116600 +vn 0.985700 -0.124400 0.113800 +vn 0.986000 -0.125900 0.109700 +vn 0.986000 -0.123300 0.112400 +vn 0.985000 -0.129400 0.113700 +vn 0.985100 -0.131500 0.110800 +vn 0.985300 -0.133000 0.106800 +vn 0.985300 -0.130900 0.109600 +vn 0.987700 -0.107600 0.113300 +vn 0.987600 -0.110900 0.110900 +vn 0.988000 -0.112200 0.106400 +vn 0.988100 -0.108800 0.108800 +vn 0.987000 -0.105000 0.122000 +vn 0.986900 -0.108200 0.119400 +vn 0.987300 -0.109600 0.115200 +vn 0.987300 -0.106300 0.117700 +vn 0.986300 -0.113800 0.119300 +vn 0.986300 -0.116600 0.116600 +vn 0.986600 -0.118000 0.112500 +vn 0.986700 -0.115200 0.115200 +vn 0.989200 -0.112200 0.094100 +vn 0.989000 -0.115800 0.091900 +vn 0.989300 -0.116900 0.086800 +vn 0.989600 -0.113300 0.088900 +vn 0.988500 -0.110000 0.104000 +vn 0.988300 -0.113400 0.101700 +vn 0.988700 -0.114600 0.096900 +vn 0.988900 -0.111100 0.099100 +vn 0.987700 -0.119000 0.101600 +vn 0.987600 -0.122000 0.099200 +vn 0.987900 -0.123300 0.094500 +vn 0.988000 -0.120200 0.096800 +vn 0.996500 0.003600 -0.083000 +vn 0.996500 0.000000 -0.083100 +vn 0.996000 -0.000000 -0.089100 +vn 0.996000 0.003500 -0.089100 +vn 0.997500 0.003700 -0.070400 +vn 0.997500 0.000000 -0.070400 +vn 0.997000 0.000000 -0.076900 +vn 0.997000 0.003600 -0.076800 +vn 0.997500 -0.003700 -0.070400 +vn 0.997500 -0.011200 -0.070400 +vn 0.997000 -0.010900 -0.076700 +vn 0.997000 -0.003600 -0.076800 +vn 0.996100 0.032000 -0.082000 +vn 0.996300 0.025300 -0.082700 +vn 0.995700 0.024900 -0.088700 +vn 0.995600 0.031600 -0.088000 +vn 0.997100 0.032700 -0.069300 +vn 0.997200 0.025900 -0.070000 +vn 0.996700 0.025600 -0.076400 +vn 0.996600 0.032400 -0.075700 +vn 0.997400 0.018300 -0.070000 +vn 0.997500 0.011200 -0.070400 +vn 0.997000 0.011000 -0.076800 +vn 0.996900 0.018100 -0.076400 +vn 0.994000 0.030300 -0.105000 +vn 0.994100 0.024000 -0.105700 +vn 0.993500 0.023700 -0.111000 +vn 0.993400 0.029900 -0.110300 +vn 0.995100 0.031200 -0.093900 +vn 0.995200 0.024600 -0.094600 +vn 0.994700 0.024300 -0.100200 +vn 0.994600 0.030800 -0.099500 +vn 0.995400 0.017400 -0.094600 +vn 0.995400 0.010600 -0.094900 +vn 0.994900 0.010500 -0.100600 +vn 0.994800 0.017200 -0.100300 +vn 0.997700 0.063100 0.025900 +vn 0.998100 0.056300 0.026200 +vn 0.998200 0.056800 0.019000 +vn 0.997800 0.063600 0.018800 +vn 0.997200 0.062300 0.040200 +vn 0.997600 0.055500 0.040700 +vn 0.997800 0.056300 0.033900 +vn 0.997400 0.063100 0.033500 +vn 0.998000 0.048600 0.041100 +vn 0.998300 0.041500 0.041500 +vn 0.998500 0.042200 0.034500 +vn 0.998200 0.049300 0.034200 +vn 0.995800 0.088400 0.024600 +vn 0.996300 0.082400 0.025000 +vn 0.996400 0.082900 0.018100 +vn 0.995900 0.088900 0.017900 +vn 0.995400 0.087500 0.038400 +vn 0.995900 0.081500 0.038900 +vn 0.996100 0.082300 0.032300 +vn 0.995600 0.088400 0.031900 +vn 0.996400 0.075300 0.039300 +vn 0.996800 0.068900 0.039800 +vn 0.997000 0.069700 0.033100 +vn 0.996600 0.076100 0.032700 +vn 0.996000 0.089100 0.000000 +vn 0.996500 0.083100 0.000000 +vn 0.996500 0.083100 -0.003600 +vn 0.996000 0.089100 -0.003500 +vn 0.996000 0.089000 0.010600 +vn 0.996500 0.082900 0.010800 +vn 0.996500 0.083100 0.003600 +vn 0.996000 0.089100 0.003600 +vn 0.997000 0.076700 0.010900 +vn 0.997500 0.070200 0.011000 +vn 0.997500 0.070400 0.003700 +vn 0.997000 0.076900 0.003700 +vn 0.991000 0.053200 0.122600 +vn 0.991200 0.047200 0.123300 +vn 0.991700 0.048500 0.119200 +vn 0.991400 0.054700 0.118600 +vn 0.990000 0.051800 0.131500 +vn 0.990200 0.045900 0.132200 +vn 0.990600 0.047200 0.128500 +vn 0.990400 0.053200 0.127800 +vn 0.990300 0.040000 0.132900 +vn 0.990500 0.034000 0.133500 +vn 0.991000 0.034900 0.129600 +vn 0.990800 0.041100 0.129100 +vn 0.990000 0.076100 0.119000 +vn 0.990300 0.070600 0.120000 +vn 0.990600 0.072400 0.116200 +vn 0.990300 0.078000 0.115300 +vn 0.989000 0.074100 0.127800 +vn 0.989300 0.068700 0.128900 +vn 0.989600 0.070500 0.125400 +vn 0.989300 0.076100 0.124500 +vn 0.989500 0.063200 0.129800 +vn 0.989800 0.057500 0.130700 +vn 0.990100 0.059100 0.127100 +vn 0.989900 0.064900 0.126300 +vn 0.991800 0.080000 0.099300 +vn 0.992200 0.074200 0.100200 +vn 0.992500 0.075900 0.095600 +vn 0.992100 0.081700 0.094700 +vn 0.990900 0.078100 0.109500 +vn 0.991200 0.072400 0.110500 +vn 0.991600 0.074200 0.106200 +vn 0.991200 0.079900 0.105400 +vn 0.991500 0.066700 0.111400 +vn 0.991800 0.060700 0.112200 +vn 0.992200 0.062300 0.107900 +vn 0.991900 0.068300 0.107100 +vn 0.991300 -0.041700 0.124500 +vn 0.991200 -0.047200 0.123300 +vn 0.991800 -0.047900 0.118600 +vn 0.991900 -0.042300 0.119800 +vn 0.990200 -0.040500 0.133400 +vn 0.990200 -0.045900 0.132200 +vn 0.990700 -0.046600 0.127900 +vn 0.990800 -0.041100 0.129100 +vn 0.989800 -0.052500 0.132200 +vn 0.989800 -0.057500 0.130700 +vn 0.990300 -0.058300 0.126300 +vn 0.990400 -0.053200 0.127800 +vn 0.991900 -0.016300 0.126000 +vn 0.991800 -0.022400 0.125500 +vn 0.992400 -0.022700 0.120700 +vn 0.992500 -0.016500 0.121300 +vn 0.990700 -0.015800 0.134900 +vn 0.990700 -0.021700 0.134400 +vn 0.991300 -0.022100 0.130000 +vn 0.991300 -0.016000 0.130500 +vn 0.990500 -0.028300 0.134300 +vn 0.990500 -0.034000 0.133500 +vn 0.991000 -0.034500 0.129100 +vn 0.991100 -0.028700 0.130000 +vn 0.994200 -0.017200 0.106000 +vn 0.994100 -0.023700 0.105400 +vn 0.994700 -0.024000 0.099900 +vn 0.994800 -0.017400 0.100500 +vn 0.993100 -0.016700 0.116300 +vn 0.993000 -0.023000 0.115800 +vn 0.993600 -0.023400 0.110700 +vn 0.993600 -0.017000 0.111200 +vn 0.992800 -0.029900 0.115800 +vn 0.992700 -0.036000 0.114900 +vn 0.993300 -0.036400 0.109800 +vn 0.993400 -0.030300 0.110700 +vn 0.987000 0.047300 -0.153800 +vn 0.987000 0.042600 -0.155200 +vn 0.986500 0.041900 -0.158300 +vn 0.986500 0.046500 -0.156900 +vn 0.987900 0.048800 -0.147100 +vn 0.987900 0.043900 -0.148500 +vn 0.987400 0.043200 -0.151900 +vn 0.987400 0.048000 -0.150500 +vn 0.988200 0.037600 -0.148500 +vn 0.988200 0.032400 -0.149500 +vn 0.987700 0.031900 -0.153000 +vn 0.987700 0.037100 -0.151900 +vn 0.986300 0.067900 -0.150000 +vn 0.986300 0.063800 -0.152000 +vn 0.985900 0.062900 -0.155100 +vn 0.985900 0.066900 -0.153100 +vn 0.987200 0.070000 -0.143400 +vn 0.987200 0.065800 -0.145300 +vn 0.986700 0.064800 -0.148700 +vn 0.986800 0.069000 -0.146800 +vn 0.987600 0.059600 -0.145400 +vn 0.987600 0.055000 -0.147000 +vn 0.987100 0.054200 -0.150500 +vn 0.987100 0.058700 -0.148800 +vn 0.984800 0.063700 -0.161300 +vn 0.984800 0.059900 -0.163300 +vn 0.984400 0.058900 -0.165700 +vn 0.984500 0.062600 -0.163700 +vn 0.985600 0.065800 -0.156000 +vn 0.985500 0.061900 -0.158000 +vn 0.985100 0.060900 -0.160700 +vn 0.985200 0.064800 -0.158700 +vn 0.985800 0.056000 -0.158100 +vn 0.985800 0.051700 -0.159700 +vn 0.985400 0.050900 -0.162500 +vn 0.985500 0.055100 -0.160800 +vn 0.995100 0.058900 -0.079700 +vn 0.995300 0.052900 -0.080900 +vn 0.994800 0.052300 -0.087000 +vn 0.994600 0.058200 -0.085700 +vn 0.995900 0.060100 -0.067200 +vn 0.996200 0.054000 -0.068400 +vn 0.995800 0.053500 -0.074700 +vn 0.995500 0.059500 -0.073600 +vn 0.996600 0.046700 -0.068400 +vn 0.996800 0.040200 -0.069300 +vn 0.996300 0.039800 -0.075700 +vn 0.996100 0.046200 -0.074800 +vn 0.993500 0.083500 -0.076800 +vn 0.993900 0.078300 -0.078300 +vn 0.993400 0.077500 -0.084200 +vn 0.993100 0.082600 -0.082600 +vn 0.994300 0.085000 -0.064500 +vn 0.994600 0.079700 -0.065900 +vn 0.994300 0.079000 -0.072200 +vn 0.993900 0.084300 -0.070700 +vn 0.995200 0.072900 -0.065900 +vn 0.995500 0.067200 -0.067200 +vn 0.995100 0.066600 -0.073500 +vn 0.994800 0.072200 -0.072200 +vn 0.991800 0.080000 -0.099300 +vn 0.992100 0.075000 -0.101000 +vn 0.991600 0.074200 -0.106200 +vn 0.991400 0.079000 -0.104500 +vn 0.992700 0.081800 -0.088300 +vn 0.993000 0.076700 -0.090000 +vn 0.992500 0.075900 -0.095600 +vn 0.992300 0.080900 -0.093900 +vn 0.993500 0.069900 -0.090000 +vn 0.993700 0.064500 -0.091500 +vn 0.993200 0.063800 -0.097100 +vn 0.993000 0.069100 -0.095600 +vn 0.995600 -0.046200 -0.081500 +vn 0.995300 -0.052900 -0.080900 +vn 0.994900 -0.051700 -0.086400 +vn 0.995200 -0.045100 -0.087000 +vn 0.996500 -0.047200 -0.068900 +vn 0.996200 -0.054000 -0.068400 +vn 0.995800 -0.052900 -0.074200 +vn 0.996100 -0.046200 -0.074800 +vn 0.995900 -0.060700 -0.067800 +vn 0.995500 -0.067200 -0.067200 +vn 0.995200 -0.065900 -0.072900 +vn 0.995500 -0.059500 -0.073600 +vn 0.996400 -0.018100 -0.082900 +vn 0.996300 -0.025300 -0.082700 +vn 0.995800 -0.024600 -0.088400 +vn 0.995900 -0.017700 -0.088700 +vn 0.997400 -0.018600 -0.070200 +vn 0.997200 -0.025900 -0.070000 +vn 0.996800 -0.025300 -0.076100 +vn 0.996900 -0.018100 -0.076400 +vn 0.997000 -0.033100 -0.069700 +vn 0.996800 -0.040200 -0.069300 +vn 0.996400 -0.039300 -0.075300 +vn 0.996600 -0.032400 -0.075700 +vn 0.994200 -0.017200 -0.106000 +vn 0.994100 -0.024000 -0.105700 +vn 0.993600 -0.023400 -0.110700 +vn 0.993700 -0.016700 -0.111000 +vn 0.995300 -0.017600 -0.094800 +vn 0.995200 -0.024600 -0.094600 +vn 0.994700 -0.024000 -0.099900 +vn 0.994800 -0.017200 -0.100300 +vn 0.995000 -0.031500 -0.094200 +vn 0.994800 -0.038400 -0.093800 +vn 0.994400 -0.037400 -0.099000 +vn 0.994600 -0.030800 -0.099500 +vn 0.984000 -0.113000 -0.137900 +vn 0.983800 -0.116600 -0.136300 +vn 0.984000 -0.113400 -0.137700 +vn 0.984100 -0.109800 -0.139300 +vn 0.984500 -0.116100 -0.131400 +vn 0.984300 -0.119800 -0.129900 +vn 0.984400 -0.116700 -0.131700 +vn 0.984600 -0.113000 -0.133300 +vn 0.984000 -0.123300 -0.128300 +vn 0.983800 -0.126700 -0.126700 +vn 0.984000 -0.123500 -0.128400 +vn 0.984200 -0.120100 -0.130000 +vn 0.984800 -0.097000 -0.143800 +vn 0.984600 -0.101200 -0.142400 +vn 0.984700 -0.098300 -0.144000 +vn 0.984900 -0.094200 -0.145500 +vn 0.985500 -0.099700 -0.137200 +vn 0.985300 -0.104000 -0.135800 +vn 0.985300 -0.101200 -0.137800 +vn 0.985500 -0.097000 -0.139300 +vn 0.985000 -0.108200 -0.134400 +vn 0.984800 -0.112200 -0.132900 +vn 0.984800 -0.109200 -0.134800 +vn 0.985000 -0.105300 -0.136300 +vn 0.983700 -0.091300 -0.154900 +vn 0.983600 -0.095300 -0.153500 +vn 0.983700 -0.092300 -0.154400 +vn 0.983800 -0.088400 -0.155900 +vn 0.984200 -0.094100 -0.149700 +vn 0.984100 -0.098300 -0.148300 +vn 0.984200 -0.095300 -0.149500 +vn 0.984300 -0.091300 -0.151000 +vn 0.983900 -0.102200 -0.146800 +vn 0.983700 -0.106100 -0.145200 +vn 0.983900 -0.103000 -0.146400 +vn 0.984000 -0.099200 -0.148000 +vn 0.988600 -0.133900 -0.068700 +vn 0.988100 -0.137900 -0.067700 +vn 0.988100 -0.136000 -0.072100 +vn 0.988600 -0.132000 -0.073100 +vn 0.989100 -0.135600 -0.057500 +vn 0.988600 -0.139600 -0.056700 +vn 0.988500 -0.137900 -0.061400 +vn 0.989000 -0.134000 -0.062300 +vn 0.988100 -0.143400 -0.055900 +vn 0.987600 -0.147000 -0.055000 +vn 0.987600 -0.145400 -0.059600 +vn 0.988100 -0.141700 -0.060500 +vn 0.990600 -0.116200 -0.072400 +vn 0.990100 -0.120900 -0.071500 +vn 0.990000 -0.119000 -0.076100 +vn 0.990400 -0.114400 -0.077100 +vn 0.991200 -0.117800 -0.060700 +vn 0.990700 -0.122600 -0.059900 +vn 0.990500 -0.120900 -0.064900 +vn 0.991000 -0.116200 -0.065800 +vn 0.990100 -0.127100 -0.059100 +vn 0.989600 -0.131400 -0.058300 +vn 0.989500 -0.129800 -0.063200 +vn 0.990000 -0.125500 -0.064100 +vn 0.989200 -0.112200 -0.094100 +vn 0.988800 -0.116800 -0.093000 +vn 0.988700 -0.114600 -0.096900 +vn 0.989100 -0.110000 -0.098100 +vn 0.989900 -0.114300 -0.083500 +vn 0.989500 -0.119000 -0.082500 +vn 0.989300 -0.116900 -0.086800 +vn 0.989800 -0.112300 -0.087900 +vn 0.989000 -0.123500 -0.081500 +vn 0.988500 -0.127800 -0.080400 +vn 0.988500 -0.125700 -0.084600 +vn 0.988900 -0.121400 -0.085700 +vn 0.986300 -0.124700 -0.108200 +vn 0.985900 -0.128600 -0.106800 +vn 0.986000 -0.125900 -0.109700 +vn 0.986300 -0.122000 -0.111100 +vn 0.986900 -0.127300 -0.099200 +vn 0.986500 -0.131200 -0.097900 +vn 0.986500 -0.128700 -0.101100 +vn 0.986900 -0.124800 -0.102500 +vn 0.986100 -0.135000 -0.096600 +vn 0.985800 -0.138500 -0.095300 +vn 0.985800 -0.135900 -0.098400 +vn 0.986200 -0.132400 -0.099800 +vn 0.987700 -0.107600 -0.113300 +vn 0.987400 -0.112100 -0.112100 +vn 0.987300 -0.109600 -0.115200 +vn 0.987600 -0.105100 -0.116500 +vn 0.988500 -0.109900 -0.104000 +vn 0.988100 -0.114500 -0.102900 +vn 0.988000 -0.112200 -0.106400 +vn 0.988400 -0.107600 -0.107600 +vn 0.987700 -0.119000 -0.101600 +vn 0.987300 -0.123200 -0.100400 +vn 0.987200 -0.120700 -0.103800 +vn 0.987600 -0.116500 -0.105100 +vn 0.986200 -0.102400 -0.129900 +vn 0.985900 -0.106800 -0.128600 +vn 0.985900 -0.104100 -0.131000 +vn 0.986200 -0.099800 -0.132400 +vn 0.987000 -0.105000 -0.122000 +vn 0.986600 -0.109500 -0.120700 +vn 0.986600 -0.106900 -0.123400 +vn 0.986900 -0.102500 -0.124800 +vn 0.986300 -0.113800 -0.119300 +vn 0.986000 -0.118000 -0.118000 +vn 0.986000 -0.115200 -0.120600 +vn 0.986300 -0.111100 -0.122000 +vn 0.991700 0.105400 -0.073300 +vn 0.992100 0.101000 -0.075000 +vn 0.991700 0.100100 -0.080800 +vn 0.991400 0.104500 -0.079000 +vn 0.992300 0.107100 -0.061500 +vn 0.992700 0.102600 -0.063000 +vn 0.992400 0.101800 -0.069100 +vn 0.992000 0.106300 -0.067500 +vn 0.993300 0.096400 -0.063100 +vn 0.993700 0.091500 -0.064500 +vn 0.993400 0.090800 -0.070700 +vn 0.993000 0.095600 -0.069100 +vn 0.989800 0.124500 -0.069700 +vn 0.990100 0.120900 -0.071500 +vn 0.989800 0.120000 -0.077100 +vn 0.989500 0.123500 -0.075100 +vn 0.990300 0.126300 -0.058300 +vn 0.990700 0.122600 -0.059900 +vn 0.990400 0.121700 -0.065800 +vn 0.990000 0.125500 -0.064100 +vn 0.991300 0.117100 -0.059900 +vn 0.991700 0.112900 -0.061500 +vn 0.991400 0.112100 -0.067500 +vn 0.991000 0.116200 -0.065800 +vn 0.988600 0.120200 -0.090800 +vn 0.988800 0.116800 -0.093000 +vn 0.988400 0.115700 -0.098000 +vn 0.988300 0.119000 -0.095700 +vn 0.989200 0.122500 -0.080500 +vn 0.989500 0.119000 -0.082500 +vn 0.989100 0.117900 -0.087800 +vn 0.988900 0.121400 -0.085700 +vn 0.990100 0.113300 -0.082600 +vn 0.990400 0.109400 -0.084500 +vn 0.990000 0.108400 -0.089900 +vn 0.989800 0.112300 -0.087900 +vn 0.993600 0.110700 -0.023400 +vn 0.994100 0.105700 -0.024000 +vn 0.994000 0.105400 -0.030700 +vn 0.993400 0.110300 -0.029900 +vn 0.993700 0.111300 -0.010100 +vn 0.994300 0.106100 -0.010300 +vn 0.994200 0.106000 -0.017200 +vn 0.993700 0.111000 -0.016700 +vn 0.994900 0.100500 -0.010300 +vn 0.995400 0.094900 -0.010600 +vn 0.995300 0.094800 -0.017600 +vn 0.994800 0.100300 -0.017200 +vn 0.991300 0.130000 -0.022100 +vn 0.991800 0.125800 -0.022700 +vn 0.991700 0.125400 -0.029100 +vn 0.991200 0.129600 -0.028300 +vn 0.991400 0.130600 -0.009500 +vn 0.992000 0.126100 -0.009800 +vn 0.991900 0.126000 -0.016300 +vn 0.991300 0.130300 -0.015800 +vn 0.992600 0.121300 -0.009800 +vn 0.993100 0.116500 -0.010000 +vn 0.993100 0.116300 -0.016700 +vn 0.992500 0.121000 -0.016300 +vn 0.990700 0.127900 -0.046600 +vn 0.991100 0.123900 -0.047900 +vn 0.990900 0.123300 -0.053900 +vn 0.990500 0.127100 -0.052500 +vn 0.991000 0.129100 -0.034500 +vn 0.991500 0.125000 -0.035400 +vn 0.991300 0.124500 -0.041700 +vn 0.990900 0.128500 -0.040600 +vn 0.992200 0.119800 -0.035500 +vn 0.992700 0.115400 -0.036400 +vn 0.992500 0.114900 -0.042800 +vn 0.992000 0.119300 -0.041700 +vn 0.997700 0.063100 -0.025900 +vn 0.998000 0.056600 -0.026500 +vn 0.997800 0.056300 -0.033900 +vn 0.997500 0.062700 -0.033100 +vn 0.997900 0.063600 -0.011200 +vn 0.998300 0.057000 -0.011400 +vn 0.998200 0.056800 -0.019000 +vn 0.997800 0.063400 -0.018600 +vn 0.998700 0.049800 -0.011400 +vn 0.999000 0.042800 -0.011700 +vn 0.998900 0.042600 -0.019400 +vn 0.998600 0.049600 -0.019000 +vn 0.995800 0.088400 -0.024600 +vn 0.996300 0.082700 -0.025300 +vn 0.996100 0.082300 -0.032300 +vn 0.995600 0.088000 -0.031600 +vn 0.996000 0.089000 -0.010600 +vn 0.996500 0.083000 -0.010900 +vn 0.996400 0.082900 -0.018100 +vn 0.995900 0.088700 -0.017700 +vn 0.997000 0.076700 -0.010900 +vn 0.997500 0.070400 -0.011200 +vn 0.997400 0.070200 -0.018600 +vn 0.996900 0.076400 -0.018100 +vn 0.994900 0.086400 -0.051700 +vn 0.995300 0.080900 -0.052900 +vn 0.995000 0.080400 -0.059500 +vn 0.994600 0.085700 -0.058200 +vn 0.995400 0.087500 -0.038400 +vn 0.995900 0.081900 -0.039300 +vn 0.995600 0.081500 -0.046200 +vn 0.995200 0.087000 -0.045100 +vn 0.996400 0.075300 -0.039300 +vn 0.996800 0.069300 -0.040200 +vn 0.996500 0.068900 -0.047200 +vn 0.996100 0.074800 -0.046200 +vn 0.985600 0.086900 -0.145200 +vn 0.985500 0.083500 -0.147700 +vn 0.985100 0.082300 -0.150700 +vn 0.985200 0.085600 -0.148300 +vn 0.986300 0.089500 -0.138600 +vn 0.986300 0.086000 -0.141000 +vn 0.985900 0.084700 -0.144400 +vn 0.985900 0.088200 -0.142000 +vn 0.986800 0.080000 -0.141100 +vn 0.986700 0.076100 -0.143300 +vn 0.986300 0.075000 -0.146700 +vn 0.986400 0.078800 -0.144500 +vn 0.984800 0.103800 -0.139500 +vn 0.984600 0.101200 -0.142400 +vn 0.984300 0.099700 -0.145400 +vn 0.984500 0.102300 -0.142500 +vn 0.985300 0.106800 -0.133000 +vn 0.985300 0.104000 -0.135800 +vn 0.984900 0.102600 -0.139200 +vn 0.985000 0.105300 -0.136300 +vn 0.985800 0.098400 -0.135900 +vn 0.985800 0.095300 -0.138500 +vn 0.985400 0.093900 -0.141900 +vn 0.985500 0.097000 -0.139300 +vn 0.983800 0.097700 -0.150500 +vn 0.983600 0.095300 -0.153500 +vn 0.983300 0.093800 -0.155800 +vn 0.983400 0.095700 -0.154300 +vn 0.984200 0.100800 -0.145300 +vn 0.984100 0.098300 -0.148300 +vn 0.983800 0.096800 -0.150900 +vn 0.984000 0.099200 -0.148000 +vn 0.984600 0.092800 -0.148300 +vn 0.984400 0.089900 -0.151100 +vn 0.984100 0.088500 -0.153800 +vn 0.984300 0.091300 -0.151000 +vn 0.988700 0.096900 -0.114600 +vn 0.988800 0.093000 -0.116800 +vn 0.988400 0.091900 -0.121300 +vn 0.988300 0.095700 -0.119000 +vn 0.989500 0.099200 -0.105300 +vn 0.989600 0.095200 -0.107400 +vn 0.989200 0.094100 -0.112200 +vn 0.989100 0.098100 -0.110000 +vn 0.990200 0.089000 -0.107500 +vn 0.990400 0.084500 -0.109400 +vn 0.989900 0.083500 -0.114300 +vn 0.989800 0.087900 -0.112300 +vn 0.987300 0.115200 -0.109600 +vn 0.987400 0.112100 -0.112100 +vn 0.987000 0.110800 -0.116500 +vn 0.986900 0.113900 -0.113900 +vn 0.987900 0.117800 -0.100500 +vn 0.988100 0.114500 -0.102900 +vn 0.987700 0.113300 -0.107600 +vn 0.987600 0.116500 -0.105100 +vn 0.988700 0.108800 -0.102900 +vn 0.988900 0.105200 -0.105200 +vn 0.988500 0.104000 -0.110000 +vn 0.988400 0.107600 -0.107600 +vn 0.986000 0.109700 -0.125900 +vn 0.985900 0.106800 -0.128600 +vn 0.985600 0.105400 -0.132300 +vn 0.985600 0.108300 -0.129500 +vn 0.986600 0.112500 -0.118000 +vn 0.986600 0.109500 -0.120700 +vn 0.986300 0.108200 -0.124700 +vn 0.986300 0.111100 -0.122000 +vn 0.987200 0.103800 -0.120700 +vn 0.987300 0.100400 -0.123200 +vn 0.986900 0.099200 -0.127300 +vn 0.986900 0.102500 -0.124800 +vn 0.991000 0.053200 -0.122600 +vn 0.991100 0.047900 -0.123900 +vn 0.990600 0.047200 -0.128500 +vn 0.990500 0.052500 -0.127100 +vn 0.992100 0.054700 -0.113000 +vn 0.992200 0.049200 -0.114300 +vn 0.991700 0.048500 -0.119200 +vn 0.991600 0.054000 -0.117900 +vn 0.992500 0.042300 -0.114300 +vn 0.992700 0.036400 -0.115400 +vn 0.992100 0.035900 -0.120300 +vn 0.992000 0.041700 -0.119300 +vn 0.990000 0.076100 -0.119000 +vn 0.990100 0.071500 -0.120900 +vn 0.989600 0.070500 -0.125400 +vn 0.989500 0.075100 -0.123500 +vn 0.990900 0.078100 -0.109500 +vn 0.991100 0.073300 -0.111300 +vn 0.990600 0.072400 -0.116200 +vn 0.990400 0.077100 -0.114400 +vn 0.991500 0.066700 -0.111400 +vn 0.991700 0.061500 -0.112900 +vn 0.991200 0.060700 -0.117800 +vn 0.991000 0.065800 -0.116200 +vn 0.988100 0.072100 -0.136000 +vn 0.988100 0.067700 -0.137900 +vn 0.987700 0.066800 -0.141700 +vn 0.987600 0.071100 -0.139700 +vn 0.989000 0.074100 -0.127900 +vn 0.989100 0.069600 -0.129700 +vn 0.988600 0.068700 -0.133900 +vn 0.988600 0.073100 -0.132000 +vn 0.989500 0.063200 -0.129800 +vn 0.989600 0.058300 -0.131400 +vn 0.989100 0.057500 -0.135600 +vn 0.989000 0.062300 -0.134000 +vn 0.992000 0.003200 0.126100 +vn 0.992000 0.000000 0.126200 +vn 0.992600 0.000000 0.121500 +vn 0.992600 0.003300 0.121500 +vn 0.990800 0.003100 0.135100 +vn 0.990800 0.000000 0.135100 +vn 0.991400 0.000000 0.130700 +vn 0.991400 0.003200 0.130700 +vn 0.990800 -0.003200 0.135100 +vn 0.990800 -0.009400 0.134900 +vn 0.991400 -0.009500 0.130600 +vn 0.991400 -0.003200 0.130700 +vn 0.991700 0.028700 0.125100 +vn 0.991800 0.022400 0.125500 +vn 0.992400 0.023000 0.121000 +vn 0.992200 0.029500 0.120700 +vn 0.990600 0.027900 0.134000 +vn 0.990700 0.021700 0.134400 +vn 0.991200 0.022400 0.130300 +vn 0.991100 0.028700 0.130000 +vn 0.990800 0.015600 0.134700 +vn 0.990800 0.009400 0.134900 +vn 0.991400 0.009600 0.130700 +vn 0.991300 0.016000 0.130500 +vn 0.994000 0.030300 0.105000 +vn 0.994100 0.023700 0.105400 +vn 0.994700 0.024300 0.100200 +vn 0.994500 0.031100 0.099900 +vn 0.992900 0.029500 0.115400 +vn 0.993000 0.023000 0.115800 +vn 0.993500 0.023700 0.111000 +vn 0.993400 0.030300 0.110700 +vn 0.993100 0.016500 0.116100 +vn 0.993200 0.009900 0.116400 +vn 0.993700 0.010200 0.111400 +vn 0.993600 0.017000 0.111200 +vn 0.987500 0.002800 0.157400 +vn 0.987500 -0.000000 0.157400 +vn 0.988000 0.000000 0.154200 +vn 0.988000 0.002900 0.154200 +vn 0.986600 0.002700 0.163400 +vn 0.986600 0.000000 0.163400 +vn 0.987000 -0.000000 0.160500 +vn 0.987000 0.002800 0.160500 +vn 0.986600 -0.002800 0.163400 +vn 0.986600 -0.008200 0.163200 +vn 0.987000 -0.008400 0.160300 +vn 0.987000 -0.002800 0.160500 +vn 0.987400 0.025400 0.156300 +vn 0.987400 0.019800 0.156700 +vn 0.987900 0.020400 0.153700 +vn 0.987800 0.026200 0.153400 +vn 0.986400 0.024600 0.162300 +vn 0.986500 0.019200 0.162700 +vn 0.986900 0.019800 0.160100 +vn 0.986800 0.025400 0.159800 +vn 0.986500 0.013700 0.163000 +vn 0.986600 0.008200 0.163200 +vn 0.987000 0.008500 0.160500 +vn 0.987000 0.014200 0.160300 +vn 0.989500 0.027100 0.142100 +vn 0.989600 0.021100 0.142500 +vn 0.990100 0.021700 0.138800 +vn 0.990000 0.027900 0.138500 +vn 0.988400 0.026200 0.149600 +vn 0.988500 0.020500 0.150000 +vn 0.989000 0.021100 0.146700 +vn 0.988900 0.027000 0.146300 +vn 0.988500 0.014600 0.150300 +vn 0.988600 0.008800 0.150500 +vn 0.989100 0.009100 0.147000 +vn 0.989000 0.015100 0.146900 +vn 0.987100 -0.037000 0.155800 +vn 0.987100 -0.041900 0.154500 +vn 0.987600 -0.042600 0.151300 +vn 0.987600 -0.037600 0.152500 +vn 0.986200 -0.035900 0.161800 +vn 0.986200 -0.040600 0.160500 +vn 0.986600 -0.041200 0.157600 +vn 0.986600 -0.036400 0.158800 +vn 0.985900 -0.046500 0.160500 +vn 0.986000 -0.050900 0.159000 +vn 0.986400 -0.051700 0.156100 +vn 0.986400 -0.047300 0.157600 +vn 0.987500 -0.014400 0.157200 +vn 0.987400 -0.019800 0.156700 +vn 0.988000 -0.020100 0.153400 +vn 0.988000 -0.014600 0.154000 +vn 0.986500 -0.013900 0.163200 +vn 0.986500 -0.019200 0.162700 +vn 0.987000 -0.019500 0.159800 +vn 0.987000 -0.014200 0.160300 +vn 0.986400 -0.025000 0.162700 +vn 0.986400 -0.030000 0.161800 +vn 0.986800 -0.030500 0.158900 +vn 0.986800 -0.025400 0.159800 +vn 0.989600 -0.015300 0.143100 +vn 0.989600 -0.021100 0.142500 +vn 0.990100 -0.021400 0.138500 +vn 0.990200 -0.015600 0.139100 +vn 0.988500 -0.014900 0.150500 +vn 0.988500 -0.020500 0.150000 +vn 0.989000 -0.020800 0.146400 +vn 0.989000 -0.015100 0.146900 +vn 0.988300 -0.026600 0.150000 +vn 0.988300 -0.032000 0.149100 +vn 0.988800 -0.032500 0.145400 +vn 0.988900 -0.027000 0.146300 +vn 0.988700 0.096900 0.114600 +vn 0.989000 0.091900 0.115800 +vn 0.989200 0.094100 0.112200 +vn 0.988900 0.099100 0.111100 +vn 0.987900 0.094500 0.123300 +vn 0.988200 0.089600 0.124500 +vn 0.988400 0.091900 0.121300 +vn 0.988000 0.096800 0.120200 +vn 0.988500 0.084600 0.125700 +vn 0.988700 0.079400 0.126800 +vn 0.989000 0.081500 0.123500 +vn 0.988700 0.086700 0.122400 +vn 0.987300 0.115200 0.109600 +vn 0.987600 0.110900 0.110900 +vn 0.987700 0.113300 0.107600 +vn 0.987300 0.117700 0.106300 +vn 0.986600 0.112500 0.118000 +vn 0.986900 0.108200 0.119400 +vn 0.987000 0.110800 0.116500 +vn 0.986700 0.115200 0.115200 +vn 0.987200 0.103800 0.120700 +vn 0.987600 0.099200 0.122000 +vn 0.987700 0.101600 0.119000 +vn 0.987300 0.106300 0.117700 +vn 0.988600 0.120200 0.090800 +vn 0.989000 0.115800 0.091900 +vn 0.989100 0.117900 0.087800 +vn 0.988700 0.122400 0.086700 +vn 0.987900 0.117800 0.100500 +vn 0.988300 0.113400 0.101700 +vn 0.988400 0.115700 0.098000 +vn 0.988000 0.120200 0.096800 +vn 0.988700 0.108800 0.102900 +vn 0.989100 0.104100 0.104100 +vn 0.989300 0.106300 0.100300 +vn 0.988900 0.111100 0.099100 +vn 0.985600 0.086900 0.145200 +vn 0.985800 0.082300 0.146500 +vn 0.985900 0.084700 0.144400 +vn 0.985600 0.089400 0.143200 +vn 0.984900 0.084300 0.151100 +vn 0.985100 0.079800 0.152500 +vn 0.985100 0.082300 0.150700 +vn 0.984900 0.086800 0.149500 +vn 0.985200 0.075300 0.153700 +vn 0.985400 0.070600 0.154900 +vn 0.985500 0.072800 0.153100 +vn 0.985300 0.077600 0.151900 +vn 0.984800 0.103800 0.139500 +vn 0.985000 0.099800 0.141000 +vn 0.984900 0.102600 0.139200 +vn 0.984700 0.106700 0.137800 +vn 0.984200 0.102300 0.144900 +vn 0.984400 0.096800 0.146900 +vn 0.984300 0.099700 0.145400 +vn 0.984100 0.103700 0.143900 +vn 0.984600 0.092800 0.148300 +vn 0.984700 0.088600 0.149800 +vn 0.984700 0.091300 0.148200 +vn 0.984500 0.095600 0.146800 +vn 0.986000 0.109700 0.125900 +vn 0.986200 0.105500 0.127300 +vn 0.986300 0.108200 0.124700 +vn 0.986000 0.112400 0.123300 +vn 0.985300 0.106800 0.133000 +vn 0.985600 0.102700 0.134500 +vn 0.985600 0.105400 0.132300 +vn 0.985300 0.109600 0.130900 +vn 0.985800 0.098400 0.135900 +vn 0.986100 0.094000 0.137300 +vn 0.986100 0.096600 0.135000 +vn 0.985900 0.101100 0.133600 +vn 0.987000 0.047300 0.153800 +vn 0.987100 0.041900 0.154500 +vn 0.987400 0.043200 0.151900 +vn 0.987300 0.048800 0.151200 +vn 0.986100 0.045800 0.159800 +vn 0.986200 0.040600 0.160500 +vn 0.986500 0.041900 0.158300 +vn 0.986400 0.047300 0.157600 +vn 0.986300 0.035300 0.161200 +vn 0.986400 0.030000 0.161800 +vn 0.986700 0.030900 0.159400 +vn 0.986600 0.036400 0.158800 +vn 0.986300 0.067900 0.150000 +vn 0.986500 0.062900 0.151100 +vn 0.986700 0.064800 0.148700 +vn 0.986500 0.070000 0.147800 +vn 0.985600 0.065800 0.156000 +vn 0.985700 0.060900 0.157100 +vn 0.985900 0.062900 0.155100 +vn 0.985700 0.067900 0.154100 +vn 0.985800 0.056000 0.158100 +vn 0.986000 0.050900 0.159000 +vn 0.986200 0.052500 0.156800 +vn 0.986100 0.057800 0.156000 +vn 0.988100 0.072100 0.136000 +vn 0.988300 0.066800 0.137000 +vn 0.988600 0.068700 0.133900 +vn 0.988400 0.074100 0.132900 +vn 0.987200 0.070000 0.143400 +vn 0.987400 0.064900 0.144400 +vn 0.987700 0.066800 0.141700 +vn 0.987400 0.072000 0.140700 +vn 0.987600 0.059600 0.145400 +vn 0.987800 0.054200 0.146300 +vn 0.988100 0.055900 0.143400 +vn 0.987900 0.061400 0.142600 +vn 0.993600 0.110700 0.023400 +vn 0.994100 0.105400 0.023700 +vn 0.994200 0.106000 0.017200 +vn 0.993600 0.111200 0.017000 +vn 0.993300 0.109800 0.036400 +vn 0.993800 0.104500 0.036900 +vn 0.994000 0.105400 0.030700 +vn 0.993400 0.110700 0.030300 +vn 0.994400 0.099100 0.037400 +vn 0.994900 0.093400 0.037900 +vn 0.995000 0.094200 0.031500 +vn 0.994500 0.099900 0.031100 +vn 0.991300 0.130000 0.022100 +vn 0.991800 0.125500 0.022400 +vn 0.991900 0.126000 0.016300 +vn 0.991300 0.130500 0.016000 +vn 0.991000 0.129100 0.034500 +vn 0.991600 0.124600 0.035000 +vn 0.991700 0.125400 0.029100 +vn 0.991100 0.130000 0.028700 +vn 0.992200 0.119800 0.035500 +vn 0.992700 0.114900 0.036000 +vn 0.992800 0.115800 0.029900 +vn 0.992200 0.120700 0.029500 +vn 0.991400 0.130700 0.000000 +vn 0.992000 0.126200 0.000000 +vn 0.992000 0.126200 -0.003300 +vn 0.991400 0.130700 -0.003200 +vn 0.991400 0.130600 0.009500 +vn 0.992000 0.126000 0.009600 +vn 0.992000 0.126200 0.003300 +vn 0.991400 0.130700 0.003200 +vn 0.992600 0.121300 0.009800 +vn 0.993200 0.116400 0.009900 +vn 0.993200 0.116500 0.003400 +vn 0.992600 0.121500 0.003300 +vn 0.991700 0.105400 0.073300 +vn 0.992200 0.100200 0.074200 +vn 0.992400 0.101800 0.069100 +vn 0.991900 0.107100 0.068300 +vn 0.991000 0.103500 0.084600 +vn 0.991500 0.098300 0.085600 +vn 0.991700 0.100100 0.080800 +vn 0.991200 0.105400 0.079900 +vn 0.991900 0.093000 0.086500 +vn 0.992300 0.087500 0.087500 +vn 0.992600 0.089200 0.082600 +vn 0.992100 0.094700 0.081700 +vn 0.989800 0.124500 0.069700 +vn 0.990300 0.120000 0.070600 +vn 0.990400 0.121800 0.065800 +vn 0.989900 0.126300 0.064900 +vn 0.989200 0.122500 0.080500 +vn 0.989700 0.118000 0.081500 +vn 0.989800 0.120000 0.077100 +vn 0.989300 0.124500 0.076100 +vn 0.990100 0.113300 0.082600 +vn 0.990600 0.108500 0.083600 +vn 0.990700 0.110400 0.079000 +vn 0.990300 0.115300 0.078000 +vn 0.990700 0.127900 0.046600 +vn 0.991200 0.123300 0.047200 +vn 0.991300 0.124500 0.041700 +vn 0.990800 0.129100 0.041100 +vn 0.990300 0.126300 0.058300 +vn 0.990800 0.121800 0.059100 +vn 0.990900 0.123300 0.053900 +vn 0.990400 0.127800 0.053200 +vn 0.991300 0.117100 0.059900 +vn 0.991800 0.112200 0.060700 +vn 0.992000 0.113700 0.055400 +vn 0.991400 0.118600 0.054700 +vn 0.995100 0.058900 0.079700 +vn 0.995400 0.052300 0.080400 +vn 0.995800 0.053500 0.074700 +vn 0.995400 0.060100 0.074200 +vn 0.994100 0.057500 0.091500 +vn 0.994400 0.051100 0.092200 +vn 0.994800 0.052300 0.087000 +vn 0.994500 0.058800 0.086400 +vn 0.994700 0.044600 0.092800 +vn 0.994900 0.037900 0.093400 +vn 0.995400 0.038800 0.088000 +vn 0.995100 0.045600 0.087500 +vn 0.993500 0.083500 0.076800 +vn 0.994000 0.077600 0.077600 +vn 0.994300 0.079000 0.072200 +vn 0.993800 0.085000 0.071400 +vn 0.992700 0.081800 0.088300 +vn 0.993100 0.075900 0.089200 +vn 0.993400 0.077500 0.084200 +vn 0.993000 0.083400 0.083400 +vn 0.993500 0.069900 0.090000 +vn 0.993800 0.063800 0.090800 +vn 0.994200 0.065200 0.085700 +vn 0.993800 0.071400 0.085000 +vn 0.994900 0.086400 0.051700 +vn 0.995400 0.080400 0.052300 +vn 0.995600 0.081500 0.046200 +vn 0.995100 0.087500 0.045600 +vn 0.994300 0.085000 0.064500 +vn 0.994700 0.079100 0.065200 +vn 0.995000 0.080400 0.059500 +vn 0.994500 0.086400 0.058800 +vn 0.995200 0.072900 0.065900 +vn 0.995600 0.066600 0.066600 +vn 0.995900 0.067800 0.060700 +vn 0.995400 0.074200 0.060100 +vn 0.989100 -0.087800 0.117900 +vn 0.989000 -0.091900 0.115800 +vn 0.989400 -0.093100 0.111200 +vn 0.989600 -0.088900 0.113300 +vn 0.988200 -0.085600 0.126700 +vn 0.988200 -0.089600 0.124500 +vn 0.988600 -0.090800 0.120200 +vn 0.988700 -0.086700 0.122400 +vn 0.987600 -0.095600 0.124400 +vn 0.987600 -0.099200 0.122000 +vn 0.987900 -0.100500 0.117800 +vn 0.988000 -0.096800 0.120200 +vn 0.990400 -0.065800 0.121700 +vn 0.990300 -0.070600 0.120000 +vn 0.990800 -0.071500 0.115300 +vn 0.990900 -0.066600 0.117000 +vn 0.989400 -0.064000 0.130600 +vn 0.989300 -0.068700 0.128900 +vn 0.989800 -0.069700 0.124500 +vn 0.989900 -0.064900 0.126300 +vn 0.988800 -0.075100 0.128800 +vn 0.988700 -0.079400 0.126800 +vn 0.989200 -0.080500 0.122500 +vn 0.989300 -0.076100 0.124500 +vn 0.992400 -0.069100 0.101800 +vn 0.992200 -0.074200 0.100200 +vn 0.992700 -0.075100 0.094800 +vn 0.992900 -0.069900 0.096400 +vn 0.991400 -0.067500 0.112100 +vn 0.991200 -0.072400 0.110500 +vn 0.991700 -0.073300 0.105400 +vn 0.991900 -0.068300 0.107100 +vn 0.990700 -0.079000 0.110400 +vn 0.990600 -0.083600 0.108500 +vn 0.991000 -0.084600 0.103500 +vn 0.991200 -0.079900 0.105400 +vn 0.985700 -0.078800 0.148900 +vn 0.985800 -0.082300 0.146500 +vn 0.986100 -0.083600 0.143300 +vn 0.986100 -0.079900 0.145600 +vn 0.985000 -0.076400 0.154800 +vn 0.985100 -0.079800 0.152500 +vn 0.985400 -0.081100 0.149600 +vn 0.985300 -0.077600 0.151900 +vn 0.984600 -0.085500 0.152400 +vn 0.984700 -0.088600 0.149800 +vn 0.985100 -0.089900 0.146900 +vn 0.984900 -0.086800 0.149500 +vn 0.986500 -0.058700 0.152900 +vn 0.986500 -0.062900 0.151100 +vn 0.986900 -0.063900 0.147800 +vn 0.986900 -0.059600 0.149700 +vn 0.985700 -0.056800 0.158900 +vn 0.985700 -0.060900 0.157100 +vn 0.986100 -0.061900 0.154200 +vn 0.986100 -0.057800 0.156000 +vn 0.985300 -0.066800 0.157000 +vn 0.985400 -0.070600 0.154900 +vn 0.985800 -0.071700 0.152000 +vn 0.985700 -0.067900 0.154100 +vn 0.988400 -0.062200 0.138800 +vn 0.988300 -0.066800 0.137000 +vn 0.988800 -0.067800 0.133000 +vn 0.988900 -0.063100 0.134800 +vn 0.987400 -0.060500 0.146200 +vn 0.987400 -0.064900 0.144400 +vn 0.987900 -0.065800 0.140800 +vn 0.987900 -0.061400 0.142600 +vn 0.987000 -0.071000 0.144300 +vn 0.987000 -0.075100 0.142300 +vn 0.987400 -0.076200 0.138700 +vn 0.987400 -0.072000 0.140700 +vn 0.984000 -0.113000 0.137900 +vn 0.984200 -0.115000 0.134800 +vn 0.984400 -0.116700 0.131700 +vn 0.984200 -0.114500 0.134700 +vn 0.983500 -0.109800 0.143700 +vn 0.983800 -0.111700 0.140500 +vn 0.984000 -0.113400 0.137700 +vn 0.983700 -0.111400 0.140900 +vn 0.983200 -0.116700 0.140400 +vn 0.983300 -0.118000 0.138700 +vn 0.983600 -0.120100 0.134300 +vn 0.983400 -0.118400 0.137600 +vn 0.984800 -0.097000 0.143800 +vn 0.985000 -0.099800 0.141000 +vn 0.985300 -0.101200 0.137800 +vn 0.985200 -0.098300 0.140600 +vn 0.984200 -0.094100 0.149700 +vn 0.984400 -0.096800 0.146900 +vn 0.984700 -0.098300 0.144000 +vn 0.984500 -0.095600 0.146800 +vn 0.983900 -0.102200 0.146800 +vn 0.984100 -0.104600 0.143700 +vn 0.984300 -0.106100 0.140900 +vn 0.984100 -0.103700 0.143900 +vn 0.986200 -0.102400 0.129900 +vn 0.986200 -0.105500 0.127300 +vn 0.986600 -0.106900 0.123400 +vn 0.986600 -0.103700 0.126000 +vn 0.985500 -0.099700 0.137200 +vn 0.985600 -0.102700 0.134500 +vn 0.985900 -0.104100 0.131000 +vn 0.985900 -0.101100 0.133600 +vn 0.985000 -0.108200 0.134400 +vn 0.985100 -0.110800 0.131500 +vn 0.985400 -0.112300 0.128000 +vn 0.985300 -0.109600 0.130900 +vn 0.994700 -0.100200 0.024300 +vn 0.994100 -0.105400 0.023700 +vn 0.994200 -0.105700 0.017000 +vn 0.994800 -0.100500 0.017400 +vn 0.994300 -0.099500 0.037900 +vn 0.993800 -0.104500 0.036900 +vn 0.994000 -0.105000 0.030300 +vn 0.994500 -0.099900 0.031100 +vn 0.993200 -0.110300 0.036900 +vn 0.992700 -0.114900 0.036000 +vn 0.992900 -0.115400 0.029500 +vn 0.993400 -0.110700 0.030300 +vn 0.996700 -0.076400 0.025600 +vn 0.996300 -0.082400 0.025000 +vn 0.996400 -0.082700 0.017900 +vn 0.996900 -0.076700 0.018300 +vn 0.996300 -0.075700 0.039800 +vn 0.995900 -0.081500 0.038900 +vn 0.996100 -0.082000 0.032000 +vn 0.996600 -0.076100 0.032700 +vn 0.995400 -0.088000 0.038800 +vn 0.994900 -0.093400 0.037900 +vn 0.995100 -0.093900 0.031200 +vn 0.995600 -0.088400 0.031900 +vn 0.997000 -0.076900 0.000000 +vn 0.996500 -0.083100 0.000000 +vn 0.996500 -0.083000 -0.003600 +vn 0.997000 -0.076800 -0.003600 +vn 0.997000 -0.076800 0.011000 +vn 0.996500 -0.082900 0.010800 +vn 0.996500 -0.083000 0.003600 +vn 0.997000 -0.076900 0.003700 +vn 0.996000 -0.089100 0.010700 +vn 0.995400 -0.094800 0.010500 +vn 0.995500 -0.094900 0.003500 +vn 0.996000 -0.089100 0.003600 +vn 0.992500 -0.095600 0.075900 +vn 0.992200 -0.100200 0.074200 +vn 0.992500 -0.101100 0.068300 +vn 0.992900 -0.096400 0.069900 +vn 0.991700 -0.093800 0.087400 +vn 0.991500 -0.098300 0.085600 +vn 0.991800 -0.099300 0.080000 +vn 0.992100 -0.094700 0.081700 +vn 0.990900 -0.104400 0.085500 +vn 0.990600 -0.108500 0.083600 +vn 0.990900 -0.109500 0.078100 +vn 0.991200 -0.105400 0.079900 +vn 0.994300 -0.072200 0.079000 +vn 0.994000 -0.077600 0.077600 +vn 0.994400 -0.078300 0.071500 +vn 0.994700 -0.072900 0.072900 +vn 0.993400 -0.070700 0.090800 +vn 0.993100 -0.075900 0.089200 +vn 0.993500 -0.076800 0.083500 +vn 0.993800 -0.071400 0.085000 +vn 0.992600 -0.082600 0.089200 +vn 0.992300 -0.087500 0.087500 +vn 0.992700 -0.088300 0.081800 +vn 0.993000 -0.083400 0.083400 +vn 0.995800 -0.074700 0.053500 +vn 0.995400 -0.080400 0.052300 +vn 0.995700 -0.081000 0.045700 +vn 0.996100 -0.075300 0.046700 +vn 0.995100 -0.073500 0.066600 +vn 0.994700 -0.079100 0.065200 +vn 0.995100 -0.079700 0.058900 +vn 0.995400 -0.074200 0.060100 +vn 0.994200 -0.085700 0.065200 +vn 0.993800 -0.090800 0.063800 +vn 0.994100 -0.091500 0.057500 +vn 0.994500 -0.086400 0.058800 +vn 0.988600 -0.133900 0.068700 +vn 0.988300 -0.137000 0.066800 +vn 0.988500 -0.137900 0.061400 +vn 0.988900 -0.134800 0.063100 +vn 0.988100 -0.131900 0.079400 +vn 0.987800 -0.134900 0.077300 +vn 0.988100 -0.136000 0.072100 +vn 0.988400 -0.132900 0.074100 +vn 0.987200 -0.139700 0.077200 +vn 0.987000 -0.142300 0.075100 +vn 0.987200 -0.143400 0.070000 +vn 0.987400 -0.140700 0.072000 +vn 0.990600 -0.116200 0.072400 +vn 0.990300 -0.120000 0.070600 +vn 0.990500 -0.120900 0.064900 +vn 0.990900 -0.117000 0.066600 +vn 0.989900 -0.114300 0.083500 +vn 0.989700 -0.118000 0.081500 +vn 0.990000 -0.119000 0.076100 +vn 0.990300 -0.115300 0.078000 +vn 0.989000 -0.123500 0.081500 +vn 0.988700 -0.126800 0.079400 +vn 0.989000 -0.127900 0.074100 +vn 0.989300 -0.124500 0.076100 +vn 0.991700 -0.119200 0.048500 +vn 0.991200 -0.123300 0.047200 +vn 0.991400 -0.124000 0.041100 +vn 0.991900 -0.119800 0.042300 +vn 0.991200 -0.117800 0.060700 +vn 0.990800 -0.121800 0.059100 +vn 0.991000 -0.122600 0.053200 +vn 0.991400 -0.118600 0.054700 +vn 0.990100 -0.127100 0.059100 +vn 0.989800 -0.130700 0.057500 +vn 0.990000 -0.131500 0.051800 +vn 0.990400 -0.127800 0.053200 +vn 0.999600 0.004000 0.027900 +vn 0.999600 -0.000000 0.027900 +vn 0.999800 0.000000 0.020200 +vn 0.999800 0.004100 0.020200 +vn 0.999100 0.003900 0.042800 +vn 0.999100 0.000000 0.042800 +vn 0.999400 0.000000 0.035500 +vn 0.999400 0.004000 0.035500 +vn 0.999100 -0.003900 0.042800 +vn 0.999000 -0.011600 0.042700 +vn 0.999300 -0.011700 0.035300 +vn 0.999400 -0.004000 0.035500 +vn 0.999000 0.034800 0.027100 +vn 0.999300 0.027300 0.027300 +vn 0.999400 0.027700 0.019800 +vn 0.999200 0.035300 0.019600 +vn 0.998500 0.034200 0.041800 +vn 0.998800 0.026800 0.042200 +vn 0.999000 0.027300 0.035100 +vn 0.998800 0.034800 0.034800 +vn 0.998900 0.019200 0.042400 +vn 0.999000 0.011600 0.042700 +vn 0.999300 0.011800 0.035400 +vn 0.999200 0.019600 0.035300 +vn 0.999400 0.035500 0.000000 +vn 0.999600 0.027900 0.000000 +vn 0.999600 0.027900 -0.004000 +vn 0.999400 0.035400 -0.003900 +vn 0.999300 0.035300 0.011700 +vn 0.999500 0.027700 0.011900 +vn 0.999600 0.027900 0.004000 +vn 0.999400 0.035500 0.004000 +vn 0.999700 0.020000 0.012000 +vn 0.999900 0.012100 0.012100 +vn 0.999900 0.012200 0.004100 +vn 0.999800 0.020200 0.004100 +vn 0.996500 0.003600 0.083000 +vn 0.996500 -0.000000 0.083100 +vn 0.997000 -0.000000 0.076900 +vn 0.997000 0.003700 0.076900 +vn 0.995500 0.003500 0.094900 +vn 0.995500 0.000000 0.095000 +vn 0.996000 -0.000000 0.089100 +vn 0.996000 0.003600 0.089100 +vn 0.995500 -0.003500 0.095000 +vn 0.995400 -0.010500 0.094800 +vn 0.996000 -0.010600 0.089000 +vn 0.996000 -0.003600 0.089100 +vn 0.996100 0.032000 0.082000 +vn 0.996300 0.025000 0.082400 +vn 0.996700 0.025600 0.076400 +vn 0.996600 0.032700 0.076100 +vn 0.995100 0.031200 0.093900 +vn 0.995300 0.024300 0.094300 +vn 0.995700 0.024900 0.088700 +vn 0.995600 0.031900 0.088400 +vn 0.995400 0.017400 0.094600 +vn 0.995400 0.010500 0.094800 +vn 0.996000 0.010700 0.089100 +vn 0.995900 0.017900 0.088900 +vn 0.997900 0.033500 0.055900 +vn 0.998100 0.026200 0.056300 +vn 0.998400 0.026800 0.049600 +vn 0.998200 0.034200 0.049300 +vn 0.997100 0.032700 0.069300 +vn 0.997200 0.025600 0.069700 +vn 0.997600 0.026200 0.063400 +vn 0.997400 0.033500 0.063100 +vn 0.997400 0.018300 0.070000 +vn 0.997500 0.011000 0.070200 +vn 0.997900 0.011300 0.063800 +vn 0.997800 0.018800 0.063600 +vn 0.995600 -0.046200 0.081500 +vn 0.995400 -0.052300 0.080400 +vn 0.995800 -0.052900 0.074200 +vn 0.996100 -0.046700 0.075300 +vn 0.994600 -0.045100 0.093400 +vn 0.994400 -0.051100 0.092200 +vn 0.994900 -0.051700 0.086400 +vn 0.995100 -0.045600 0.087500 +vn 0.994000 -0.058200 0.092200 +vn 0.993800 -0.063800 0.090800 +vn 0.994300 -0.064500 0.085000 +vn 0.994500 -0.058800 0.086400 +vn 0.996400 -0.018100 0.082900 +vn 0.996300 -0.025000 0.082400 +vn 0.996800 -0.025300 0.076100 +vn 0.996900 -0.018300 0.076700 +vn 0.995300 -0.017600 0.094800 +vn 0.995300 -0.024300 0.094300 +vn 0.995800 -0.024600 0.088400 +vn 0.995900 -0.017900 0.088900 +vn 0.995000 -0.031500 0.094200 +vn 0.994900 -0.037900 0.093400 +vn 0.995400 -0.038400 0.087500 +vn 0.995600 -0.031900 0.088400 +vn 0.998200 -0.019000 0.056800 +vn 0.998100 -0.026200 0.056300 +vn 0.998400 -0.026500 0.049300 +vn 0.998600 -0.019200 0.049800 +vn 0.997400 -0.018600 0.070200 +vn 0.997200 -0.025600 0.069700 +vn 0.997700 -0.025900 0.063100 +vn 0.997800 -0.018800 0.063600 +vn 0.997000 -0.033100 0.069700 +vn 0.996800 -0.039800 0.068900 +vn 0.997200 -0.040200 0.062300 +vn 0.997400 -0.033500 0.063100 +vn 0.987500 0.002800 -0.157400 +vn 0.987500 0.000000 -0.157400 +vn 0.987000 -0.000000 -0.160500 +vn 0.987000 0.002800 -0.160500 +vn 0.988600 0.002900 -0.150700 +vn 0.988600 0.000000 -0.150700 +vn 0.988000 0.000000 -0.154200 +vn 0.988000 0.002900 -0.154100 +vn 0.988600 -0.003000 -0.150700 +vn 0.988500 -0.008900 -0.150700 +vn 0.988000 -0.008700 -0.154000 +vn 0.988000 -0.002900 -0.154100 +vn 0.987400 0.025400 -0.156300 +vn 0.987400 0.020100 -0.157000 +vn 0.986900 0.019800 -0.160100 +vn 0.986900 0.025000 -0.159400 +vn 0.988400 0.026200 -0.149600 +vn 0.988400 0.020800 -0.150300 +vn 0.987900 0.020400 -0.153700 +vn 0.987900 0.025800 -0.153000 +vn 0.988500 0.014600 -0.150300 +vn 0.988500 0.008900 -0.150700 +vn 0.988000 0.008800 -0.154100 +vn 0.988000 0.014400 -0.153700 +vn 0.985600 0.023800 -0.167600 +vn 0.985600 0.018800 -0.168300 +vn 0.985200 0.018500 -0.170700 +vn 0.985200 0.023400 -0.169900 +vn 0.986400 0.024600 -0.162300 +vn 0.986400 0.019500 -0.163000 +vn 0.986000 0.019200 -0.165700 +vn 0.986000 0.024200 -0.165000 +vn 0.986500 0.013700 -0.163000 +vn 0.986500 0.008400 -0.163400 +vn 0.986100 0.008200 -0.166100 +vn 0.986100 0.013500 -0.165700 +vn 0.992000 0.003200 -0.126100 +vn 0.992000 0.000000 -0.126200 +vn 0.991400 0.000000 -0.130700 +vn 0.991400 0.003200 -0.130700 +vn 0.993200 0.003300 -0.116500 +vn 0.993200 0.000000 -0.116500 +vn 0.992600 0.000000 -0.121500 +vn 0.992600 0.003300 -0.121400 +vn 0.993200 -0.003400 -0.116500 +vn 0.993100 -0.010000 -0.116500 +vn 0.992600 -0.009800 -0.121300 +vn 0.992600 -0.003300 -0.121400 +vn 0.991700 0.028700 -0.125000 +vn 0.991800 0.022700 -0.125800 +vn 0.991200 0.022400 -0.130300 +vn 0.991200 0.028300 -0.129600 +vn 0.992900 0.029500 -0.115400 +vn 0.993000 0.023300 -0.116100 +vn 0.992400 0.023000 -0.121000 +vn 0.992300 0.029100 -0.120300 +vn 0.993100 0.016500 -0.116100 +vn 0.993100 0.010000 -0.116500 +vn 0.992600 0.009900 -0.121400 +vn 0.992500 0.016300 -0.121000 +vn 0.989500 0.027100 -0.142100 +vn 0.989500 0.021400 -0.142800 +vn 0.989000 0.021100 -0.146700 +vn 0.988900 0.026600 -0.145900 +vn 0.990600 0.027900 -0.134000 +vn 0.990600 0.022100 -0.134700 +vn 0.990100 0.021700 -0.138900 +vn 0.990000 0.027500 -0.138100 +vn 0.990800 0.015600 -0.134700 +vn 0.990800 0.009500 -0.135100 +vn 0.990200 0.009300 -0.139200 +vn 0.990200 0.015300 -0.138900 +vn 0.991300 -0.041700 -0.124500 +vn 0.991100 -0.047900 -0.123900 +vn 0.990700 -0.046600 -0.127900 +vn 0.990900 -0.040600 -0.128500 +vn 0.992500 -0.042800 -0.114900 +vn 0.992200 -0.049200 -0.114300 +vn 0.991800 -0.047900 -0.118600 +vn 0.992000 -0.041700 -0.119300 +vn 0.992000 -0.055400 -0.113700 +vn 0.991700 -0.061500 -0.112900 +vn 0.991300 -0.059900 -0.117100 +vn 0.991600 -0.054000 -0.117900 +vn 0.991900 -0.016300 -0.126000 +vn 0.991800 -0.022700 -0.125800 +vn 0.991300 -0.022100 -0.130000 +vn 0.991300 -0.015800 -0.130300 +vn 0.993100 -0.016700 -0.116300 +vn 0.993000 -0.023300 -0.116100 +vn 0.992400 -0.022700 -0.120700 +vn 0.992500 -0.016300 -0.121000 +vn 0.992800 -0.029900 -0.115800 +vn 0.992700 -0.036400 -0.115400 +vn 0.992200 -0.035500 -0.119800 +vn 0.992300 -0.029100 -0.120300 +vn 0.989600 -0.015300 -0.143100 +vn 0.989500 -0.021400 -0.142800 +vn 0.989000 -0.020800 -0.146400 +vn 0.989100 -0.014900 -0.146700 +vn 0.990700 -0.015800 -0.134900 +vn 0.990600 -0.022100 -0.134700 +vn 0.990100 -0.021400 -0.138500 +vn 0.990200 -0.015300 -0.138900 +vn 0.990500 -0.028300 -0.134300 +vn 0.990400 -0.034400 -0.133900 +vn 0.989900 -0.033500 -0.137600 +vn 0.990000 -0.027500 -0.138100 +vn 0.989100 -0.039400 -0.141600 +vn 0.989000 -0.045200 -0.141000 +vn 0.988600 -0.043900 -0.144200 +vn 0.988700 -0.038200 -0.144900 +vn 0.990200 -0.040500 -0.133400 +vn 0.990000 -0.046500 -0.132800 +vn 0.989600 -0.045300 -0.136400 +vn 0.989800 -0.039400 -0.137100 +vn 0.989800 -0.052500 -0.132200 +vn 0.989600 -0.058300 -0.131400 +vn 0.989200 -0.056700 -0.134800 +vn 0.989400 -0.051000 -0.135700 +vn 0.989700 0.003000 -0.143200 +vn 0.989700 -0.000000 -0.143300 +vn 0.989100 0.000000 -0.147100 +vn 0.989100 0.003000 -0.147000 +vn 0.990800 0.003100 -0.135100 +vn 0.990800 0.000000 -0.135100 +vn 0.990300 -0.000000 -0.139300 +vn 0.990300 0.003100 -0.139200 +vn 0.990800 -0.003200 -0.135100 +vn 0.990800 -0.009500 -0.135100 +vn 0.990200 -0.009200 -0.139100 +vn 0.990300 -0.003100 -0.139200 +vn 0.985700 0.002700 -0.168700 +vn 0.985700 0.000000 -0.168700 +vn 0.985300 0.000000 -0.171100 +vn 0.985300 0.002600 -0.171000 +vn 0.986600 0.002700 -0.163400 +vn 0.986600 -0.000000 -0.163400 +vn 0.986100 0.000000 -0.166100 +vn 0.986100 0.002700 -0.166100 +vn 0.986600 -0.002800 -0.163400 +vn 0.986500 -0.008400 -0.163400 +vn 0.986100 -0.008100 -0.166000 +vn 0.986100 -0.002700 -0.166100 +vn 0.997300 -0.048100 0.055500 +vn 0.997000 -0.054600 0.054600 +vn 0.997300 -0.055100 0.047700 +vn 0.997600 -0.048600 0.048600 +vn 0.996500 -0.047200 0.068900 +vn 0.996300 -0.053500 0.067800 +vn 0.996700 -0.054100 0.061300 +vn 0.996900 -0.047700 0.062300 +vn 0.995900 -0.060700 0.067800 +vn 0.995600 -0.066600 0.066600 +vn 0.995900 -0.067200 0.060100 +vn 0.996200 -0.061300 0.061300 +vn 0.998400 0.003800 0.057000 +vn 0.998400 0.000000 0.057000 +vn 0.998700 0.000000 0.050000 +vn 0.998700 0.003900 0.050000 +vn 0.997500 0.003700 0.070400 +vn 0.997500 0.000000 0.070400 +vn 0.998000 0.000000 0.063800 +vn 0.998000 0.003800 0.063800 +vn 0.997500 -0.003700 0.070400 +vn 0.997500 -0.011000 0.070200 +vn 0.997900 -0.011200 0.063600 +vn 0.998000 -0.003800 0.063800 +vn 1.000000 0.004100 0.000000 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 -0.004100 +vn 1.000000 0.004100 -0.004100 +vn 0.999900 0.004100 0.012200 +vn 0.999900 0.000000 0.012200 +vn 1.000000 -0.000000 0.004100 +vn 1.000000 0.004100 0.004100 +vn 0.999900 -0.004100 0.012200 +vn 0.999900 -0.012100 0.012100 +vn 0.999900 -0.012200 0.004000 +vn 1.000000 -0.004100 0.004100 +vn 0.989500 -0.137000 0.045900 +vn 0.989100 -0.140400 0.044600 +vn 0.989200 -0.141100 0.038800 +vn 0.989700 -0.137600 0.040000 +vn 0.989100 -0.135600 0.057500 +vn 0.988700 -0.138800 0.055900 +vn 0.988900 -0.139600 0.050300 +vn 0.989300 -0.136400 0.051700 +vn 0.988100 -0.143400 0.055900 +vn 0.987800 -0.146300 0.054200 +vn 0.987900 -0.147100 0.048800 +vn 0.988300 -0.144200 0.050300 +vn 0.993800 -0.098500 0.051100 +vn 0.993400 -0.103300 0.049800 +vn 0.993600 -0.104000 0.043400 +vn 0.994100 -0.099000 0.044500 +vn 0.993200 -0.097100 0.063800 +vn 0.992800 -0.101900 0.062300 +vn 0.993100 -0.102600 0.056100 +vn 0.993500 -0.097800 0.057500 +vn 0.992200 -0.107800 0.062300 +vn 0.991800 -0.112200 0.060700 +vn 0.992100 -0.113000 0.054700 +vn 0.992500 -0.108600 0.056100 +vn 0.994900 -0.100700 0.000000 +vn 0.994400 -0.106100 0.000000 +vn 0.994300 -0.106100 -0.003400 +vn 0.994900 -0.100600 -0.003400 +vn 0.994900 -0.100600 0.010500 +vn 0.994300 -0.106000 0.010200 +vn 0.994300 -0.106100 0.003400 +vn 0.994900 -0.100700 0.003500 +vn 0.993700 -0.111400 0.010200 +vn 0.993200 -0.116400 0.009900 +vn 0.993200 -0.116500 0.003300 +vn 0.993800 -0.111400 0.003400 +vn 0.985100 -0.119100 0.124300 +vn 0.985200 -0.121400 0.121400 +vn 0.985400 -0.122900 0.117700 +vn 0.985400 -0.120500 0.120500 +vn 0.984500 -0.116100 0.131400 +vn 0.984600 -0.118300 0.128400 +vn 0.984900 -0.119800 0.125000 +vn 0.984800 -0.117600 0.128000 +vn 0.984000 -0.123300 0.128300 +vn 0.984200 -0.125100 0.125100 +vn 0.984400 -0.126800 0.121800 +vn 0.984300 -0.124900 0.124900 +vn 0.987400 -0.083400 0.134800 +vn 0.987300 -0.087200 0.132500 +vn 0.987700 -0.088400 0.128600 +vn 0.987800 -0.084500 0.130900 +vn 0.986500 -0.081100 0.142200 +vn 0.986500 -0.084800 0.139900 +vn 0.986900 -0.086000 0.136300 +vn 0.986900 -0.082300 0.138600 +vn 0.986000 -0.090700 0.139800 +vn 0.986100 -0.094000 0.137300 +vn 0.986400 -0.095300 0.133700 +vn 0.986400 -0.091900 0.136200 +vn 0.990900 -0.092000 0.098300 +vn 0.990700 -0.096300 0.096300 +vn 0.991100 -0.097300 0.091000 +vn 0.991300 -0.092900 0.092900 +vn 0.990000 -0.089900 0.108400 +vn 0.989900 -0.094200 0.106400 +vn 0.990300 -0.095200 0.101400 +vn 0.990500 -0.091000 0.103400 +vn 0.989300 -0.100300 0.106300 +vn 0.989100 -0.104100 0.104100 +vn 0.989500 -0.105300 0.099200 +vn 0.989700 -0.101400 0.101400 +vn 0.996700 0.061300 0.054000 +vn 0.997000 0.054600 0.054600 +vn 0.997300 0.055500 0.048100 +vn 0.996900 0.062300 0.047700 +vn 0.995900 0.060100 0.067200 +vn 0.996300 0.053500 0.067800 +vn 0.996600 0.054600 0.061800 +vn 0.996200 0.061300 0.061300 +vn 0.996600 0.046700 0.068400 +vn 0.996800 0.039800 0.068900 +vn 0.997200 0.040700 0.062700 +vn 0.996900 0.047700 0.062300 +vn 0.992900 0.108600 0.049200 +vn 0.993400 0.103300 0.049800 +vn 0.993600 0.104500 0.044000 +vn 0.993000 0.109800 0.043400 +vn 0.992300 0.107100 0.061500 +vn 0.992800 0.101900 0.062300 +vn 0.993000 0.103300 0.056800 +vn 0.992500 0.108600 0.056100 +vn 0.993300 0.096400 0.063100 +vn 0.993800 0.090800 0.063800 +vn 0.994000 0.092200 0.058200 +vn 0.993500 0.097800 0.057500 +vn 0.993800 0.111400 0.000000 +vn 0.994400 0.106100 0.000000 +vn 0.994300 0.106100 -0.003400 +vn 0.993800 0.111400 -0.003400 +vn 0.993700 0.111300 0.010100 +vn 0.994300 0.106000 0.010200 +vn 0.994300 0.106100 0.003400 +vn 0.993800 0.111400 0.003400 +vn 0.994900 0.100500 0.010300 +vn 0.995400 0.094800 0.010500 +vn 0.995500 0.095000 0.003500 +vn 0.994900 0.100700 0.003500 +vn 0.988900 0.050300 0.139600 +vn 0.989100 0.044600 0.140400 +vn 0.989500 0.045900 0.137000 +vn 0.989300 0.051700 0.136400 +vn 0.987900 0.048800 0.147100 +vn 0.988100 0.043300 0.147800 +vn 0.988500 0.044600 0.144800 +vn 0.988300 0.050300 0.144200 +vn 0.988200 0.037600 0.148500 +vn 0.988300 0.032000 0.149100 +vn 0.988700 0.032900 0.145900 +vn 0.988600 0.038800 0.145400 +vn 0.987100 0.092000 0.131300 +vn 0.987300 0.087200 0.132500 +vn 0.987500 0.089500 0.129700 +vn 0.987200 0.094400 0.128500 +vn 0.986300 0.089500 0.138600 +vn 0.986500 0.084800 0.139900 +vn 0.986700 0.087200 0.137400 +vn 0.986400 0.091900 0.136200 +vn 0.986800 0.080000 0.141100 +vn 0.987000 0.075100 0.142300 +vn 0.987200 0.077200 0.139700 +vn 0.986900 0.082300 0.138600 +vn 0.990300 0.101400 0.095200 +vn 0.990700 0.096300 0.096300 +vn 0.990900 0.098300 0.091900 +vn 0.990500 0.103400 0.091000 +vn 0.989500 0.099200 0.105300 +vn 0.989900 0.094200 0.106400 +vn 0.990100 0.096200 0.102400 +vn 0.989700 0.101400 0.101400 +vn 0.990200 0.089000 0.107500 +vn 0.990600 0.083600 0.108500 +vn 0.990900 0.085500 0.104400 +vn 0.990500 0.091000 0.103400 +vn 0.989100 -0.039400 0.141600 +vn 0.989100 -0.044600 0.140400 +vn 0.989600 -0.045300 0.136400 +vn 0.989700 -0.040000 0.137600 +vn 0.988100 -0.038200 0.149000 +vn 0.988100 -0.043300 0.147800 +vn 0.988600 -0.043900 0.144200 +vn 0.988600 -0.038800 0.145400 +vn 0.987800 -0.049500 0.147800 +vn 0.987800 -0.054200 0.146300 +vn 0.988200 -0.055100 0.142600 +vn 0.988300 -0.050300 0.144200 +vn 0.989700 0.003000 0.143200 +vn 0.989700 -0.000000 0.143300 +vn 0.990300 0.000000 0.139300 +vn 0.990200 0.003100 0.139300 +vn 0.988600 0.002900 0.150700 +vn 0.988600 0.000000 0.150700 +vn 0.989100 -0.000000 0.147100 +vn 0.989100 0.003000 0.147100 +vn 0.988600 -0.003000 0.150700 +vn 0.988600 -0.008800 0.150500 +vn 0.989100 -0.008900 0.146900 +vn 0.989100 -0.003000 0.147100 +vn 0.994300 0.003400 0.106100 +vn 0.994400 0.000000 0.106100 +vn 0.994900 0.000000 0.100700 +vn 0.994900 0.003500 0.100700 +vn 0.993200 0.003300 0.116500 +vn 0.993200 0.000000 0.116500 +vn 0.993800 0.000000 0.111400 +vn 0.993800 0.003400 0.111400 +vn 0.993200 -0.003400 0.116500 +vn 0.993200 -0.009900 0.116400 +vn 0.993700 -0.010100 0.111300 +vn 0.993800 -0.003400 0.111400 +vn 0.988900 0.050300 -0.139600 +vn 0.989000 0.045200 -0.141000 +vn 0.988500 0.044600 -0.144800 +vn 0.988400 0.049500 -0.143500 +vn 0.990000 0.051800 -0.131500 +vn 0.990000 0.046500 -0.132800 +vn 0.989500 0.045900 -0.137000 +vn 0.989400 0.051000 -0.135700 +vn 0.990300 0.040000 -0.132900 +vn 0.990400 0.034400 -0.133900 +vn 0.989800 0.033900 -0.138100 +vn 0.989800 0.039400 -0.137100 +vn 0.987100 0.092000 -0.131300 +vn 0.987100 0.088400 -0.133700 +vn 0.986700 0.087200 -0.137400 +vn 0.986700 0.090700 -0.135000 +vn 0.987900 0.094500 -0.123300 +vn 0.987900 0.090700 -0.125600 +vn 0.987500 0.089500 -0.129700 +vn 0.987500 0.093300 -0.127400 +vn 0.988500 0.084600 -0.125700 +vn 0.988500 0.080400 -0.127800 +vn 0.988100 0.079400 -0.131900 +vn 0.988000 0.083400 -0.129800 +vn 0.984300 0.081600 -0.156400 +vn 0.984200 0.078500 -0.158900 +vn 0.983900 0.077200 -0.161300 +vn 0.984100 0.080300 -0.158700 +vn 0.984900 0.084300 -0.151100 +vn 0.984800 0.081000 -0.153600 +vn 0.984500 0.079800 -0.156400 +vn 0.984600 0.082900 -0.153800 +vn 0.985200 0.075300 -0.153700 +vn 0.985200 0.071700 -0.156000 +vn 0.984800 0.070500 -0.158700 +vn 0.984900 0.074100 -0.156400 +vn 0.996700 0.061300 -0.054100 +vn 0.997000 0.055100 -0.055100 +vn 0.996600 0.054600 -0.061800 +vn 0.996300 0.060700 -0.060700 +vn 0.997200 0.062300 -0.040200 +vn 0.997600 0.055900 -0.041100 +vn 0.997300 0.055500 -0.048100 +vn 0.997000 0.061800 -0.047200 +vn 0.998000 0.048600 -0.041100 +vn 0.998200 0.041800 -0.041800 +vn 0.997900 0.041500 -0.049000 +vn 0.997700 0.048200 -0.048200 +vn 0.992900 0.108600 -0.049200 +vn 0.993300 0.103900 -0.050400 +vn 0.993000 0.103300 -0.056800 +vn 0.992600 0.107900 -0.055400 +vn 0.993300 0.109800 -0.036400 +vn 0.993800 0.105000 -0.037400 +vn 0.993600 0.104500 -0.044000 +vn 0.993100 0.109200 -0.042900 +vn 0.994400 0.099000 -0.037400 +vn 0.994800 0.093800 -0.038400 +vn 0.994600 0.093400 -0.045100 +vn 0.994200 0.098500 -0.044000 +vn 0.990300 0.101400 -0.095200 +vn 0.990500 0.097300 -0.097300 +vn 0.990100 0.096200 -0.102400 +vn 0.989900 0.100300 -0.100300 +vn 0.991000 0.103500 -0.084600 +vn 0.991300 0.099200 -0.086500 +vn 0.990900 0.098300 -0.092000 +vn 0.990700 0.102500 -0.090000 +vn 0.991900 0.093000 -0.086500 +vn 0.992200 0.088300 -0.088300 +vn 0.991700 0.087400 -0.093800 +vn 0.991500 0.092000 -0.092000 +vn 0.985100 -0.119100 -0.124300 +vn 0.984800 -0.122800 -0.122800 +vn 0.984900 -0.119800 -0.125000 +vn 0.985100 -0.116100 -0.126500 +vn 0.985700 -0.122000 -0.116600 +vn 0.985400 -0.125800 -0.115100 +vn 0.985400 -0.122900 -0.117700 +vn 0.985700 -0.119100 -0.119100 +vn 0.985000 -0.129400 -0.113700 +vn 0.984800 -0.132900 -0.112200 +vn 0.984900 -0.130000 -0.114600 +vn 0.985100 -0.126500 -0.116100 +vn 0.987500 -0.129700 -0.089500 +vn 0.987100 -0.133700 -0.088400 +vn 0.987100 -0.131300 -0.092000 +vn 0.987500 -0.127400 -0.093300 +vn 0.988100 -0.131900 -0.079400 +vn 0.987600 -0.135900 -0.078300 +vn 0.987600 -0.133700 -0.082300 +vn 0.988000 -0.129800 -0.083500 +vn 0.987200 -0.139700 -0.077200 +vn 0.986700 -0.143300 -0.076100 +vn 0.986800 -0.141100 -0.080000 +vn 0.987200 -0.137500 -0.081200 +vn 0.983100 -0.106500 -0.148800 +vn 0.983000 -0.110000 -0.147100 +vn 0.983300 -0.106600 -0.147800 +vn 0.983400 -0.103200 -0.149500 +vn 0.983500 -0.109800 -0.143700 +vn 0.983400 -0.113300 -0.142000 +vn 0.983600 -0.110000 -0.143100 +vn 0.983700 -0.106600 -0.144800 +vn 0.983200 -0.116700 -0.140400 +vn 0.983000 -0.120000 -0.138700 +vn 0.983300 -0.116600 -0.139600 +vn 0.983400 -0.113400 -0.141300 +vn 0.993600 -0.044000 -0.104500 +vn 0.993300 -0.050400 -0.103900 +vn 0.992900 -0.049200 -0.108600 +vn 0.993100 -0.042900 -0.109200 +vn 0.994600 -0.045100 -0.093400 +vn 0.994300 -0.051700 -0.092800 +vn 0.993900 -0.050500 -0.097900 +vn 0.994200 -0.044000 -0.098500 +vn 0.994000 -0.058200 -0.092200 +vn 0.993700 -0.064500 -0.091500 +vn 0.993300 -0.063100 -0.096400 +vn 0.993600 -0.056800 -0.097200 +vn 0.993100 0.056100 -0.102600 +vn 0.993300 0.050400 -0.103900 +vn 0.992800 0.049800 -0.109200 +vn 0.992600 0.055400 -0.107900 +vn 0.994100 0.057500 -0.091500 +vn 0.994300 0.051700 -0.092800 +vn 0.993800 0.051100 -0.098500 +vn 0.993600 0.056800 -0.097200 +vn 0.994700 0.044600 -0.092800 +vn 0.994800 0.038400 -0.093800 +vn 0.994300 0.037900 -0.099500 +vn 0.994200 0.044000 -0.098500 +vn 0.985300 0.044300 -0.165100 +vn 0.985200 0.039900 -0.166500 +vn 0.984900 0.039200 -0.168800 +vn 0.984900 0.043500 -0.167500 +vn 0.986100 0.045800 -0.159800 +vn 0.986100 0.041200 -0.161200 +vn 0.985600 0.040600 -0.163900 +vn 0.985700 0.045000 -0.162500 +vn 0.986300 0.035300 -0.161200 +vn 0.986300 0.030500 -0.162300 +vn 0.985800 0.030000 -0.165000 +vn 0.985900 0.034700 -0.163900 +vn 0.993600 -0.044000 0.104500 +vn 0.993400 -0.049800 0.103300 +vn 0.993900 -0.050500 0.097900 +vn 0.994100 -0.044500 0.099000 +vn 0.992500 -0.042800 0.114900 +vn 0.992300 -0.048600 0.113700 +vn 0.992900 -0.049200 0.108600 +vn 0.993000 -0.043400 0.109800 +vn 0.992000 -0.055400 0.113700 +vn 0.991800 -0.060700 0.112200 +vn 0.992300 -0.061500 0.107100 +vn 0.992500 -0.056100 0.108600 +vn 0.993100 0.056100 0.102600 +vn 0.993400 0.049800 0.103300 +vn 0.993800 0.051100 0.098500 +vn 0.993500 0.057500 0.097800 +vn 0.992100 0.054700 0.113000 +vn 0.992300 0.048600 0.113700 +vn 0.992800 0.049800 0.109200 +vn 0.992500 0.056100 0.108600 +vn 0.992500 0.042300 0.114300 +vn 0.992700 0.036000 0.114900 +vn 0.993200 0.036900 0.110300 +vn 0.993000 0.043400 0.109800 +vn 0.998000 0.063800 0.000000 +vn 0.998400 0.057000 0.000000 +vn 0.998400 0.057000 -0.003800 +vn 0.998000 0.063800 -0.003700 +vn 0.997900 0.063600 0.011200 +vn 0.998300 0.056800 0.011300 +vn 0.998400 0.057000 0.003800 +vn 0.998000 0.063800 0.003800 +vn 0.998700 0.049800 0.011500 +vn 0.999000 0.042700 0.011600 +vn 0.999100 0.042800 0.003900 +vn 0.998700 0.050000 0.003900 +vn 0.994300 0.003400 -0.106100 +vn 0.994400 0.000000 -0.106100 +vn 0.993800 0.000000 -0.111400 +vn 0.993800 0.003400 -0.111400 +vn 0.995500 0.003500 -0.094900 +vn 0.995500 0.000000 -0.095000 +vn 0.994900 0.000000 -0.100700 +vn 0.994900 0.003400 -0.100600 +vn 0.995500 -0.003500 -0.095000 +vn 0.995400 -0.010600 -0.094900 +vn 0.994900 -0.010300 -0.100500 +vn 0.994900 -0.003400 -0.100600 +vn 0.987500 -0.129700 0.089500 +vn 0.987300 -0.132500 0.087200 +vn 0.987600 -0.133700 0.082300 +vn 0.987800 -0.130900 0.084500 +vn 0.986900 -0.127300 0.099200 +vn 0.986800 -0.130000 0.096600 +vn 0.987100 -0.131300 0.092000 +vn 0.987200 -0.128500 0.094400 +vn 0.986100 -0.135000 0.096600 +vn 0.986100 -0.137300 0.094000 +vn 0.986300 -0.138600 0.089500 +vn 0.986400 -0.136200 0.091900 +vn 0.990300 -0.139300 -0.000000 +vn 0.989700 -0.143300 -0.000000 +vn 0.989700 -0.143200 -0.003000 +vn 0.990300 -0.139200 -0.003100 +vn 0.990200 -0.139200 0.009300 +vn 0.989700 -0.143100 0.009100 +vn 0.989700 -0.143200 0.003000 +vn 0.990200 -0.139300 0.003100 +vn 0.989100 -0.147000 0.009100 +vn 0.988600 -0.150500 0.008800 +vn 0.988600 -0.150700 0.002900 +vn 0.989100 -0.147100 0.003000 +vn 0.998400 0.003800 -0.057000 +vn 0.998400 0.000000 -0.057000 +vn 0.998000 0.000000 -0.063800 +vn 0.998000 0.003700 -0.063800 +vn 0.999100 0.003900 -0.042800 +vn 0.999100 -0.000000 -0.042800 +vn 0.998700 0.000000 -0.050000 +vn 0.998700 0.003800 -0.050000 +vn 0.999100 -0.003900 -0.042800 +vn 0.999000 -0.011700 -0.042800 +vn 0.998700 -0.011500 -0.049800 +vn 0.998700 -0.003800 -0.050000 +vn 0.998700 -0.050000 0.000000 +vn 0.998400 -0.057000 -0.000000 +vn 0.998400 -0.057000 -0.003800 +vn 0.998700 -0.050000 -0.003800 +vn 0.998700 -0.050000 0.011600 +vn 0.998300 -0.056800 0.011300 +vn 0.998400 -0.057000 0.003800 +vn 0.998700 -0.050000 0.003900 +vn 0.997900 -0.063800 0.011300 +vn 0.997500 -0.070200 0.011000 +vn 0.997500 -0.070400 0.003700 +vn 0.998000 -0.063800 0.003800 +vn 0.985300 -0.034700 -0.167000 +vn 0.985200 -0.039900 -0.166500 +vn 0.985000 -0.038600 -0.168200 +vn 0.985100 -0.033500 -0.168900 +vn 0.986200 -0.035900 -0.161800 +vn 0.986100 -0.041200 -0.161200 +vn 0.985800 -0.039900 -0.163300 +vn 0.985900 -0.034700 -0.163900 +vn 0.985900 -0.046500 -0.160500 +vn 0.985800 -0.051700 -0.159700 +vn 0.985600 -0.050100 -0.161700 +vn 0.985700 -0.045000 -0.162500 +vn 0.990900 -0.092000 -0.098300 +vn 0.990500 -0.097300 -0.097300 +vn 0.990300 -0.095200 -0.101400 +vn 0.990700 -0.090000 -0.102500 +vn 0.991700 -0.093800 -0.087400 +vn 0.991300 -0.099200 -0.086500 +vn 0.991100 -0.097300 -0.091000 +vn 0.991500 -0.092000 -0.092000 +vn 0.990900 -0.104400 -0.085500 +vn 0.990400 -0.109400 -0.084500 +vn 0.990200 -0.107500 -0.089000 +vn 0.990700 -0.102500 -0.090000 +vn 0.993800 -0.098500 -0.051100 +vn 0.993300 -0.103900 -0.050400 +vn 0.993100 -0.102600 -0.056100 +vn 0.993600 -0.097200 -0.056800 +vn 0.994300 -0.099500 -0.037900 +vn 0.993800 -0.105000 -0.037400 +vn 0.993600 -0.104000 -0.043400 +vn 0.994200 -0.098500 -0.044000 +vn 0.993200 -0.110300 -0.036900 +vn 0.992700 -0.115400 -0.036400 +vn 0.992500 -0.114300 -0.042300 +vn 0.993100 -0.109200 -0.042900 +vn 0.989500 -0.137000 -0.045900 +vn 0.989000 -0.141000 -0.045200 +vn 0.988900 -0.139600 -0.050300 +vn 0.989400 -0.135700 -0.051000 +vn 0.989800 -0.138100 -0.033900 +vn 0.989300 -0.142100 -0.033400 +vn 0.989200 -0.141100 -0.038800 +vn 0.989800 -0.137100 -0.039400 +vn 0.988700 -0.145900 -0.032900 +vn 0.988200 -0.149500 -0.032400 +vn 0.988200 -0.148500 -0.037600 +vn 0.988700 -0.144900 -0.038200 +vn 0.997300 -0.048100 -0.055500 +vn 0.997000 -0.055100 -0.055100 +vn 0.996700 -0.054000 -0.061300 +vn 0.997000 -0.047200 -0.061800 +vn 0.997900 -0.049000 -0.041500 +vn 0.997600 -0.055900 -0.041100 +vn 0.997300 -0.055100 -0.047700 +vn 0.997700 -0.048200 -0.048200 +vn 0.997200 -0.062700 -0.040700 +vn 0.996800 -0.069300 -0.040200 +vn 0.996600 -0.068400 -0.046700 +vn 0.997000 -0.061800 -0.047200 +vn 0.984300 -0.074000 -0.160100 +vn 0.984200 -0.078500 -0.158900 +vn 0.984200 -0.076000 -0.160100 +vn 0.984300 -0.071700 -0.161300 +vn 0.985000 -0.076400 -0.154800 +vn 0.984800 -0.081000 -0.153600 +vn 0.984800 -0.078600 -0.155200 +vn 0.984900 -0.074100 -0.156400 +vn 0.984600 -0.085500 -0.152400 +vn 0.984400 -0.089900 -0.151100 +vn 0.984500 -0.087200 -0.152500 +vn 0.984600 -0.082900 -0.153800 +vn 0.987400 -0.083400 -0.134800 +vn 0.987100 -0.088400 -0.133700 +vn 0.986900 -0.086000 -0.136300 +vn 0.987200 -0.081200 -0.137500 +vn 0.988200 -0.085600 -0.126700 +vn 0.987900 -0.090700 -0.125600 +vn 0.987700 -0.088400 -0.128600 +vn 0.988000 -0.083500 -0.129800 +vn 0.987600 -0.095600 -0.124400 +vn 0.987300 -0.100400 -0.123200 +vn 0.987200 -0.097900 -0.126100 +vn 0.987500 -0.093300 -0.127400 +vn 0.987100 -0.092000 -0.131300 +vn 0.986800 -0.096600 -0.130000 +vn 0.986100 -0.096600 -0.135000 +vn 0.986400 -0.091900 -0.136200 +vn 0.984300 -0.081600 -0.156400 +vn 0.984200 -0.085800 -0.155000 +vn 0.983600 -0.085700 -0.158700 +vn 0.983700 -0.081500 -0.160000 +vn 0.996700 -0.061300 -0.054000 +vn 0.996300 -0.067800 -0.053500 +vn 0.995900 -0.067800 -0.060700 +vn 0.996200 -0.061300 -0.061300 +vn 0.988600 -0.144200 -0.043900 +vn 0.988100 -0.147800 -0.043300 +vn 0.987800 -0.147800 -0.049500 +vn 0.988300 -0.144200 -0.050300 +vn 0.992900 -0.108600 -0.049200 +vn 0.992300 -0.113700 -0.048500 +vn 0.992000 -0.113700 -0.055400 +vn 0.992500 -0.108600 -0.056100 +vn 0.990300 -0.101400 -0.095200 +vn 0.989900 -0.106400 -0.094200 +vn 0.989300 -0.106300 -0.100300 +vn 0.989700 -0.101400 -0.101400 +vn 0.985300 -0.044300 -0.165100 +vn 0.985200 -0.049300 -0.164200 +vn 0.984700 -0.049200 -0.167400 +vn 0.984800 -0.044300 -0.168200 +vn 0.998000 -0.063800 -0.003800 +vn 0.998300 -0.011300 -0.056800 +vn 0.997900 -0.011300 -0.063800 +vn 0.998000 -0.003800 -0.063800 +vn 0.988600 -0.150700 -0.003000 +vn 0.989100 -0.147100 -0.003000 +vn 0.986900 -0.136300 0.086000 +vn 0.986300 -0.141000 0.086000 +vn 0.986500 -0.142200 0.081100 +vn 0.987200 -0.137500 0.081200 +vn 0.994300 -0.010200 -0.106000 +vn 0.993700 -0.010200 -0.111400 +vn 0.998700 0.050000 -0.003900 +vn 0.993600 0.044000 0.104500 +vn 0.993800 0.037400 0.105000 +vn 0.994400 0.037400 0.099000 +vn 0.994200 0.044000 0.098500 +vn 0.993100 -0.056100 0.102600 +vn 0.992700 -0.063000 0.102600 +vn 0.993200 -0.063800 0.097100 +vn 0.993600 -0.056800 0.097200 +vn 0.985300 0.034700 -0.167000 +vn 0.985500 0.029000 -0.167100 +vn 0.985100 0.028500 -0.169500 +vn 0.985000 0.034100 -0.169400 +vn 0.993600 0.044000 -0.104500 +vn 0.993800 0.036900 -0.104500 +vn 0.993300 0.036400 -0.109800 +vn 0.993000 0.043400 -0.109800 +vn 0.993100 -0.056100 -0.102600 +vn 0.992800 -0.062300 -0.101900 +vn 0.992200 -0.062300 -0.107800 +vn 0.992500 -0.056100 -0.108600 +vn 0.983300 -0.111600 -0.143800 +vn 0.983200 -0.114800 -0.142000 +vn 0.982800 -0.112700 -0.146000 +vn 0.982700 -0.111600 -0.147700 +vn 0.986900 -0.136300 -0.086000 +vn 0.986500 -0.139900 -0.084800 +vn 0.986000 -0.139800 -0.090700 +vn 0.986400 -0.136200 -0.091900 +vn 0.984900 -0.125000 -0.119800 +vn 0.984600 -0.128400 -0.118300 +vn 0.984000 -0.128300 -0.123300 +vn 0.984300 -0.124900 -0.124900 +vn 0.990900 0.092000 -0.098300 +vn 0.991500 0.085600 -0.098300 +vn 0.991000 0.084600 -0.103500 +vn 0.990500 0.091000 -0.103400 +vn 0.993800 0.098500 -0.051100 +vn 0.994400 0.092200 -0.051100 +vn 0.994100 0.091500 -0.057500 +vn 0.993500 0.097800 -0.057500 +vn 0.997300 0.048100 -0.055500 +vn 0.997600 0.040700 -0.055500 +vn 0.997200 0.040200 -0.062300 +vn 0.996900 0.047700 -0.062300 +vn 0.984300 0.074000 -0.160100 +vn 0.984700 0.068300 -0.160200 +vn 0.984400 0.067200 -0.162500 +vn 0.984000 0.072800 -0.162500 +vn 0.987400 0.083400 -0.134800 +vn 0.987800 0.077300 -0.134900 +vn 0.987400 0.076200 -0.138700 +vn 0.986900 0.082300 -0.138600 +vn 0.989100 0.039400 -0.141600 +vn 0.989400 0.033000 -0.141600 +vn 0.988800 0.032500 -0.145400 +vn 0.988600 0.038800 -0.145400 +vn 0.994300 -0.010300 0.106100 +vn 0.994900 -0.010500 0.100600 +vn 0.994900 -0.003400 0.100600 +vn 0.989700 -0.003000 0.143200 +vn 0.989600 -0.009200 0.143200 +vn 0.990200 -0.009300 0.139200 +vn 0.990300 -0.003100 0.139200 +vn 0.988900 -0.050300 0.139600 +vn 0.988600 -0.056700 0.139600 +vn 0.989100 -0.057500 0.135600 +vn 0.989400 -0.051000 0.135700 +vn 0.990900 0.092000 0.098300 +vn 0.991300 0.086500 0.099200 +vn 0.991900 0.086500 0.093000 +vn 0.991500 0.092000 0.092000 +vn 0.987400 0.083400 0.134800 +vn 0.987600 0.078300 0.135900 +vn 0.988300 0.078300 0.130900 +vn 0.988000 0.083500 0.129800 +vn 0.989100 0.039400 0.141600 +vn 0.989300 0.033400 0.142100 +vn 0.989900 0.033500 0.137600 +vn 0.989800 0.039400 0.137100 +vn 0.995500 0.094900 -0.003500 +vn 0.994900 0.100700 -0.003500 +vn 0.993800 0.098500 0.051100 +vn 0.994300 0.092800 0.051700 +vn 0.994700 0.092800 0.044600 +vn 0.994200 0.098500 0.044000 +vn 0.997300 0.048100 0.055500 +vn 0.997600 0.041100 0.055900 +vn 0.998000 0.041100 0.048600 +vn 0.997700 0.048200 0.048200 +vn 0.990300 -0.101400 0.095200 +vn 0.989600 -0.107400 0.095200 +vn 0.990000 -0.108400 0.089900 +vn 0.990700 -0.102500 0.090000 +vn 0.987100 -0.092000 0.131300 +vn 0.986500 -0.097900 0.131200 +vn 0.986900 -0.099200 0.127300 +vn 0.987500 -0.093300 0.127400 +vn 0.984900 -0.125000 0.119800 +vn 0.984300 -0.129900 0.119800 +vn 0.984500 -0.131400 0.116100 +vn 0.985100 -0.126500 0.116100 +vn 0.993200 -0.116500 -0.003400 +vn 0.992900 -0.108600 0.049200 +vn 0.992200 -0.114300 0.049200 +vn 0.992500 -0.114900 0.042800 +vn 0.993100 -0.109200 0.042900 +vn 0.988600 -0.144200 0.043900 +vn 0.987900 -0.148500 0.043900 +vn 0.988100 -0.149000 0.038200 +vn 0.988700 -0.144900 0.038200 +vn 0.998300 -0.011400 0.057000 +vn 0.998700 -0.011600 0.050000 +vn 0.998700 -0.003800 0.050000 +vn 0.996700 -0.061300 0.054100 +vn 0.996200 -0.068400 0.054000 +vn 0.996500 -0.068900 0.047200 +vn 0.997000 -0.061800 0.047200 +vn 0.985700 -0.008000 -0.168500 +vn 0.985200 -0.008000 -0.171000 +vn 0.985300 -0.002700 -0.171100 +vn 0.989700 -0.003000 -0.143200 +vn 0.989700 -0.009100 -0.143100 +vn 0.989100 -0.009100 -0.147000 +vn 0.989100 -0.003000 -0.147100 +vn 0.988900 -0.050300 -0.139600 +vn 0.988700 -0.055900 -0.138800 +vn 0.988100 -0.055900 -0.143400 +vn 0.988300 -0.050200 -0.144200 +vn 0.989500 -0.027100 -0.142100 +vn 0.989400 -0.033000 -0.141600 +vn 0.988700 -0.032900 -0.145900 +vn 0.988900 -0.027000 -0.146300 +vn 0.991700 -0.028700 -0.125100 +vn 0.991600 -0.035000 -0.124600 +vn 0.991000 -0.034900 -0.129600 +vn 0.991100 -0.028700 -0.130000 +vn 0.991000 -0.053200 -0.122600 +vn 0.990800 -0.059100 -0.121800 +vn 0.990100 -0.059100 -0.127100 +vn 0.990400 -0.053200 -0.127800 +vn 0.989600 0.015300 -0.143100 +vn 0.989700 0.009100 -0.143100 +vn 0.989100 0.008900 -0.146900 +vn 0.989000 0.015100 -0.146900 +vn 0.991900 0.016300 -0.126000 +vn 0.992000 0.009600 -0.126000 +vn 0.991400 0.009500 -0.130600 +vn 0.991300 0.016000 -0.130500 +vn 0.992000 -0.003200 -0.126100 +vn 0.992000 -0.009600 -0.126000 +vn 0.991400 -0.009600 -0.130700 +vn 0.985600 0.013500 -0.168500 +vn 0.985700 0.008000 -0.168500 +vn 0.985300 0.007800 -0.170900 +vn 0.985200 0.013200 -0.170900 +vn 0.987500 0.014400 -0.157200 +vn 0.987500 0.008500 -0.157200 +vn 0.987000 0.008400 -0.160300 +vn 0.987000 0.014200 -0.160300 +vn 0.987500 -0.002800 -0.157400 +vn 0.987500 -0.008500 -0.157200 +vn 0.987000 -0.008500 -0.160500 +vn 0.997900 -0.033500 0.055900 +vn 0.997600 -0.041100 0.055900 +vn 0.997900 -0.041500 0.049000 +vn 0.998200 -0.033900 0.049000 +vn 0.996100 -0.032000 0.082000 +vn 0.995900 -0.039300 0.081900 +vn 0.996300 -0.039800 0.075700 +vn 0.996600 -0.032400 0.075700 +vn 0.995100 -0.058900 0.079700 +vn 0.994600 -0.065900 0.079700 +vn 0.995100 -0.066600 0.073500 +vn 0.995500 -0.059500 0.073600 +vn 0.998200 0.019000 0.056800 +vn 0.998300 0.011400 0.057000 +vn 0.998700 0.011500 0.049800 +vn 0.998600 0.019000 0.049600 +vn 0.996400 0.018100 0.082900 +vn 0.996500 0.010900 0.083000 +vn 0.997000 0.010900 0.076700 +vn 0.996900 0.018100 0.076400 +vn 0.996500 -0.003600 0.083000 +vn 0.996500 -0.010900 0.083000 +vn 0.997000 -0.011000 0.076800 +vn 0.997000 -0.003600 0.076800 +vn 0.999800 0.020200 -0.004100 +vn 0.999400 0.019800 0.027700 +vn 0.999500 0.012000 0.027900 +vn 0.999700 0.012000 0.020000 +vn 0.999600 0.019800 0.019800 +vn 0.999500 -0.012000 0.027900 +vn 0.999700 -0.012100 0.020100 +vn 0.999800 -0.004000 0.020100 +vn 0.990700 -0.127900 0.046600 +vn 0.990000 -0.132800 0.046500 +vn 0.990200 -0.133400 0.040500 +vn 0.990900 -0.128500 0.040600 +vn 0.989800 -0.124500 0.069700 +vn 0.989100 -0.129700 0.069600 +vn 0.989400 -0.130600 0.064000 +vn 0.990000 -0.125500 0.064100 +vn 0.987900 -0.140800 0.065800 +vn 0.987200 -0.145300 0.065800 +vn 0.987400 -0.146200 0.060500 +vn 0.988100 -0.141700 0.060500 +vn 0.994900 -0.086400 0.051700 +vn 0.994300 -0.092800 0.051700 +vn 0.994600 -0.093400 0.045100 +vn 0.995200 -0.087000 0.045100 +vn 0.993500 -0.083500 0.076800 +vn 0.993000 -0.090000 0.076700 +vn 0.993400 -0.090800 0.070700 +vn 0.993900 -0.084300 0.070700 +vn 0.991700 -0.105400 0.073300 +vn 0.991100 -0.111300 0.073300 +vn 0.991400 -0.112100 0.067500 +vn 0.992000 -0.106300 0.067500 +vn 0.995500 -0.095000 -0.003500 +vn 0.996000 -0.089100 -0.003600 +vn 0.995800 -0.088400 0.024600 +vn 0.995200 -0.094600 0.024600 +vn 0.995300 -0.094800 0.017600 +vn 0.995900 -0.088700 0.017700 +vn 0.993600 -0.110700 0.023400 +vn 0.993000 -0.116100 0.023300 +vn 0.993100 -0.116300 0.016700 +vn 0.993700 -0.111000 0.016700 +vn 0.986000 -0.109700 0.125900 +vn 0.985400 -0.115100 0.125800 +vn 0.985700 -0.116600 0.122000 +vn 0.986300 -0.111100 0.122000 +vn 0.984800 -0.103800 0.139500 +vn 0.984200 -0.109200 0.139400 +vn 0.984500 -0.110700 0.136300 +vn 0.985000 -0.105300 0.136300 +vn 0.984000 -0.118500 0.133100 +vn 0.983400 -0.123400 0.133000 +vn 0.983600 -0.125100 0.129900 +vn 0.984200 -0.120100 0.130000 +vn 0.988100 -0.072100 0.136000 +vn 0.987600 -0.078300 0.135900 +vn 0.988100 -0.079400 0.131900 +vn 0.988600 -0.073100 0.132000 +vn 0.986300 -0.067900 0.150000 +vn 0.985900 -0.073900 0.150000 +vn 0.986300 -0.075000 0.146700 +vn 0.986800 -0.069000 0.146800 +vn 0.985600 -0.086900 0.145200 +vn 0.985100 -0.092600 0.145100 +vn 0.985400 -0.093900 0.141900 +vn 0.985900 -0.088200 0.142000 +vn 0.991800 -0.080000 0.099300 +vn 0.991300 -0.086500 0.099200 +vn 0.991700 -0.087400 0.093800 +vn 0.992300 -0.080900 0.093900 +vn 0.990000 -0.076100 0.119000 +vn 0.989500 -0.082500 0.119000 +vn 0.989900 -0.083500 0.114300 +vn 0.990400 -0.077100 0.114400 +vn 0.988700 -0.096900 0.114600 +vn 0.988100 -0.102900 0.114500 +vn 0.988500 -0.104000 0.109900 +vn 0.989100 -0.098100 0.110000 +vn 0.995800 0.074700 0.053500 +vn 0.996200 0.068400 0.054000 +vn 0.996600 0.068400 0.046700 +vn 0.996100 0.074800 0.046200 +vn 0.994300 0.072200 0.079000 +vn 0.994600 0.065900 0.079700 +vn 0.995200 0.065900 0.072900 +vn 0.994800 0.072200 0.072200 +vn 0.995600 0.046200 0.081500 +vn 0.995900 0.039300 0.081900 +vn 0.996400 0.039300 0.075300 +vn 0.996100 0.046200 0.074800 +vn 0.991700 0.119200 0.048500 +vn 0.992200 0.114300 0.049200 +vn 0.992500 0.114300 0.042300 +vn 0.992000 0.119300 0.041700 +vn 0.990600 0.116200 0.072400 +vn 0.991100 0.111300 0.073300 +vn 0.991500 0.111400 0.066700 +vn 0.991000 0.116200 0.065800 +vn 0.992500 0.095600 0.075900 +vn 0.993000 0.090000 0.076700 +vn 0.993500 0.090000 0.069900 +vn 0.993000 0.095600 0.069100 +vn 0.993200 0.116500 -0.003300 +vn 0.992600 0.121500 -0.003300 +vn 0.992400 0.121000 0.023000 +vn 0.993000 0.116100 0.023300 +vn 0.993100 0.116100 0.016500 +vn 0.992500 0.121000 0.016300 +vn 0.994700 0.100200 0.024300 +vn 0.995200 0.094600 0.024600 +vn 0.995400 0.094600 0.017400 +vn 0.994800 0.100300 0.017200 +vn 0.988400 0.062200 0.138800 +vn 0.988600 0.056700 0.139600 +vn 0.989200 0.056700 0.134800 +vn 0.989000 0.062300 0.134000 +vn 0.986500 0.058700 0.152900 +vn 0.986700 0.053400 0.153700 +vn 0.987300 0.053400 0.149700 +vn 0.987100 0.058700 0.148800 +vn 0.987100 0.037000 0.155800 +vn 0.987200 0.031500 0.156300 +vn 0.987800 0.031500 0.152500 +vn 0.987700 0.037100 0.151900 +vn 0.986200 0.102400 0.129900 +vn 0.986500 0.097900 0.131200 +vn 0.987200 0.097900 0.126100 +vn 0.986900 0.102500 0.124800 +vn 0.984800 0.097000 0.143800 +vn 0.985100 0.092600 0.145100 +vn 0.985700 0.092700 0.140700 +vn 0.985500 0.097000 0.139300 +vn 0.985700 0.078800 0.148900 +vn 0.985900 0.073900 0.150000 +vn 0.986600 0.074000 0.145700 +vn 0.986400 0.078800 0.144500 +vn 0.989200 0.112200 0.094100 +vn 0.989600 0.107400 0.095200 +vn 0.990200 0.107500 0.089000 +vn 0.989800 0.112300 0.087900 +vn 0.987700 0.107600 0.113300 +vn 0.988100 0.102900 0.114500 +vn 0.988700 0.102900 0.108800 +vn 0.988400 0.107600 0.107600 +vn 0.989100 0.087800 0.117900 +vn 0.989500 0.082500 0.119000 +vn 0.990100 0.082600 0.113300 +vn 0.989800 0.087900 0.112300 +vn 0.989500 -0.027100 0.142100 +vn 0.989300 -0.033400 0.142100 +vn 0.989800 -0.033900 0.138100 +vn 0.990000 -0.027500 0.138100 +vn 0.987400 -0.025400 0.156300 +vn 0.987200 -0.031400 0.156300 +vn 0.987700 -0.031900 0.153000 +vn 0.987900 -0.025800 0.153000 +vn 0.987000 -0.047300 0.153800 +vn 0.986700 -0.053400 0.153700 +vn 0.987100 -0.054200 0.150500 +vn 0.987400 -0.048000 0.150500 +vn 0.989600 0.015300 0.143100 +vn 0.989600 0.009200 0.143200 +vn 0.990200 0.009200 0.139100 +vn 0.990200 0.015300 0.138900 +vn 0.987500 0.014400 0.157200 +vn 0.987500 0.008600 0.157400 +vn 0.988000 0.008700 0.154000 +vn 0.988000 0.014400 0.153700 +vn 0.987500 -0.002800 0.157400 +vn 0.987500 -0.008600 0.157400 +vn 0.988000 -0.008800 0.154100 +vn 0.988000 -0.002900 0.154100 +vn 0.994200 0.017200 0.106000 +vn 0.994300 0.010300 0.106100 +vn 0.994900 0.010300 0.100500 +vn 0.994800 0.017200 0.100300 +vn 0.991900 0.016300 0.126000 +vn 0.992000 0.009800 0.126100 +vn 0.992600 0.009800 0.121300 +vn 0.992500 0.016300 0.121000 +vn 0.992000 -0.003200 0.126100 +vn 0.992000 -0.009800 0.126100 +vn 0.992600 -0.009900 0.121400 +vn 0.992600 -0.003300 0.121400 +vn 0.988400 0.062200 -0.138800 +vn 0.988700 0.055900 -0.138800 +vn 0.988200 0.055100 -0.142600 +vn 0.987900 0.061400 -0.142600 +vn 0.990400 0.065800 -0.121700 +vn 0.990800 0.059100 -0.121800 +vn 0.990300 0.058300 -0.126300 +vn 0.989900 0.064900 -0.126300 +vn 0.991300 0.041700 -0.124500 +vn 0.991600 0.035000 -0.124600 +vn 0.991000 0.034500 -0.129100 +vn 0.990800 0.041100 -0.129100 +vn 0.986200 0.102400 -0.129900 +vn 0.986800 0.096600 -0.130000 +vn 0.986400 0.095300 -0.133700 +vn 0.985900 0.101100 -0.133600 +vn 0.987700 0.107600 -0.113300 +vn 0.988300 0.101700 -0.113400 +vn 0.987900 0.100500 -0.117800 +vn 0.987300 0.106300 -0.117700 +vn 0.989100 0.087800 -0.117900 +vn 0.989700 0.081500 -0.118000 +vn 0.989200 0.080500 -0.122500 +vn 0.988700 0.086700 -0.122400 +vn 0.983700 0.091300 -0.154900 +vn 0.984200 0.085800 -0.155000 +vn 0.983900 0.084400 -0.157300 +vn 0.983500 0.089800 -0.157300 +vn 0.984800 0.097000 -0.143800 +vn 0.985400 0.091300 -0.143900 +vn 0.985100 0.089900 -0.146900 +vn 0.984500 0.095600 -0.146800 +vn 0.985700 0.078800 -0.148900 +vn 0.986200 0.072800 -0.148900 +vn 0.985800 0.071700 -0.152000 +vn 0.985300 0.077600 -0.151900 +vn 0.995800 0.074700 -0.053500 +vn 0.996300 0.067800 -0.053500 +vn 0.995900 0.067200 -0.060100 +vn 0.995400 0.074200 -0.060100 +vn 0.996700 0.076400 -0.025600 +vn 0.997200 0.069700 -0.025600 +vn 0.997100 0.069300 -0.032700 +vn 0.996600 0.076100 -0.032700 +vn 0.998400 0.049600 -0.026800 +vn 0.998800 0.042200 -0.026800 +vn 0.998500 0.041800 -0.034200 +vn 0.998200 0.049300 -0.034200 +vn 0.991700 0.119200 -0.048500 +vn 0.992300 0.113700 -0.048600 +vn 0.992100 0.113000 -0.054700 +vn 0.991400 0.118600 -0.054700 +vn 0.992400 0.121000 -0.023000 +vn 0.993000 0.115800 -0.023000 +vn 0.992900 0.115400 -0.029500 +vn 0.992200 0.120700 -0.029500 +vn 0.994700 0.100200 -0.024300 +vn 0.995200 0.094300 -0.024300 +vn 0.995100 0.093900 -0.031200 +vn 0.994500 0.099900 -0.031100 +vn 0.989200 0.112200 -0.094100 +vn 0.989900 0.106400 -0.094200 +vn 0.989500 0.105300 -0.099200 +vn 0.988900 0.111100 -0.099100 +vn 0.990600 0.116200 -0.072400 +vn 0.991200 0.110400 -0.072400 +vn 0.990900 0.109500 -0.078100 +vn 0.990300 0.115300 -0.078000 +vn 0.992500 0.095600 -0.075900 +vn 0.993100 0.089200 -0.075900 +vn 0.992700 0.088300 -0.081800 +vn 0.992100 0.094700 -0.081700 +vn 0.986000 -0.109700 -0.125900 +vn 0.985700 -0.113800 -0.124400 +vn 0.985000 -0.113700 -0.129400 +vn 0.985300 -0.109600 -0.130900 +vn 0.987300 -0.115200 -0.109600 +vn 0.986900 -0.119400 -0.108200 +vn 0.986300 -0.119300 -0.113800 +vn 0.986700 -0.115200 -0.115200 +vn 0.985900 -0.131000 -0.104100 +vn 0.985600 -0.134500 -0.102700 +vn 0.985000 -0.134400 -0.108200 +vn 0.985300 -0.130900 -0.109600 +vn 0.988600 -0.120200 -0.090800 +vn 0.988200 -0.124500 -0.089600 +vn 0.987600 -0.124400 -0.095600 +vn 0.988000 -0.120200 -0.096800 +vn 0.989800 -0.124500 -0.069700 +vn 0.989300 -0.128900 -0.068700 +vn 0.988800 -0.128800 -0.075100 +vn 0.989300 -0.124500 -0.076100 +vn 0.987900 -0.140800 -0.065800 +vn 0.987400 -0.144400 -0.064900 +vn 0.987000 -0.144300 -0.071000 +vn 0.987400 -0.140700 -0.072000 +vn 0.983800 -0.097700 -0.150500 +vn 0.983600 -0.101400 -0.148900 +vn 0.983100 -0.101300 -0.152700 +vn 0.983200 -0.097600 -0.154300 +vn 0.984800 -0.103800 -0.139500 +vn 0.984600 -0.107700 -0.138000 +vn 0.983900 -0.107600 -0.142400 +vn 0.984100 -0.103700 -0.143900 +vn 0.984000 -0.118500 -0.133100 +vn 0.983800 -0.121800 -0.131400 +vn 0.983200 -0.121700 -0.135900 +vn 0.983400 -0.118400 -0.137600 +vn 0.994000 -0.030300 -0.105000 +vn 0.993800 -0.036900 -0.104500 +vn 0.993200 -0.036900 -0.110300 +vn 0.993400 -0.030300 -0.110700 +vn 0.996100 -0.032000 -0.082000 +vn 0.995900 -0.038900 -0.081500 +vn 0.995400 -0.038800 -0.088000 +vn 0.995600 -0.031900 -0.088400 +vn 0.995100 -0.058900 -0.079700 +vn 0.994700 -0.065200 -0.079100 +vn 0.994200 -0.065200 -0.085700 +vn 0.994500 -0.058800 -0.086400 +vn 0.992400 0.069100 -0.101800 +vn 0.992800 0.062300 -0.101900 +vn 0.992300 0.061500 -0.107100 +vn 0.991900 0.068300 -0.107100 +vn 0.994300 0.072200 -0.079000 +vn 0.994700 0.065200 -0.079100 +vn 0.994300 0.064500 -0.085000 +vn 0.993800 0.071400 -0.085000 +vn 0.995600 0.046200 -0.081500 +vn 0.995900 0.038900 -0.081500 +vn 0.995400 0.038400 -0.087500 +vn 0.995100 0.045600 -0.087500 +vn 0.984900 0.055000 -0.164200 +vn 0.985200 0.049300 -0.164200 +vn 0.984800 0.048400 -0.166600 +vn 0.984500 0.054100 -0.166600 +vn 0.986500 0.058700 -0.152900 +vn 0.986800 0.052600 -0.153000 +vn 0.986400 0.051700 -0.156100 +vn 0.986100 0.057800 -0.156000 +vn 0.987100 0.037000 -0.155800 +vn 0.987300 0.031000 -0.155800 +vn 0.986800 0.030500 -0.158900 +vn 0.986600 0.036400 -0.158800 +vn 0.994000 -0.030300 0.105000 +vn 0.993800 -0.037400 0.105000 +vn 0.994300 -0.037900 0.099500 +vn 0.994600 -0.030800 0.099500 +vn 0.991700 -0.028700 0.125000 +vn 0.991500 -0.035400 0.125000 +vn 0.992100 -0.035900 0.120300 +vn 0.992300 -0.029100 0.120300 +vn 0.991000 -0.053200 0.122600 +vn 0.990700 -0.059900 0.122600 +vn 0.991200 -0.060700 0.117800 +vn 0.991600 -0.054000 0.117900 +vn 0.992400 0.069100 0.101800 +vn 0.992700 0.063000 0.102600 +vn 0.993300 0.063100 0.096400 +vn 0.993000 0.069100 0.095600 +vn 0.990400 0.065800 0.121700 +vn 0.990700 0.059900 0.122600 +vn 0.991300 0.059900 0.117100 +vn 0.991000 0.065800 0.116200 +vn 0.991300 0.041700 0.124500 +vn 0.991500 0.035400 0.125000 +vn 0.992200 0.035500 0.119800 +vn 0.992000 0.041700 0.119300 +vn 0.997000 0.076900 -0.003700 +vn 0.996700 0.076400 0.025600 +vn 0.997200 0.070000 0.025900 +vn 0.997400 0.070000 0.018300 +vn 0.996900 0.076400 0.018100 +vn 0.998400 0.049600 0.026800 +vn 0.998700 0.042400 0.027100 +vn 0.998900 0.042400 0.019200 +vn 0.998600 0.049600 0.019000 +vn 0.994200 0.017200 -0.106000 +vn 0.994300 0.010200 -0.106000 +vn 0.993700 0.010100 -0.111300 +vn 0.993600 0.017000 -0.111200 +vn 0.996400 0.018100 -0.082900 +vn 0.996500 0.010800 -0.082900 +vn 0.996000 0.010600 -0.089000 +vn 0.995900 0.017900 -0.088900 +vn 0.996500 -0.003600 -0.083000 +vn 0.996500 -0.010800 -0.082900 +vn 0.996000 -0.010700 -0.089100 +vn 0.996000 -0.003600 -0.089100 +vn 0.988600 -0.120200 0.090800 +vn 0.987900 -0.125600 0.090700 +vn 0.988200 -0.126700 0.085600 +vn 0.988900 -0.121400 0.085700 +vn 0.987300 -0.115200 0.109600 +vn 0.986600 -0.120700 0.109500 +vn 0.987000 -0.122000 0.105000 +vn 0.987600 -0.116500 0.105100 +vn 0.985900 -0.131000 0.104100 +vn 0.985300 -0.135800 0.104000 +vn 0.985500 -0.137200 0.099700 +vn 0.986200 -0.132400 0.099800 +vn 0.990800 -0.135100 -0.003200 +vn 0.991300 -0.130000 0.022100 +vn 0.990600 -0.134700 0.022100 +vn 0.990700 -0.134900 0.015800 +vn 0.991300 -0.130300 0.015800 +vn 0.989000 -0.146400 0.020800 +vn 0.988400 -0.150300 0.020800 +vn 0.988500 -0.150500 0.014900 +vn 0.989100 -0.146700 0.014900 +vn 0.998200 0.019000 -0.056800 +vn 0.998300 0.011300 -0.056800 +vn 0.997900 0.011200 -0.063600 +vn 0.997800 0.018800 -0.063600 +vn 0.999400 0.019800 -0.027700 +vn 0.999500 0.011900 -0.027700 +vn 0.999300 0.011700 -0.035300 +vn 0.999200 0.019600 -0.035300 +vn 0.999500 -0.011900 -0.027700 +vn 0.999300 -0.011800 -0.035400 +vn 0.999400 -0.004000 -0.035500 +vn 0.999400 -0.035500 -0.004000 +vn 0.999000 -0.034800 0.027100 +vn 0.998700 -0.042400 0.027100 +vn 0.998900 -0.042600 0.019400 +vn 0.999200 -0.035100 0.019400 +vn 0.997700 -0.063100 0.025900 +vn 0.997200 -0.070000 0.025900 +vn 0.997400 -0.070200 0.018600 +vn 0.997800 -0.063400 0.018600 +vn 0.985600 -0.023800 -0.167600 +vn 0.985500 -0.029000 -0.167100 +vn 0.985000 -0.029000 -0.169900 +vn 0.985100 -0.023800 -0.170300 +vn 0.987400 -0.025400 -0.156300 +vn 0.987300 -0.031000 -0.155800 +vn 0.986700 -0.030900 -0.159400 +vn 0.986800 -0.025400 -0.159800 +vn 0.987000 -0.047300 -0.153800 +vn 0.986800 -0.052600 -0.153000 +vn 0.986200 -0.052500 -0.156800 +vn 0.986400 -0.047300 -0.157600 +vn 0.991800 -0.080000 -0.099300 +vn 0.991500 -0.085600 -0.098300 +vn 0.990900 -0.085500 -0.104400 +vn 0.991200 -0.079900 -0.105400 +vn 0.993600 -0.083500 -0.076800 +vn 0.993100 -0.089200 -0.075900 +vn 0.992600 -0.089200 -0.082600 +vn 0.993000 -0.083400 -0.083400 +vn 0.991700 -0.105400 -0.073300 +vn 0.991200 -0.110500 -0.072400 +vn 0.990700 -0.110400 -0.079000 +vn 0.991200 -0.105400 -0.079900 +vn 0.994900 -0.086400 -0.051700 +vn 0.994400 -0.092200 -0.051100 +vn 0.994000 -0.092200 -0.058200 +vn 0.994500 -0.086400 -0.058800 +vn 0.995800 -0.088400 -0.024600 +vn 0.995300 -0.094300 -0.024300 +vn 0.995000 -0.094200 -0.031500 +vn 0.995600 -0.088400 -0.031900 +vn 0.993600 -0.110700 -0.023400 +vn 0.993000 -0.115800 -0.023000 +vn 0.992800 -0.115800 -0.029900 +vn 0.993400 -0.110700 -0.030300 +vn 0.990700 -0.127900 -0.046600 +vn 0.990200 -0.132200 -0.045900 +vn 0.989800 -0.132200 -0.052500 +vn 0.990400 -0.127800 -0.053200 +vn 0.991300 -0.130000 -0.022100 +vn 0.990700 -0.134400 -0.021700 +vn 0.990500 -0.134300 -0.028300 +vn 0.991100 -0.130000 -0.028700 +vn 0.989000 -0.146400 -0.020800 +vn 0.988500 -0.150000 -0.020500 +vn 0.988300 -0.150000 -0.026600 +vn 0.988900 -0.146300 -0.027000 +vn 0.997900 -0.033500 -0.055900 +vn 0.997600 -0.040700 -0.055500 +vn 0.997200 -0.040700 -0.062700 +vn 0.997400 -0.033500 -0.063100 +vn 0.999000 -0.034800 -0.027100 +vn 0.998800 -0.042200 -0.026800 +vn 0.998500 -0.042200 -0.034500 +vn 0.998800 -0.034800 -0.034800 +vn 0.997700 -0.063100 -0.025900 +vn 0.997200 -0.069700 -0.025600 +vn 0.997000 -0.069700 -0.033100 +vn 0.997400 -0.063100 -0.033500 +vn 0.984800 -0.063700 -0.161300 +vn 0.984700 -0.068300 -0.160200 +vn 0.984200 -0.068300 -0.163600 +vn 0.984300 -0.063700 -0.164700 +vn 0.986300 -0.067900 -0.150000 +vn 0.986200 -0.072800 -0.148900 +vn 0.985500 -0.072800 -0.153100 +vn 0.985700 -0.067900 -0.154100 +vn 0.985600 -0.086900 -0.145200 +vn 0.985400 -0.091300 -0.143900 +vn 0.984700 -0.091300 -0.148200 +vn 0.984900 -0.086800 -0.149500 +vn 0.988100 -0.072100 -0.136000 +vn 0.987800 -0.077300 -0.134900 +vn 0.987200 -0.077200 -0.139700 +vn 0.987400 -0.072000 -0.140700 +vn 0.990000 -0.076100 -0.119000 +vn 0.989700 -0.081500 -0.118000 +vn 0.989000 -0.081500 -0.123500 +vn 0.989300 -0.076100 -0.124500 +vn 0.988700 -0.096900 -0.114600 +vn 0.988300 -0.101700 -0.113400 +vn 0.987700 -0.101600 -0.119000 +vn 0.988000 -0.096800 -0.120200 +vn 0.989300 -0.086800 -0.116900 +vn 0.989000 -0.091900 -0.115800 +vn 0.988400 -0.091900 -0.121300 +vn 0.988700 -0.086700 -0.122400 +vn 0.990200 -0.089000 -0.107500 +vn 0.989900 -0.094200 -0.106400 +vn 0.989200 -0.094100 -0.112200 +vn 0.989600 -0.088900 -0.113300 +vn 0.989500 -0.099200 -0.105300 +vn 0.989100 -0.104100 -0.104100 +vn 0.988500 -0.104000 -0.109900 +vn 0.988900 -0.099100 -0.111100 +vn 0.990500 -0.064900 -0.120900 +vn 0.990300 -0.070600 -0.120000 +vn 0.989600 -0.070600 -0.125400 +vn 0.989900 -0.064900 -0.126300 +vn 0.991500 -0.066700 -0.111400 +vn 0.991200 -0.072400 -0.110500 +vn 0.990600 -0.072400 -0.116200 +vn 0.990900 -0.066600 -0.117000 +vn 0.990900 -0.078100 -0.109500 +vn 0.990600 -0.083600 -0.108500 +vn 0.989900 -0.083500 -0.114300 +vn 0.990300 -0.078000 -0.115300 +vn 0.988500 -0.061400 -0.137900 +vn 0.988300 -0.066800 -0.137000 +vn 0.987700 -0.066800 -0.141700 +vn 0.987900 -0.061400 -0.142600 +vn 0.989500 -0.063200 -0.129800 +vn 0.989300 -0.068700 -0.128900 +vn 0.988600 -0.068700 -0.133900 +vn 0.988900 -0.063100 -0.134800 +vn 0.989000 -0.074100 -0.127800 +vn 0.988700 -0.079400 -0.126800 +vn 0.988100 -0.079400 -0.131900 +vn 0.988400 -0.074100 -0.132900 +vn 0.986000 -0.077600 -0.147800 +vn 0.985800 -0.082300 -0.146500 +vn 0.985100 -0.082300 -0.150700 +vn 0.985300 -0.077600 -0.151900 +vn 0.986800 -0.080000 -0.141100 +vn 0.986500 -0.084800 -0.139900 +vn 0.985900 -0.084700 -0.144400 +vn 0.986100 -0.079900 -0.145600 +vn 0.986300 -0.089500 -0.138600 +vn 0.986100 -0.094000 -0.137300 +vn 0.985400 -0.093900 -0.141900 +vn 0.985600 -0.089400 -0.143200 +vn 0.986700 -0.057800 -0.152100 +vn 0.986500 -0.062900 -0.151100 +vn 0.985900 -0.062900 -0.155100 +vn 0.986100 -0.057800 -0.156000 +vn 0.987600 -0.059600 -0.145400 +vn 0.987400 -0.064900 -0.144400 +vn 0.986700 -0.064800 -0.148700 +vn 0.986900 -0.059600 -0.149600 +vn 0.987200 -0.070000 -0.143400 +vn 0.987000 -0.075100 -0.142300 +vn 0.986300 -0.075000 -0.146700 +vn 0.986500 -0.070000 -0.147800 +vn 0.985100 -0.054200 -0.163300 +vn 0.985000 -0.059000 -0.162400 +vn 0.984400 -0.058900 -0.165700 +vn 0.984500 -0.054100 -0.166600 +vn 0.985800 -0.056000 -0.158100 +vn 0.985700 -0.060900 -0.157100 +vn 0.985100 -0.060900 -0.160700 +vn 0.985300 -0.055900 -0.161600 +vn 0.985600 -0.065800 -0.156000 +vn 0.985400 -0.070600 -0.154900 +vn 0.984800 -0.070500 -0.158700 +vn 0.985000 -0.065800 -0.159700 +vn 0.998400 -0.049300 -0.026500 +vn 0.998100 -0.056300 -0.026200 +vn 0.997800 -0.056300 -0.033900 +vn 0.998200 -0.049300 -0.034200 +vn 0.998700 -0.049800 -0.011500 +vn 0.998300 -0.056800 -0.011300 +vn 0.998200 -0.056800 -0.019000 +vn 0.998600 -0.049800 -0.019200 +vn 0.997900 -0.063600 -0.011200 +vn 0.997500 -0.070200 -0.011000 +vn 0.997400 -0.070200 -0.018600 +vn 0.997800 -0.063600 -0.018800 +vn 0.999400 -0.019700 -0.027500 +vn 0.999300 -0.027300 -0.027300 +vn 0.999000 -0.027300 -0.035100 +vn 0.999200 -0.019600 -0.035300 +vn 0.999700 -0.020000 -0.012000 +vn 0.999500 -0.027700 -0.011900 +vn 0.999400 -0.027700 -0.019800 +vn 0.999600 -0.020000 -0.020000 +vn 0.999300 -0.035300 -0.011700 +vn 0.999000 -0.042700 -0.011600 +vn 0.998900 -0.042600 -0.019400 +vn 0.999200 -0.035300 -0.019600 +vn 0.998200 -0.018800 -0.056600 +vn 0.998100 -0.026200 -0.056300 +vn 0.997600 -0.026200 -0.063400 +vn 0.997800 -0.018800 -0.063600 +vn 0.998900 -0.019200 -0.042400 +vn 0.998800 -0.026800 -0.042200 +vn 0.998400 -0.026800 -0.049600 +vn 0.998600 -0.019200 -0.049800 +vn 0.998500 -0.034200 -0.041800 +vn 0.998300 -0.041500 -0.041500 +vn 0.997900 -0.041500 -0.049000 +vn 0.998200 -0.034200 -0.049300 +vn 0.990100 -0.138500 -0.021400 +vn 0.989600 -0.142500 -0.021100 +vn 0.989400 -0.142500 -0.027500 +vn 0.990000 -0.138500 -0.027900 +vn 0.990200 -0.139100 -0.009200 +vn 0.989700 -0.143100 -0.009100 +vn 0.989600 -0.143100 -0.015300 +vn 0.990200 -0.139100 -0.015600 +vn 0.989100 -0.146900 -0.008900 +vn 0.988600 -0.150500 -0.008800 +vn 0.988500 -0.150500 -0.014900 +vn 0.989000 -0.146900 -0.015100 +vn 0.992400 -0.120700 -0.022700 +vn 0.991800 -0.125500 -0.022400 +vn 0.991700 -0.125400 -0.029100 +vn 0.992200 -0.120700 -0.029500 +vn 0.992600 -0.121300 -0.009800 +vn 0.992000 -0.126000 -0.009600 +vn 0.991900 -0.126000 -0.016300 +vn 0.992500 -0.121300 -0.016500 +vn 0.991400 -0.130600 -0.009500 +vn 0.990800 -0.134900 -0.009400 +vn 0.990700 -0.134900 -0.015800 +vn 0.991300 -0.130500 -0.016000 +vn 0.991800 -0.118600 -0.047900 +vn 0.991200 -0.123300 -0.047200 +vn 0.990900 -0.123300 -0.053900 +vn 0.991400 -0.118600 -0.054700 +vn 0.992200 -0.119800 -0.035500 +vn 0.991600 -0.124600 -0.035000 +vn 0.991300 -0.124500 -0.041700 +vn 0.991900 -0.119800 -0.042300 +vn 0.991000 -0.129100 -0.034500 +vn 0.990500 -0.133500 -0.034000 +vn 0.990200 -0.133400 -0.040500 +vn 0.990800 -0.129100 -0.041100 +vn 0.994700 -0.099900 -0.024000 +vn 0.994100 -0.105400 -0.023700 +vn 0.994000 -0.105400 -0.030700 +vn 0.994500 -0.099900 -0.031100 +vn 0.994900 -0.100500 -0.010300 +vn 0.994300 -0.106000 -0.010200 +vn 0.994200 -0.106000 -0.017200 +vn 0.994800 -0.100500 -0.017400 +vn 0.993700 -0.111300 -0.010100 +vn 0.993200 -0.116400 -0.009900 +vn 0.993100 -0.116300 -0.016700 +vn 0.993600 -0.111200 -0.017000 +vn 0.996800 -0.076100 -0.025300 +vn 0.996300 -0.082400 -0.025000 +vn 0.996100 -0.082300 -0.032300 +vn 0.996600 -0.076100 -0.032700 +vn 0.997000 -0.076700 -0.010900 +vn 0.996500 -0.082900 -0.010800 +vn 0.996400 -0.082900 -0.018100 +vn 0.996900 -0.076700 -0.018300 +vn 0.996000 -0.089000 -0.010600 +vn 0.995400 -0.094800 -0.010500 +vn 0.995300 -0.094800 -0.017600 +vn 0.995900 -0.088900 -0.017900 +vn 0.995800 -0.074200 -0.052900 +vn 0.995400 -0.080400 -0.052300 +vn 0.995000 -0.080400 -0.059500 +vn 0.995400 -0.074200 -0.060100 +vn 0.996400 -0.075300 -0.039300 +vn 0.995900 -0.081500 -0.038900 +vn 0.995600 -0.081500 -0.046200 +vn 0.996100 -0.075300 -0.046700 +vn 0.995400 -0.087500 -0.038400 +vn 0.994900 -0.093400 -0.037900 +vn 0.994600 -0.093400 -0.045100 +vn 0.995100 -0.087500 -0.045600 +vn 0.992700 -0.094800 -0.075100 +vn 0.992200 -0.100200 -0.074200 +vn 0.991700 -0.100100 -0.080800 +vn 0.992100 -0.094700 -0.081700 +vn 0.993300 -0.096400 -0.063100 +vn 0.992800 -0.101900 -0.062300 +vn 0.992400 -0.101800 -0.069100 +vn 0.992900 -0.096400 -0.069900 +vn 0.992300 -0.107100 -0.061500 +vn 0.991800 -0.112200 -0.060700 +vn 0.991400 -0.112100 -0.067500 +vn 0.991900 -0.107100 -0.068300 +vn 0.994400 -0.071500 -0.078300 +vn 0.994000 -0.077600 -0.077600 +vn 0.993400 -0.077500 -0.084200 +vn 0.993800 -0.071400 -0.085000 +vn 0.995200 -0.072900 -0.065900 +vn 0.994700 -0.079100 -0.065200 +vn 0.994300 -0.079000 -0.072200 +vn 0.994700 -0.072900 -0.072900 +vn 0.994300 -0.085000 -0.064500 +vn 0.993800 -0.090800 -0.063800 +vn 0.993400 -0.090800 -0.070700 +vn 0.993800 -0.085000 -0.071400 +vn 0.992500 -0.068300 -0.101000 +vn 0.992200 -0.074200 -0.100200 +vn 0.991600 -0.074200 -0.106200 +vn 0.991900 -0.068300 -0.107100 +vn 0.993500 -0.069900 -0.090000 +vn 0.993100 -0.075900 -0.089200 +vn 0.992500 -0.075900 -0.095600 +vn 0.992900 -0.069900 -0.096400 +vn 0.992700 -0.081800 -0.088400 +vn 0.992300 -0.087500 -0.087500 +vn 0.991700 -0.087400 -0.093800 +vn 0.992100 -0.081700 -0.094700 +vn 0.987200 -0.036500 -0.155200 +vn 0.987100 -0.041900 -0.154500 +vn 0.986500 -0.041900 -0.158300 +vn 0.986600 -0.036400 -0.158900 +vn 0.988200 -0.037600 -0.148500 +vn 0.988100 -0.043300 -0.147800 +vn 0.987400 -0.043200 -0.151900 +vn 0.987600 -0.037600 -0.152500 +vn 0.987900 -0.048800 -0.147100 +vn 0.987800 -0.054200 -0.146300 +vn 0.987100 -0.054200 -0.150500 +vn 0.987300 -0.048800 -0.151200 +vn 0.987500 -0.014200 -0.157000 +vn 0.987400 -0.019800 -0.156700 +vn 0.986900 -0.019800 -0.160100 +vn 0.987000 -0.014200 -0.160300 +vn 0.988500 -0.014600 -0.150300 +vn 0.988500 -0.020500 -0.150000 +vn 0.987900 -0.020400 -0.153700 +vn 0.988000 -0.014600 -0.154000 +vn 0.988400 -0.026200 -0.149600 +vn 0.988300 -0.032000 -0.149100 +vn 0.987700 -0.031900 -0.153000 +vn 0.987800 -0.026200 -0.153400 +vn 0.985600 -0.013300 -0.168300 +vn 0.985600 -0.018500 -0.168000 +vn 0.985200 -0.018500 -0.170700 +vn 0.985200 -0.013200 -0.170900 +vn 0.986500 -0.013700 -0.163000 +vn 0.986500 -0.019200 -0.162700 +vn 0.986000 -0.019200 -0.165700 +vn 0.986000 -0.013700 -0.166000 +vn 0.986400 -0.024600 -0.162300 +vn 0.986400 -0.030000 -0.161800 +vn 0.985800 -0.030000 -0.165000 +vn 0.985900 -0.024600 -0.165400 +vn 0.998400 -0.049300 0.026500 +vn 0.998000 -0.056600 0.026500 +vn 0.998200 -0.056800 0.019000 +vn 0.998600 -0.049600 0.019000 +vn 0.998000 -0.048600 0.041100 +vn 0.997600 -0.055900 0.041100 +vn 0.997800 -0.056300 0.033900 +vn 0.998200 -0.049000 0.033900 +vn 0.997200 -0.062300 0.040200 +vn 0.996800 -0.069300 0.040200 +vn 0.997000 -0.069700 0.033100 +vn 0.997500 -0.062700 0.033100 +vn 0.999400 -0.019700 0.027500 +vn 0.999200 -0.027500 0.027500 +vn 0.999400 -0.027700 0.019800 +vn 0.999600 -0.019800 0.019800 +vn 0.998900 -0.019200 0.042400 +vn 0.998700 -0.027100 0.042400 +vn 0.999000 -0.027300 0.035100 +vn 0.999200 -0.019400 0.035100 +vn 0.998500 -0.034200 0.041800 +vn 0.998200 -0.041800 0.041800 +vn 0.998500 -0.042200 0.034500 +vn 0.998800 -0.034500 0.034500 +vn 0.999800 -0.020200 -0.004100 +vn 0.999700 -0.020000 0.012000 +vn 0.999500 -0.027900 0.012000 +vn 0.999800 -0.020100 0.004000 +vn 0.999300 -0.035300 0.011700 +vn 0.999000 -0.042800 0.011700 +vn 0.999400 -0.035400 0.003900 +vn 0.999400 0.004000 -0.035500 +vn 0.999800 0.004100 -0.020200 +vn 0.999900 -0.012100 -0.012100 +vn 0.999700 -0.012100 -0.020100 +vn 0.999800 -0.004100 -0.020200 +vn 0.999000 0.035100 -0.027300 +vn 0.999300 0.027300 -0.027300 +vn 0.999000 0.027100 -0.034800 +vn 0.998800 0.034800 -0.034800 +vn 0.999300 0.035400 -0.011800 +vn 0.999500 0.027700 -0.011900 +vn 0.999400 0.027500 -0.019700 +vn 0.999200 0.035300 -0.019600 +vn 0.999700 0.020100 -0.012100 +vn 0.999900 0.012100 -0.012100 +vn 0.999700 0.012000 -0.020000 +vn 0.999600 0.020000 -0.020000 +vn 0.997800 0.033900 -0.056300 +vn 0.998100 0.026200 -0.056300 +vn 0.997700 0.025900 -0.063100 +vn 0.997400 0.033500 -0.063100 +vn 0.998500 0.034500 -0.042200 +vn 0.998800 0.026800 -0.042200 +vn 0.998400 0.026500 -0.049300 +vn 0.998200 0.034200 -0.049300 +vn 0.998900 0.019400 -0.042600 +vn 0.999000 0.011600 -0.042700 +vn 0.998700 0.011500 -0.049800 +vn 0.998600 0.019200 -0.049800 +vn 0.990100 -0.138500 0.021400 +vn 0.989500 -0.142800 0.021400 +vn 0.989600 -0.143100 0.015300 +vn 0.990200 -0.138900 0.015300 +vn 0.989900 -0.137600 0.033500 +vn 0.989300 -0.142100 0.033400 +vn 0.989400 -0.142500 0.027500 +vn 0.990000 -0.138100 0.027500 +vn 0.988800 -0.145400 0.032500 +vn 0.988200 -0.149500 0.032400 +vn 0.988300 -0.150000 0.026600 +vn 0.988900 -0.145900 0.026600 +vn 0.992400 -0.120700 0.022700 +vn 0.991800 -0.125800 0.022700 +vn 0.991900 -0.126000 0.016300 +vn 0.992500 -0.121000 0.016300 +vn 0.992200 -0.119800 0.035500 +vn 0.991500 -0.125000 0.035400 +vn 0.991700 -0.125400 0.029100 +vn 0.992300 -0.120300 0.029100 +vn 0.991000 -0.129100 0.034500 +vn 0.990400 -0.133900 0.034400 +vn 0.990500 -0.134300 0.028300 +vn 0.991200 -0.129600 0.028300 +vn 0.992000 -0.126200 -0.003300 +vn 0.992600 -0.121500 -0.003300 +vn 0.992600 -0.121300 0.009800 +vn 0.992000 -0.126100 0.009800 +vn 0.992000 -0.126200 0.003300 +vn 0.992600 -0.121400 0.003300 +vn 0.991400 -0.130600 0.009500 +vn 0.990800 -0.135100 0.009500 +vn 0.990800 -0.135100 0.003200 +vn 0.986600 -0.123400 0.106900 +vn 0.985900 -0.128600 0.106800 +vn 0.986200 -0.129900 0.102400 +vn 0.986900 -0.124800 0.102500 +vn 0.986000 -0.120600 0.115200 +vn 0.985400 -0.125800 0.115100 +vn 0.985600 -0.127200 0.111100 +vn 0.986300 -0.122000 0.111100 +vn 0.985400 -0.128000 0.112300 +vn 0.984800 -0.132900 0.112200 +vn 0.985000 -0.134400 0.108200 +vn 0.985600 -0.129500 0.108300 +vn 0.988000 -0.106400 0.112200 +vn 0.987400 -0.112100 0.112100 +vn 0.987700 -0.113300 0.107600 +vn 0.988400 -0.107600 0.107600 +vn 0.987200 -0.103800 0.120700 +vn 0.986600 -0.109500 0.120700 +vn 0.987000 -0.110800 0.116500 +vn 0.987600 -0.105100 0.116500 +vn 0.986600 -0.112500 0.118000 +vn 0.986000 -0.118000 0.118000 +vn 0.986300 -0.119300 0.113800 +vn 0.986900 -0.113900 0.113900 +vn 0.989400 -0.111200 0.093100 +vn 0.988800 -0.116800 0.093000 +vn 0.989100 -0.117900 0.087800 +vn 0.989800 -0.112300 0.087900 +vn 0.988700 -0.108800 0.102900 +vn 0.988100 -0.114500 0.102900 +vn 0.988400 -0.115700 0.098000 +vn 0.989100 -0.110000 0.098100 +vn 0.987900 -0.117800 0.100500 +vn 0.987300 -0.123200 0.100400 +vn 0.987600 -0.124400 0.095600 +vn 0.988300 -0.119000 0.095700 +vn 0.996500 0.003600 -0.083100 +vn 0.996000 0.003600 -0.089100 +vn 0.997000 0.003700 -0.076900 +vn 0.997500 -0.011000 -0.070200 +vn 0.997000 -0.011000 -0.076800 +vn 0.997000 -0.003700 -0.076900 +vn 0.996100 0.032300 -0.082300 +vn 0.996300 0.025000 -0.082400 +vn 0.995800 0.024600 -0.088400 +vn 0.995600 0.031900 -0.088400 +vn 0.997000 0.033100 -0.069700 +vn 0.997200 0.025600 -0.069700 +vn 0.996800 0.025300 -0.076100 +vn 0.996600 0.032700 -0.076100 +vn 0.997400 0.018600 -0.070200 +vn 0.997500 0.011000 -0.070200 +vn 0.997000 0.010900 -0.076700 +vn 0.996900 0.018300 -0.076700 +vn 0.994000 0.030700 -0.105400 +vn 0.994100 0.023700 -0.105400 +vn 0.993600 0.023400 -0.110700 +vn 0.993400 0.030300 -0.110700 +vn 0.995000 0.031500 -0.094200 +vn 0.995200 0.024300 -0.094300 +vn 0.994700 0.024000 -0.099900 +vn 0.994500 0.031100 -0.099900 +vn 0.995300 0.017600 -0.094800 +vn 0.995400 0.010500 -0.094800 +vn 0.994900 0.010300 -0.100500 +vn 0.994800 0.017400 -0.100500 +vn 0.997600 0.063400 0.026200 +vn 0.998000 0.056600 0.026500 +vn 0.998200 0.056600 0.018800 +vn 0.997800 0.063400 0.018600 +vn 0.997200 0.062700 0.040700 +vn 0.997600 0.055900 0.041100 +vn 0.997900 0.055900 0.033500 +vn 0.997500 0.062700 0.033100 +vn 0.997900 0.049000 0.041500 +vn 0.998200 0.041800 0.041800 +vn 0.998500 0.041800 0.034200 +vn 0.998200 0.049000 0.033900 +vn 0.995700 0.088700 0.024900 +vn 0.996300 0.082700 0.025300 +vn 0.996400 0.082700 0.017900 +vn 0.995900 0.088700 0.017700 +vn 0.995400 0.088000 0.038800 +vn 0.995900 0.081900 0.039300 +vn 0.996100 0.082000 0.032000 +vn 0.995600 0.088000 0.031600 +vn 0.996300 0.075700 0.039800 +vn 0.996800 0.069300 0.040200 +vn 0.997100 0.069300 0.032700 +vn 0.996600 0.075700 0.032400 +vn 0.996500 0.083000 -0.003600 +vn 0.996000 0.089100 -0.003600 +vn 0.996000 0.089100 0.010700 +vn 0.996500 0.083000 0.010900 +vn 0.996500 0.083000 0.003600 +vn 0.996000 0.089100 0.003500 +vn 0.997000 0.076800 0.011000 +vn 0.997500 0.070400 0.011200 +vn 0.997000 0.076800 0.003600 +vn 0.990900 0.053900 0.123300 +vn 0.991100 0.047900 0.123900 +vn 0.991800 0.047900 0.118600 +vn 0.991600 0.054000 0.117900 +vn 0.989800 0.052500 0.132200 +vn 0.990000 0.046500 0.132800 +vn 0.990700 0.046600 0.127900 +vn 0.990500 0.052500 0.127100 +vn 0.990200 0.040500 0.133400 +vn 0.990400 0.034400 0.133900 +vn 0.991000 0.034500 0.129100 +vn 0.990900 0.040600 0.128500 +vn 0.989800 0.077100 0.120000 +vn 0.990100 0.071500 0.120900 +vn 0.990800 0.071500 0.115300 +vn 0.990400 0.077100 0.114400 +vn 0.988800 0.075100 0.128800 +vn 0.989100 0.069600 0.129700 +vn 0.989800 0.069700 0.124500 +vn 0.989500 0.075100 0.123500 +vn 0.989400 0.064000 0.130600 +vn 0.989600 0.058300 0.131400 +vn 0.990300 0.058300 0.126300 +vn 0.990000 0.064100 0.125500 +vn 0.991700 0.080800 0.100100 +vn 0.992100 0.075000 0.101000 +vn 0.992700 0.075100 0.094800 +vn 0.992300 0.080900 0.093900 +vn 0.990700 0.079000 0.110400 +vn 0.991100 0.073300 0.111300 +vn 0.991700 0.073300 0.105400 +vn 0.991400 0.079000 0.104500 +vn 0.991400 0.067500 0.112100 +vn 0.991700 0.061500 0.112900 +vn 0.992300 0.061500 0.107100 +vn 0.992000 0.067500 0.106300 +vn 0.991400 -0.041100 0.124000 +vn 0.991100 -0.047900 0.123900 +vn 0.991700 -0.048500 0.119200 +vn 0.992000 -0.041700 0.119300 +vn 0.990300 -0.040000 0.132900 +vn 0.990000 -0.046500 0.132800 +vn 0.990600 -0.047200 0.128500 +vn 0.990900 -0.040600 0.128500 +vn 0.990000 -0.051800 0.131500 +vn 0.989600 -0.058300 0.131400 +vn 0.990100 -0.059100 0.127100 +vn 0.990500 -0.052500 0.127100 +vn 0.991900 -0.016000 0.125800 +vn 0.991800 -0.022700 0.125800 +vn 0.992400 -0.023000 0.121000 +vn 0.992500 -0.016300 0.121000 +vn 0.990800 -0.015600 0.134700 +vn 0.990600 -0.022100 0.134700 +vn 0.991200 -0.022400 0.130300 +vn 0.991300 -0.015800 0.130300 +vn 0.990600 -0.027900 0.134000 +vn 0.990400 -0.034400 0.133900 +vn 0.991000 -0.034900 0.129600 +vn 0.991200 -0.028300 0.129600 +vn 0.994300 -0.017000 0.105700 +vn 0.994100 -0.024000 0.105700 +vn 0.994700 -0.024300 0.100200 +vn 0.994800 -0.017200 0.100300 +vn 0.993100 -0.016500 0.116100 +vn 0.993000 -0.023300 0.116100 +vn 0.993500 -0.023700 0.111000 +vn 0.993700 -0.016700 0.111000 +vn 0.992900 -0.029500 0.115400 +vn 0.992700 -0.036400 0.115400 +vn 0.993200 -0.036900 0.110300 +vn 0.993400 -0.029900 0.110300 +vn 0.986800 0.048000 -0.154500 +vn 0.987100 0.041900 -0.154500 +vn 0.986600 0.041200 -0.157600 +vn 0.986400 0.047300 -0.157600 +vn 0.987800 0.049500 -0.147800 +vn 0.988100 0.043300 -0.147800 +vn 0.987600 0.042600 -0.151300 +vn 0.987300 0.048800 -0.151200 +vn 0.988100 0.038200 -0.149000 +vn 0.988300 0.032000 -0.149100 +vn 0.987800 0.031500 -0.152500 +vn 0.987600 0.037600 -0.152500 +vn 0.986100 0.068900 -0.151000 +vn 0.986500 0.062900 -0.151100 +vn 0.986100 0.061900 -0.154200 +vn 0.985700 0.067900 -0.154100 +vn 0.987000 0.071000 -0.144300 +vn 0.987400 0.064900 -0.144400 +vn 0.986900 0.063900 -0.147800 +vn 0.986500 0.070000 -0.147800 +vn 0.987400 0.060500 -0.146200 +vn 0.987800 0.054200 -0.146300 +vn 0.987300 0.053400 -0.149700 +vn 0.986900 0.059600 -0.149700 +vn 0.984600 0.064700 -0.162300 +vn 0.985000 0.059000 -0.162400 +vn 0.984600 0.058000 -0.164700 +vn 0.984300 0.063700 -0.164700 +vn 0.985300 0.066800 -0.157000 +vn 0.985700 0.060900 -0.157100 +vn 0.985300 0.060000 -0.159800 +vn 0.985000 0.065800 -0.159700 +vn 0.985700 0.056800 -0.158900 +vn 0.986000 0.050900 -0.159000 +vn 0.985600 0.050100 -0.161700 +vn 0.985300 0.055900 -0.161600 +vn 0.995000 0.059500 -0.080400 +vn 0.995400 0.052300 -0.080400 +vn 0.994900 0.051700 -0.086400 +vn 0.994500 0.058800 -0.086400 +vn 0.995900 0.060700 -0.067800 +vn 0.996300 0.053500 -0.067800 +vn 0.995800 0.052900 -0.074200 +vn 0.995400 0.060100 -0.074200 +vn 0.996500 0.047200 -0.068900 +vn 0.996800 0.039800 -0.068900 +vn 0.996400 0.039300 -0.075300 +vn 0.996100 0.046700 -0.075300 +vn 0.993400 0.084200 -0.077500 +vn 0.994000 0.077600 -0.077600 +vn 0.993500 0.076800 -0.083500 +vn 0.993000 0.083400 -0.083400 +vn 0.994200 0.085700 -0.065200 +vn 0.994700 0.079100 -0.065200 +vn 0.994400 0.078300 -0.071500 +vn 0.993800 0.085000 -0.071400 +vn 0.995100 0.073500 -0.066600 +vn 0.995600 0.066600 -0.066600 +vn 0.995200 0.065900 -0.072900 +vn 0.994700 0.072900 -0.072900 +vn 0.991700 0.080800 -0.100100 +vn 0.992200 0.074200 -0.100200 +vn 0.991700 0.073300 -0.105400 +vn 0.991200 0.079900 -0.105400 +vn 0.992600 0.082600 -0.089200 +vn 0.993100 0.075900 -0.089200 +vn 0.992700 0.075100 -0.094800 +vn 0.992100 0.081700 -0.094700 +vn 0.993400 0.070700 -0.090800 +vn 0.993800 0.063800 -0.090800 +vn 0.993300 0.063100 -0.096400 +vn 0.992900 0.069900 -0.096400 +vn 0.995700 -0.045700 -0.081000 +vn 0.995400 -0.052300 -0.080400 +vn 0.994800 -0.052300 -0.087000 +vn 0.995100 -0.045600 -0.087500 +vn 0.996600 -0.046700 -0.068400 +vn 0.996300 -0.053500 -0.067800 +vn 0.995800 -0.053500 -0.074700 +vn 0.996100 -0.046700 -0.075300 +vn 0.995900 -0.060100 -0.067200 +vn 0.995600 -0.066600 -0.066600 +vn 0.995100 -0.066600 -0.073500 +vn 0.995400 -0.060100 -0.074200 +vn 0.996400 -0.017900 -0.082700 +vn 0.996300 -0.025000 -0.082400 +vn 0.995700 -0.024900 -0.088700 +vn 0.995900 -0.017900 -0.088900 +vn 0.997400 -0.018300 -0.070000 +vn 0.997200 -0.025600 -0.069700 +vn 0.996700 -0.025600 -0.076400 +vn 0.996900 -0.018300 -0.076700 +vn 0.997100 -0.032700 -0.069300 +vn 0.996800 -0.039800 -0.068900 +vn 0.996300 -0.039800 -0.075700 +vn 0.996600 -0.032700 -0.076100 +vn 0.994200 -0.017000 -0.105700 +vn 0.994100 -0.023700 -0.105400 +vn 0.993500 -0.023700 -0.111000 +vn 0.993600 -0.017000 -0.111200 +vn 0.995400 -0.017400 -0.094600 +vn 0.995200 -0.024300 -0.094300 +vn 0.994700 -0.024300 -0.100200 +vn 0.994800 -0.017400 -0.100500 +vn 0.995100 -0.031200 -0.093900 +vn 0.994900 -0.037900 -0.093400 +vn 0.994300 -0.037900 -0.099500 +vn 0.994500 -0.031100 -0.099900 +vn 0.984400 -0.111400 -0.136400 +vn 0.984200 -0.115000 -0.134800 +vn 0.983600 -0.115000 -0.139300 +vn 0.983700 -0.111400 -0.140900 +vn 0.984900 -0.114600 -0.130000 +vn 0.984600 -0.118300 -0.128400 +vn 0.984000 -0.118200 -0.133200 +vn 0.984200 -0.114500 -0.134700 +vn 0.984400 -0.121800 -0.126800 +vn 0.984200 -0.125100 -0.125100 +vn 0.983600 -0.125100 -0.129900 +vn 0.983800 -0.121700 -0.131600 +vn 0.985200 -0.095600 -0.142500 +vn 0.985000 -0.099800 -0.141000 +vn 0.984300 -0.099700 -0.145400 +vn 0.984500 -0.095600 -0.146800 +vn 0.985800 -0.098400 -0.135900 +vn 0.985600 -0.102700 -0.134500 +vn 0.984900 -0.102600 -0.139200 +vn 0.985200 -0.098300 -0.140600 +vn 0.985300 -0.106800 -0.133000 +vn 0.985100 -0.110800 -0.131500 +vn 0.984500 -0.110700 -0.136300 +vn 0.984700 -0.106700 -0.137800 +vn 0.984000 -0.089900 -0.153500 +vn 0.983900 -0.093800 -0.152000 +vn 0.983300 -0.093800 -0.155800 +vn 0.983500 -0.089800 -0.157300 +vn 0.984600 -0.092800 -0.148300 +vn 0.984400 -0.096800 -0.146900 +vn 0.983800 -0.096800 -0.150900 +vn 0.984000 -0.092700 -0.152400 +vn 0.984200 -0.100800 -0.145300 +vn 0.984100 -0.104600 -0.143800 +vn 0.983500 -0.104500 -0.147900 +vn 0.983600 -0.100700 -0.149400 +vn 0.988800 -0.133000 -0.067800 +vn 0.988300 -0.137000 -0.066800 +vn 0.987900 -0.136900 -0.073100 +vn 0.988400 -0.132900 -0.074100 +vn 0.989200 -0.134800 -0.056700 +vn 0.988700 -0.138800 -0.055900 +vn 0.988400 -0.138800 -0.062200 +vn 0.988900 -0.134800 -0.063100 +vn 0.988200 -0.142600 -0.055100 +vn 0.987800 -0.146300 -0.054200 +vn 0.987400 -0.146200 -0.060500 +vn 0.987900 -0.142600 -0.061400 +vn 0.990800 -0.115300 -0.071500 +vn 0.990300 -0.120000 -0.070600 +vn 0.989800 -0.120000 -0.077100 +vn 0.990300 -0.115300 -0.078000 +vn 0.991300 -0.117100 -0.059900 +vn 0.990800 -0.121800 -0.059100 +vn 0.990400 -0.121800 -0.065800 +vn 0.990900 -0.117000 -0.066600 +vn 0.990300 -0.126300 -0.058300 +vn 0.989800 -0.130700 -0.057500 +vn 0.989400 -0.130600 -0.064000 +vn 0.989900 -0.126300 -0.064900 +vn 0.989400 -0.111200 -0.093100 +vn 0.989000 -0.115800 -0.091900 +vn 0.988400 -0.115700 -0.098000 +vn 0.988900 -0.111100 -0.099100 +vn 0.990100 -0.113300 -0.082600 +vn 0.989700 -0.118000 -0.081500 +vn 0.989100 -0.117900 -0.087800 +vn 0.989600 -0.113300 -0.088900 +vn 0.989200 -0.122500 -0.080500 +vn 0.988700 -0.126800 -0.079400 +vn 0.988200 -0.126700 -0.085600 +vn 0.988700 -0.122400 -0.086700 +vn 0.986600 -0.123400 -0.106900 +vn 0.986200 -0.127300 -0.105500 +vn 0.985600 -0.127200 -0.111100 +vn 0.986000 -0.123300 -0.112400 +vn 0.987200 -0.126100 -0.097900 +vn 0.986800 -0.130000 -0.096600 +vn 0.986200 -0.129900 -0.102400 +vn 0.986600 -0.126000 -0.103700 +vn 0.986400 -0.133700 -0.095300 +vn 0.986100 -0.137300 -0.094000 +vn 0.985500 -0.137200 -0.099700 +vn 0.985900 -0.133600 -0.101100 +vn 0.988000 -0.106400 -0.112200 +vn 0.987600 -0.110900 -0.110900 +vn 0.987000 -0.110800 -0.116500 +vn 0.987300 -0.106300 -0.117700 +vn 0.988700 -0.108800 -0.102900 +vn 0.988300 -0.113400 -0.101700 +vn 0.987700 -0.113300 -0.107600 +vn 0.988100 -0.108800 -0.108800 +vn 0.987900 -0.117800 -0.100500 +vn 0.987600 -0.122000 -0.099200 +vn 0.987000 -0.122000 -0.105000 +vn 0.987300 -0.117700 -0.106300 +vn 0.986500 -0.101100 -0.128700 +vn 0.986200 -0.105500 -0.127300 +vn 0.985600 -0.105400 -0.132300 +vn 0.985900 -0.101100 -0.133600 +vn 0.987200 -0.103800 -0.120700 +vn 0.986900 -0.108200 -0.119400 +vn 0.986300 -0.108200 -0.124700 +vn 0.986600 -0.103700 -0.126000 +vn 0.986600 -0.112500 -0.118000 +vn 0.986300 -0.116600 -0.116600 +vn 0.985700 -0.116600 -0.122000 +vn 0.986000 -0.112400 -0.123300 +vn 0.991600 0.106200 -0.074200 +vn 0.992200 0.100200 -0.074200 +vn 0.991800 0.099300 -0.080000 +vn 0.991200 0.105400 -0.079900 +vn 0.992200 0.107800 -0.062300 +vn 0.992800 0.101900 -0.062300 +vn 0.992500 0.101100 -0.068300 +vn 0.991900 0.107100 -0.068300 +vn 0.993200 0.097100 -0.063800 +vn 0.993800 0.090800 -0.063800 +vn 0.993500 0.090000 -0.069900 +vn 0.992900 0.096400 -0.069900 +vn 0.989600 0.125400 -0.070500 +vn 0.990300 0.120000 -0.070600 +vn 0.990000 0.119000 -0.076100 +vn 0.989300 0.124500 -0.076100 +vn 0.990100 0.127100 -0.059100 +vn 0.990800 0.121800 -0.059100 +vn 0.990500 0.120900 -0.064900 +vn 0.989900 0.126300 -0.064900 +vn 0.991200 0.117800 -0.060700 +vn 0.991800 0.112200 -0.060700 +vn 0.991500 0.111400 -0.066700 +vn 0.990900 0.117000 -0.066600 +vn 0.988400 0.121300 -0.091900 +vn 0.989000 0.115800 -0.091900 +vn 0.988700 0.114600 -0.096900 +vn 0.988000 0.120200 -0.096800 +vn 0.989000 0.123500 -0.081500 +vn 0.989700 0.118000 -0.081500 +vn 0.989300 0.116900 -0.086800 +vn 0.988700 0.122400 -0.086700 +vn 0.989900 0.114300 -0.083500 +vn 0.990600 0.108500 -0.083600 +vn 0.990200 0.107500 -0.089000 +vn 0.989600 0.113300 -0.088900 +vn 0.993500 0.111000 -0.023700 +vn 0.994100 0.105400 -0.023700 +vn 0.994000 0.105000 -0.030300 +vn 0.993400 0.110700 -0.030300 +vn 0.993700 0.111400 -0.010200 +vn 0.994300 0.106000 -0.010200 +vn 0.994200 0.105700 -0.017000 +vn 0.993600 0.111200 -0.017000 +vn 0.994900 0.100600 -0.010500 +vn 0.995400 0.094800 -0.010500 +vn 0.995400 0.094600 -0.017400 +vn 0.994800 0.100500 -0.017400 +vn 0.991200 0.130300 -0.022400 +vn 0.991800 0.125500 -0.022400 +vn 0.991700 0.125000 -0.028700 +vn 0.991100 0.130000 -0.028700 +vn 0.991400 0.130700 -0.009600 +vn 0.992000 0.126000 -0.009600 +vn 0.991900 0.125800 -0.016000 +vn 0.991300 0.130500 -0.016000 +vn 0.992600 0.121400 -0.009900 +vn 0.993200 0.116400 -0.009900 +vn 0.993100 0.116100 -0.016500 +vn 0.992500 0.121300 -0.016500 +vn 0.990600 0.128500 -0.047200 +vn 0.991200 0.123300 -0.047200 +vn 0.991000 0.122600 -0.053200 +vn 0.990400 0.127800 -0.053200 +vn 0.991000 0.129600 -0.034900 +vn 0.991600 0.124600 -0.035000 +vn 0.991400 0.124000 -0.041100 +vn 0.990800 0.129100 -0.041100 +vn 0.992100 0.120300 -0.035900 +vn 0.992700 0.114900 -0.036000 +vn 0.992500 0.114300 -0.042300 +vn 0.991900 0.119800 -0.042300 +vn 0.997600 0.063400 -0.026200 +vn 0.998100 0.056300 -0.026200 +vn 0.997900 0.055900 -0.033500 +vn 0.997400 0.063100 -0.033500 +vn 0.997900 0.063800 -0.011300 +vn 0.998300 0.056800 -0.011300 +vn 0.998200 0.056600 -0.018800 +vn 0.997800 0.063600 -0.018800 +vn 0.998700 0.050000 -0.011600 +vn 0.999000 0.042700 -0.011600 +vn 0.998900 0.042400 -0.019200 +vn 0.998600 0.049800 -0.019200 +vn 0.995700 0.088700 -0.024900 +vn 0.996300 0.082400 -0.025000 +vn 0.996100 0.082000 -0.032000 +vn 0.995600 0.088400 -0.031900 +vn 0.996000 0.089100 -0.010700 +vn 0.996500 0.082900 -0.010800 +vn 0.996400 0.082700 -0.017900 +vn 0.995900 0.088900 -0.017900 +vn 0.997000 0.076800 -0.011000 +vn 0.997500 0.070200 -0.011000 +vn 0.997400 0.070000 -0.018300 +vn 0.996900 0.076700 -0.018300 +vn 0.994800 0.087000 -0.052300 +vn 0.995400 0.080400 -0.052300 +vn 0.995100 0.079700 -0.058900 +vn 0.994500 0.086400 -0.058800 +vn 0.995400 0.088000 -0.038800 +vn 0.995900 0.081500 -0.038900 +vn 0.995700 0.081000 -0.045700 +vn 0.995100 0.087500 -0.045600 +vn 0.996300 0.075700 -0.039800 +vn 0.996800 0.068900 -0.039800 +vn 0.996600 0.068400 -0.046700 +vn 0.996100 0.075300 -0.046700 +vn 0.985300 0.088100 -0.146400 +vn 0.985800 0.082300 -0.146500 +vn 0.985400 0.081100 -0.149600 +vn 0.984900 0.086800 -0.149500 +vn 0.986000 0.090700 -0.139800 +vn 0.986500 0.084800 -0.139900 +vn 0.986100 0.083600 -0.143300 +vn 0.985600 0.089400 -0.143200 +vn 0.986500 0.081100 -0.142200 +vn 0.987000 0.075100 -0.142300 +vn 0.986600 0.074000 -0.145700 +vn 0.986100 0.079900 -0.145600 +vn 0.984400 0.105200 -0.140900 +vn 0.985000 0.099800 -0.141000 +vn 0.984700 0.098300 -0.144000 +vn 0.984100 0.103700 -0.143900 +vn 0.985000 0.108200 -0.134400 +vn 0.985600 0.102700 -0.134500 +vn 0.985300 0.101200 -0.137800 +vn 0.984700 0.106700 -0.137700 +vn 0.985500 0.099700 -0.137200 +vn 0.986100 0.094000 -0.137300 +vn 0.985700 0.092700 -0.140700 +vn 0.985200 0.098300 -0.140600 +vn 0.983400 0.099200 -0.152000 +vn 0.983900 0.093800 -0.152000 +vn 0.983700 0.092300 -0.154400 +vn 0.983500 0.097600 -0.152400 +vn 0.983900 0.102200 -0.146800 +vn 0.984400 0.096800 -0.146900 +vn 0.984200 0.095300 -0.149500 +vn 0.983600 0.100700 -0.149500 +vn 0.984200 0.094100 -0.149700 +vn 0.984700 0.088600 -0.149800 +vn 0.984500 0.087200 -0.152500 +vn 0.984000 0.092700 -0.152400 +vn 0.988400 0.098000 -0.115700 +vn 0.989000 0.091900 -0.115800 +vn 0.988600 0.090800 -0.120200 +vn 0.988000 0.096800 -0.120200 +vn 0.989300 0.100300 -0.106300 +vn 0.989900 0.094200 -0.106400 +vn 0.989400 0.093100 -0.111200 +vn 0.988900 0.099100 -0.111100 +vn 0.990000 0.089900 -0.108400 +vn 0.990600 0.083600 -0.108500 +vn 0.990100 0.082600 -0.113300 +vn 0.989600 0.088900 -0.113300 +vn 0.987000 0.116500 -0.110800 +vn 0.987600 0.110900 -0.110900 +vn 0.987300 0.109600 -0.115200 +vn 0.986700 0.115200 -0.115200 +vn 0.987700 0.119000 -0.101600 +vn 0.988300 0.113400 -0.101700 +vn 0.988000 0.112200 -0.106400 +vn 0.987300 0.117700 -0.106300 +vn 0.988500 0.109900 -0.104000 +vn 0.989100 0.104100 -0.104100 +vn 0.988700 0.102900 -0.108800 +vn 0.988100 0.108800 -0.108800 +vn 0.985600 0.111100 -0.127200 +vn 0.986200 0.105500 -0.127300 +vn 0.985900 0.104100 -0.131000 +vn 0.985300 0.109600 -0.130900 +vn 0.986300 0.113800 -0.119300 +vn 0.986900 0.108200 -0.119400 +vn 0.986600 0.106900 -0.123400 +vn 0.986000 0.112400 -0.123300 +vn 0.987000 0.105000 -0.122000 +vn 0.987600 0.099200 -0.122000 +vn 0.987200 0.097900 -0.126100 +vn 0.986600 0.103700 -0.126000 +vn 0.990900 0.053900 -0.123300 +vn 0.991200 0.047200 -0.123300 +vn 0.990700 0.046600 -0.127900 +vn 0.990400 0.053200 -0.127800 +vn 0.992000 0.055400 -0.113700 +vn 0.992300 0.048600 -0.113700 +vn 0.991800 0.047900 -0.118600 +vn 0.991400 0.054700 -0.118600 +vn 0.992500 0.042800 -0.114900 +vn 0.992700 0.036000 -0.114900 +vn 0.992200 0.035500 -0.119800 +vn 0.991900 0.042300 -0.119800 +vn 0.989800 0.077100 -0.120000 +vn 0.990300 0.070600 -0.120000 +vn 0.989800 0.069700 -0.124500 +vn 0.989300 0.076100 -0.124500 +vn 0.990700 0.079000 -0.110400 +vn 0.991200 0.072400 -0.110500 +vn 0.990800 0.071500 -0.115300 +vn 0.990300 0.078000 -0.115300 +vn 0.991400 0.067500 -0.112100 +vn 0.991800 0.060700 -0.112200 +vn 0.991300 0.059900 -0.117100 +vn 0.990900 0.066600 -0.117000 +vn 0.987900 0.073100 -0.136900 +vn 0.988300 0.066800 -0.137000 +vn 0.987900 0.065800 -0.140800 +vn 0.987400 0.072000 -0.140700 +vn 0.988800 0.075100 -0.128800 +vn 0.989300 0.068700 -0.128900 +vn 0.988800 0.067800 -0.133000 +vn 0.988400 0.074100 -0.132900 +vn 0.989400 0.064000 -0.130600 +vn 0.989800 0.057500 -0.130700 +vn 0.989200 0.056700 -0.134800 +vn 0.988900 0.063100 -0.134800 +vn 0.992000 0.003300 0.126200 +vn 0.992600 0.003300 0.121400 +vn 0.990800 0.003200 0.135100 +vn 0.990800 -0.003100 0.135100 +vn 0.990800 -0.009500 0.135100 +vn 0.991400 -0.009600 0.130700 +vn 0.991700 0.029100 0.125400 +vn 0.991800 0.022700 0.125800 +vn 0.992400 0.022700 0.120700 +vn 0.992300 0.029100 0.120300 +vn 0.990500 0.028300 0.134300 +vn 0.990600 0.022100 0.134700 +vn 0.991300 0.022100 0.130000 +vn 0.991200 0.028300 0.129600 +vn 0.990700 0.015800 0.134900 +vn 0.990800 0.009500 0.135100 +vn 0.991400 0.009500 0.130600 +vn 0.991300 0.015800 0.130300 +vn 0.994000 0.030700 0.105400 +vn 0.994100 0.024000 0.105700 +vn 0.994700 0.024000 0.099900 +vn 0.994600 0.030800 0.099500 +vn 0.992800 0.029900 0.115800 +vn 0.993000 0.023300 0.116100 +vn 0.993600 0.023400 0.110700 +vn 0.993400 0.029900 0.110300 +vn 0.993100 0.016700 0.116300 +vn 0.993100 0.010000 0.116500 +vn 0.993700 0.010100 0.111300 +vn 0.993700 0.016700 0.111000 +vn 0.987500 0.002900 0.157400 +vn 0.988000 0.002900 0.154100 +vn 0.986600 0.002800 0.163400 +vn 0.986600 -0.002700 0.163400 +vn 0.986500 -0.008400 0.163400 +vn 0.987000 -0.008500 0.160500 +vn 0.987300 0.025800 0.156700 +vn 0.987400 0.020100 0.157000 +vn 0.988000 0.020100 0.153400 +vn 0.987900 0.025800 0.153000 +vn 0.986400 0.025000 0.162700 +vn 0.986400 0.019500 0.163000 +vn 0.987000 0.019500 0.159800 +vn 0.986900 0.025000 0.159400 +vn 0.986500 0.013900 0.163200 +vn 0.986500 0.008400 0.163400 +vn 0.987000 0.008400 0.160300 +vn 0.987000 0.013900 0.160100 +vn 0.989400 0.027500 0.142500 +vn 0.989500 0.021400 0.142800 +vn 0.990100 0.021400 0.138500 +vn 0.990000 0.027500 0.138100 +vn 0.988300 0.026600 0.150000 +vn 0.988400 0.020800 0.150300 +vn 0.989000 0.020800 0.146400 +vn 0.988900 0.026600 0.145900 +vn 0.988500 0.014900 0.150500 +vn 0.988500 0.008900 0.150700 +vn 0.989100 0.008900 0.146900 +vn 0.989100 0.014900 0.146700 +vn 0.987200 -0.036500 0.155200 +vn 0.987000 -0.042600 0.155200 +vn 0.987500 -0.043200 0.151900 +vn 0.987700 -0.037100 0.151900 +vn 0.986300 -0.035300 0.161200 +vn 0.986100 -0.041200 0.161200 +vn 0.986500 -0.041900 0.158300 +vn 0.986700 -0.035900 0.158300 +vn 0.986100 -0.045800 0.159800 +vn 0.985800 -0.051700 0.159700 +vn 0.986200 -0.052500 0.156800 +vn 0.986500 -0.046500 0.156900 +vn 0.987500 -0.014200 0.157000 +vn 0.987400 -0.020100 0.157000 +vn 0.987900 -0.020400 0.153700 +vn 0.988000 -0.014400 0.153700 +vn 0.986500 -0.013700 0.163000 +vn 0.986400 -0.019500 0.163000 +vn 0.986900 -0.019800 0.160100 +vn 0.987000 -0.013900 0.160100 +vn 0.986400 -0.024600 0.162300 +vn 0.986300 -0.030500 0.162300 +vn 0.986700 -0.030900 0.159300 +vn 0.986900 -0.025000 0.159400 +vn 0.989600 -0.015100 0.142900 +vn 0.989500 -0.021400 0.142800 +vn 0.990100 -0.021700 0.138800 +vn 0.990200 -0.015300 0.138900 +vn 0.988500 -0.014600 0.150300 +vn 0.988400 -0.020800 0.150300 +vn 0.989000 -0.021100 0.146700 +vn 0.989100 -0.014900 0.146700 +vn 0.988400 -0.026200 0.149600 +vn 0.988200 -0.032400 0.149500 +vn 0.988700 -0.032900 0.145900 +vn 0.988900 -0.026600 0.145900 +vn 0.988400 0.098000 0.115700 +vn 0.988800 0.093000 0.116800 +vn 0.989400 0.093100 0.111200 +vn 0.989100 0.098100 0.110000 +vn 0.987600 0.095600 0.124400 +vn 0.987900 0.090700 0.125600 +vn 0.988600 0.090800 0.120200 +vn 0.988300 0.095700 0.119000 +vn 0.988200 0.085600 0.126700 +vn 0.988500 0.080400 0.127800 +vn 0.989200 0.080500 0.122500 +vn 0.988900 0.085700 0.121400 +vn 0.987000 0.116500 0.110800 +vn 0.987400 0.112100 0.112100 +vn 0.988000 0.112200 0.106400 +vn 0.987600 0.116500 0.105100 +vn 0.986300 0.113800 0.119300 +vn 0.986600 0.109500 0.120700 +vn 0.987300 0.109600 0.115200 +vn 0.986900 0.113900 0.113900 +vn 0.987000 0.105000 0.122000 +vn 0.987300 0.100400 0.123200 +vn 0.987900 0.100500 0.117800 +vn 0.987600 0.105100 0.116500 +vn 0.988400 0.121300 0.091900 +vn 0.988800 0.116800 0.093000 +vn 0.989300 0.116900 0.086800 +vn 0.988900 0.121400 0.085700 +vn 0.987700 0.119000 0.101600 +vn 0.988100 0.114500 0.102900 +vn 0.988700 0.114600 0.096900 +vn 0.988300 0.119000 0.095700 +vn 0.988500 0.109900 0.104000 +vn 0.988900 0.105200 0.105200 +vn 0.989500 0.105300 0.099200 +vn 0.989100 0.110000 0.098100 +vn 0.985300 0.088100 0.146400 +vn 0.985500 0.083500 0.147700 +vn 0.986100 0.083600 0.143300 +vn 0.985900 0.088200 0.142000 +vn 0.984600 0.085500 0.152400 +vn 0.984800 0.081000 0.153600 +vn 0.985400 0.081100 0.149600 +vn 0.985200 0.085600 0.148300 +vn 0.985000 0.076400 0.154800 +vn 0.985200 0.071700 0.156000 +vn 0.985800 0.071700 0.152000 +vn 0.985600 0.076500 0.150800 +vn 0.984400 0.105200 0.140900 +vn 0.984600 0.101200 0.142400 +vn 0.985300 0.101200 0.137800 +vn 0.985000 0.105300 0.136300 +vn 0.984100 0.100300 0.146800 +vn 0.984100 0.098300 0.148300 +vn 0.984700 0.098300 0.144000 +vn 0.984500 0.102300 0.142500 +vn 0.984200 0.094100 0.149700 +vn 0.984400 0.089900 0.151100 +vn 0.985100 0.089900 0.146900 +vn 0.984900 0.094200 0.145500 +vn 0.985600 0.111100 0.127200 +vn 0.985900 0.106800 0.128600 +vn 0.986600 0.106900 0.123400 +vn 0.986300 0.111100 0.122000 +vn 0.985000 0.108200 0.134400 +vn 0.985300 0.104000 0.135800 +vn 0.985900 0.104100 0.131000 +vn 0.985600 0.108300 0.129500 +vn 0.985500 0.099700 0.137200 +vn 0.985800 0.095300 0.138500 +vn 0.986400 0.095300 0.133700 +vn 0.986200 0.099800 0.132400 +vn 0.986800 0.048000 0.154500 +vn 0.987000 0.042600 0.155200 +vn 0.987600 0.042600 0.151300 +vn 0.987400 0.048000 0.150500 +vn 0.985900 0.046500 0.160500 +vn 0.986100 0.041200 0.161200 +vn 0.986600 0.041200 0.157600 +vn 0.986500 0.046500 0.156900 +vn 0.986200 0.035900 0.161800 +vn 0.986300 0.030400 0.162300 +vn 0.986800 0.030500 0.158900 +vn 0.986700 0.035900 0.158300 +vn 0.986100 0.068900 0.151000 +vn 0.986300 0.063800 0.152000 +vn 0.986900 0.063900 0.147800 +vn 0.986800 0.069000 0.146800 +vn 0.985300 0.066800 0.157000 +vn 0.985500 0.061900 0.158000 +vn 0.986100 0.061900 0.154200 +vn 0.985900 0.066900 0.153100 +vn 0.985700 0.056800 0.158900 +vn 0.985800 0.051700 0.159700 +vn 0.986400 0.051800 0.156100 +vn 0.986300 0.056900 0.155200 +vn 0.987900 0.073100 0.136900 +vn 0.988100 0.067700 0.137900 +vn 0.988800 0.067800 0.133000 +vn 0.988600 0.073100 0.132000 +vn 0.987000 0.071000 0.144300 +vn 0.987200 0.065800 0.145300 +vn 0.987900 0.065800 0.140800 +vn 0.987600 0.071100 0.139700 +vn 0.987400 0.060500 0.146200 +vn 0.987600 0.055000 0.147000 +vn 0.988200 0.055100 0.142600 +vn 0.988100 0.060500 0.141700 +vn 0.993500 0.111000 0.023700 +vn 0.994100 0.105700 0.024000 +vn 0.994200 0.105700 0.017000 +vn 0.993700 0.111000 0.016700 +vn 0.993200 0.110300 0.036900 +vn 0.993800 0.105000 0.037400 +vn 0.994000 0.105000 0.030300 +vn 0.993400 0.110300 0.029900 +vn 0.994300 0.099500 0.037900 +vn 0.994800 0.093800 0.038400 +vn 0.995100 0.093900 0.031200 +vn 0.994600 0.099500 0.030800 +vn 0.991200 0.130300 0.022400 +vn 0.991800 0.125800 0.022700 +vn 0.991900 0.125800 0.016000 +vn 0.991300 0.130300 0.015800 +vn 0.991000 0.129600 0.034900 +vn 0.991500 0.125000 0.035400 +vn 0.991700 0.125100 0.028700 +vn 0.991200 0.129600 0.028300 +vn 0.992100 0.120300 0.035900 +vn 0.992700 0.115400 0.036400 +vn 0.992900 0.115400 0.029500 +vn 0.992300 0.120300 0.029100 +vn 0.992000 0.126100 -0.003200 +vn 0.991400 0.130700 0.009600 +vn 0.992000 0.126100 0.009800 +vn 0.992000 0.126100 0.003200 +vn 0.992600 0.121400 0.009900 +vn 0.993100 0.116500 0.010000 +vn 0.993200 0.116500 0.003300 +vn 0.992600 0.121400 0.003300 +vn 0.991600 0.106200 0.074200 +vn 0.992100 0.101000 0.075000 +vn 0.992500 0.101100 0.068300 +vn 0.992000 0.106300 0.067500 +vn 0.990900 0.104400 0.085500 +vn 0.991300 0.099200 0.086500 +vn 0.991800 0.099300 0.080000 +vn 0.991400 0.104500 0.079000 +vn 0.991700 0.093800 0.087400 +vn 0.992200 0.088300 0.088300 +vn 0.992700 0.088300 0.081800 +vn 0.992300 0.093900 0.080900 +vn 0.989600 0.125400 0.070500 +vn 0.990100 0.120900 0.071500 +vn 0.990500 0.120900 0.064900 +vn 0.990000 0.125500 0.064100 +vn 0.989000 0.123500 0.081500 +vn 0.989500 0.119000 0.082500 +vn 0.990000 0.119000 0.076100 +vn 0.989500 0.123500 0.075100 +vn 0.989900 0.114300 0.083500 +vn 0.990400 0.109400 0.084500 +vn 0.990900 0.109500 0.078100 +vn 0.990400 0.114400 0.077100 +vn 0.990600 0.128500 0.047200 +vn 0.991100 0.123900 0.047900 +vn 0.991400 0.124000 0.041100 +vn 0.990900 0.128500 0.040600 +vn 0.990100 0.127100 0.059100 +vn 0.990700 0.122600 0.059900 +vn 0.991000 0.122600 0.053200 +vn 0.990500 0.127100 0.052500 +vn 0.991200 0.117800 0.060700 +vn 0.991700 0.112900 0.061500 +vn 0.992100 0.113000 0.054700 +vn 0.991600 0.117900 0.054000 +vn 0.995000 0.059500 0.080400 +vn 0.995300 0.052900 0.080900 +vn 0.995800 0.052900 0.074200 +vn 0.995500 0.059500 0.073600 +vn 0.994000 0.058200 0.092200 +vn 0.994300 0.051700 0.092800 +vn 0.994900 0.051700 0.086400 +vn 0.994600 0.058200 0.085700 +vn 0.994600 0.045100 0.093400 +vn 0.994800 0.038400 0.093800 +vn 0.995400 0.038400 0.087500 +vn 0.995200 0.045100 0.087000 +vn 0.993400 0.084200 0.077500 +vn 0.993900 0.078300 0.078300 +vn 0.994400 0.078300 0.071500 +vn 0.993900 0.084300 0.070700 +vn 0.992600 0.082600 0.089200 +vn 0.993000 0.076700 0.090000 +vn 0.993500 0.076800 0.083500 +vn 0.993100 0.082600 0.082600 +vn 0.993400 0.070700 0.090800 +vn 0.993700 0.064500 0.091500 +vn 0.994300 0.064500 0.085000 +vn 0.993900 0.070700 0.084300 +vn 0.994800 0.087000 0.052300 +vn 0.995300 0.080900 0.052900 +vn 0.995700 0.081000 0.045700 +vn 0.995200 0.087000 0.045100 +vn 0.994200 0.085700 0.065200 +vn 0.994600 0.079700 0.065900 +vn 0.995100 0.079700 0.058900 +vn 0.994600 0.085700 0.058200 +vn 0.995100 0.073500 0.066600 +vn 0.995500 0.067200 0.067200 +vn 0.995900 0.067200 0.060100 +vn 0.995500 0.073600 0.059500 +vn 0.989300 -0.086800 0.116900 +vn 0.988800 -0.093000 0.116800 +vn 0.989200 -0.094100 0.112200 +vn 0.989800 -0.087900 0.112300 +vn 0.988500 -0.084600 0.125700 +vn 0.987900 -0.090700 0.125600 +vn 0.988400 -0.091900 0.121300 +vn 0.988900 -0.085700 0.121400 +vn 0.987900 -0.094500 0.123300 +vn 0.987300 -0.100400 0.123200 +vn 0.987700 -0.101600 0.119000 +vn 0.988300 -0.095700 0.119000 +vn 0.990500 -0.064900 0.120900 +vn 0.990100 -0.071500 0.120900 +vn 0.990600 -0.072400 0.116200 +vn 0.991000 -0.065800 0.116200 +vn 0.989500 -0.063200 0.129800 +vn 0.989100 -0.069600 0.129700 +vn 0.989600 -0.070500 0.125400 +vn 0.990000 -0.064100 0.125500 +vn 0.989000 -0.074100 0.127900 +vn 0.988500 -0.080400 0.127800 +vn 0.989000 -0.081500 0.123500 +vn 0.989500 -0.075100 0.123500 +vn 0.992500 -0.068300 0.101100 +vn 0.992100 -0.075000 0.101000 +vn 0.992500 -0.075900 0.095600 +vn 0.993000 -0.069100 0.095600 +vn 0.991500 -0.066700 0.111400 +vn 0.991100 -0.073300 0.111300 +vn 0.991600 -0.074200 0.106200 +vn 0.992000 -0.067500 0.106300 +vn 0.990900 -0.078100 0.109500 +vn 0.990400 -0.084500 0.109400 +vn 0.990900 -0.085500 0.104400 +vn 0.991400 -0.079000 0.104500 +vn 0.986000 -0.077600 0.147800 +vn 0.985500 -0.083500 0.147700 +vn 0.985900 -0.084700 0.144400 +vn 0.986400 -0.078800 0.144500 +vn 0.985200 -0.075300 0.153700 +vn 0.984800 -0.081000 0.153600 +vn 0.985100 -0.082300 0.150700 +vn 0.985600 -0.076500 0.150800 +vn 0.984900 -0.084300 0.151100 +vn 0.984400 -0.089900 0.151100 +vn 0.984700 -0.091300 0.148200 +vn 0.985200 -0.085600 0.148300 +vn 0.986700 -0.057800 0.152100 +vn 0.986300 -0.063800 0.152000 +vn 0.986700 -0.064800 0.148700 +vn 0.987100 -0.058700 0.148800 +vn 0.985800 -0.056000 0.158100 +vn 0.985500 -0.061900 0.158000 +vn 0.985900 -0.062900 0.155100 +vn 0.986300 -0.056900 0.155100 +vn 0.985600 -0.065800 0.156000 +vn 0.985200 -0.071700 0.156000 +vn 0.985500 -0.072800 0.153100 +vn 0.985900 -0.066900 0.153100 +vn 0.988500 -0.061400 0.137900 +vn 0.988100 -0.067700 0.137900 +vn 0.988600 -0.068700 0.133900 +vn 0.989000 -0.062300 0.134000 +vn 0.987600 -0.059600 0.145400 +vn 0.987200 -0.065800 0.145300 +vn 0.987700 -0.066800 0.141700 +vn 0.988100 -0.060500 0.141700 +vn 0.987200 -0.070000 0.143400 +vn 0.986700 -0.076100 0.143300 +vn 0.987200 -0.077200 0.139700 +vn 0.987600 -0.071100 0.139700 +vn 0.984400 -0.111400 0.136400 +vn 0.983800 -0.116600 0.136300 +vn 0.984000 -0.118200 0.133200 +vn 0.984600 -0.113000 0.133300 +vn 0.983900 -0.108200 0.142100 +vn 0.983400 -0.113300 0.142000 +vn 0.983600 -0.115000 0.139300 +vn 0.984100 -0.109800 0.139300 +vn 0.983600 -0.115100 0.138800 +vn 0.983300 -0.120000 0.136700 +vn 0.983200 -0.121700 0.135900 +vn 0.983800 -0.116800 0.136000 +vn 0.985200 -0.095600 0.142500 +vn 0.984600 -0.101200 0.142400 +vn 0.984900 -0.102600 0.139200 +vn 0.985500 -0.097000 0.139300 +vn 0.984600 -0.092800 0.148300 +vn 0.984100 -0.098300 0.148300 +vn 0.984300 -0.099700 0.145400 +vn 0.984900 -0.094200 0.145500 +vn 0.984200 -0.100800 0.145300 +vn 0.983700 -0.106100 0.145200 +vn 0.983900 -0.107600 0.142400 +vn 0.984500 -0.102300 0.142500 +vn 0.986500 -0.101100 0.128700 +vn 0.985900 -0.106800 0.128600 +vn 0.986300 -0.108200 0.124700 +vn 0.986900 -0.102500 0.124800 +vn 0.985800 -0.098400 0.135900 +vn 0.985300 -0.104000 0.135800 +vn 0.985600 -0.105400 0.132300 +vn 0.986200 -0.099800 0.132400 +vn 0.985300 -0.106800 0.133000 +vn 0.984800 -0.112200 0.132900 +vn 0.985000 -0.113700 0.129400 +vn 0.985600 -0.108300 0.129500 +vn 0.994700 -0.099900 0.024000 +vn 0.994100 -0.105700 0.024000 +vn 0.994200 -0.106000 0.017200 +vn 0.994800 -0.100300 0.017200 +vn 0.994400 -0.099100 0.037400 +vn 0.993800 -0.105000 0.037400 +vn 0.994000 -0.105400 0.030700 +vn 0.994600 -0.099500 0.030800 +vn 0.993300 -0.109800 0.036400 +vn 0.992700 -0.115400 0.036400 +vn 0.992800 -0.115800 0.029900 +vn 0.993400 -0.110300 0.029900 +vn 0.996800 -0.076100 0.025300 +vn 0.996300 -0.082700 0.025300 +vn 0.996400 -0.082900 0.018100 +vn 0.996900 -0.076400 0.018100 +vn 0.996400 -0.075300 0.039300 +vn 0.995900 -0.081900 0.039300 +vn 0.996100 -0.082300 0.032300 +vn 0.996600 -0.075700 0.032400 +vn 0.995400 -0.087500 0.038400 +vn 0.994800 -0.093800 0.038400 +vn 0.995000 -0.094200 0.031500 +vn 0.995600 -0.088000 0.031600 +vn 0.996500 -0.083100 -0.003600 +vn 0.997000 -0.076900 -0.003700 +vn 0.997000 -0.076700 0.010900 +vn 0.996500 -0.083000 0.010900 +vn 0.996500 -0.083100 0.003600 +vn 0.997000 -0.076800 0.003600 +vn 0.996000 -0.089000 0.010600 +vn 0.995400 -0.094900 0.010600 +vn 0.995500 -0.095000 0.003500 +vn 0.996000 -0.089100 0.003500 +vn 0.992700 -0.094800 0.075100 +vn 0.992100 -0.101000 0.075000 +vn 0.992400 -0.101800 0.069100 +vn 0.993000 -0.095600 0.069100 +vn 0.991900 -0.093000 0.086500 +vn 0.991300 -0.099200 0.086500 +vn 0.991700 -0.100100 0.080800 +vn 0.992300 -0.093900 0.080900 +vn 0.991000 -0.103500 0.084600 +vn 0.990400 -0.109400 0.084500 +vn 0.990700 -0.110400 0.079000 +vn 0.991400 -0.104500 0.079000 +vn 0.994400 -0.071500 0.078300 +vn 0.993900 -0.078300 0.078300 +vn 0.994300 -0.079000 0.072200 +vn 0.994800 -0.072200 0.072200 +vn 0.993500 -0.069900 0.090000 +vn 0.993000 -0.076700 0.090000 +vn 0.993400 -0.077500 0.084200 +vn 0.993900 -0.070700 0.084300 +vn 0.992700 -0.081800 0.088300 +vn 0.992200 -0.088300 0.088300 +vn 0.992600 -0.089200 0.082600 +vn 0.993100 -0.082600 0.082600 +vn 0.995800 -0.074200 0.052900 +vn 0.995300 -0.080900 0.052900 +vn 0.995600 -0.081500 0.046200 +vn 0.996100 -0.074800 0.046200 +vn 0.995200 -0.072900 0.065900 +vn 0.994600 -0.079700 0.065900 +vn 0.995000 -0.080400 0.059500 +vn 0.995500 -0.073600 0.059500 +vn 0.994300 -0.085000 0.064500 +vn 0.993700 -0.091500 0.064500 +vn 0.994000 -0.092200 0.058200 +vn 0.994600 -0.085700 0.058200 +vn 0.988800 -0.133000 0.067800 +vn 0.988100 -0.137900 0.067700 +vn 0.988400 -0.138800 0.062200 +vn 0.989000 -0.134000 0.062300 +vn 0.988300 -0.130900 0.078300 +vn 0.987600 -0.135900 0.078300 +vn 0.987900 -0.136900 0.073100 +vn 0.988600 -0.132000 0.073100 +vn 0.987400 -0.138700 0.076200 +vn 0.986700 -0.143300 0.076100 +vn 0.987000 -0.144300 0.071000 +vn 0.987600 -0.139700 0.071100 +vn 0.990800 -0.115300 0.071500 +vn 0.990100 -0.120900 0.071500 +vn 0.990400 -0.121700 0.065800 +vn 0.991000 -0.116200 0.065800 +vn 0.990100 -0.113300 0.082600 +vn 0.989500 -0.119000 0.082500 +vn 0.989800 -0.120000 0.077100 +vn 0.990400 -0.114400 0.077100 +vn 0.989200 -0.122500 0.080500 +vn 0.988500 -0.127800 0.080400 +vn 0.988800 -0.128800 0.075100 +vn 0.989500 -0.123500 0.075100 +vn 0.991800 -0.118600 0.047900 +vn 0.991100 -0.123900 0.047900 +vn 0.991300 -0.124500 0.041700 +vn 0.992000 -0.119300 0.041700 +vn 0.991300 -0.117100 0.059900 +vn 0.990700 -0.122600 0.059900 +vn 0.990900 -0.123300 0.053900 +vn 0.991600 -0.117900 0.054000 +vn 0.990300 -0.126300 0.058300 +vn 0.989600 -0.131400 0.058300 +vn 0.989800 -0.132200 0.052500 +vn 0.990500 -0.127100 0.052500 +vn 0.999800 0.004000 0.020100 +vn 0.999400 0.003900 0.035400 +vn 0.999000 -0.011700 0.042800 +vn 0.999300 -0.011800 0.035400 +vn 0.999400 -0.003900 0.035400 +vn 0.999000 0.035100 0.027300 +vn 0.999200 0.027500 0.027500 +vn 0.999400 0.027500 0.019700 +vn 0.999200 0.035100 0.019400 +vn 0.998500 0.034500 0.042200 +vn 0.998700 0.027100 0.042400 +vn 0.999000 0.027100 0.034800 +vn 0.998800 0.034500 0.034500 +vn 0.998900 0.019400 0.042600 +vn 0.999000 0.011700 0.042800 +vn 0.999300 0.011700 0.035300 +vn 0.999200 0.019400 0.035100 +vn 0.999400 0.035500 -0.004000 +vn 0.999300 0.035400 0.011800 +vn 0.999500 0.027900 0.012000 +vn 0.999400 0.035400 0.003900 +vn 0.999700 0.020100 0.012100 +vn 0.999900 0.012200 0.012200 +vn 0.999800 0.020100 0.004000 +vn 0.996500 0.003600 0.083100 +vn 0.997000 0.003600 0.076800 +vn 0.995500 0.003500 0.095000 +vn 0.996000 0.003500 0.089100 +vn 0.995500 -0.003500 0.094900 +vn 0.995400 -0.010600 0.094900 +vn 0.996000 -0.010700 0.089100 +vn 0.996000 -0.003500 0.089100 +vn 0.996100 0.032300 0.082300 +vn 0.996300 0.025300 0.082700 +vn 0.996800 0.025300 0.076100 +vn 0.996600 0.032400 0.075700 +vn 0.995000 0.031500 0.094200 +vn 0.995200 0.024600 0.094600 +vn 0.995800 0.024600 0.088400 +vn 0.995600 0.031600 0.088000 +vn 0.995300 0.017600 0.094800 +vn 0.995400 0.010600 0.094900 +vn 0.996000 0.010600 0.089000 +vn 0.995900 0.017700 0.088700 +vn 0.997800 0.033900 0.056300 +vn 0.998000 0.026500 0.056600 +vn 0.998400 0.026500 0.049300 +vn 0.998200 0.033900 0.049000 +vn 0.997000 0.033100 0.069700 +vn 0.997200 0.025900 0.070000 +vn 0.997700 0.025900 0.063100 +vn 0.997500 0.033100 0.062700 +vn 0.997400 0.018600 0.070200 +vn 0.997500 0.011200 0.070400 +vn 0.997900 0.011200 0.063600 +vn 0.997800 0.018600 0.063400 +vn 0.995700 -0.045700 0.081000 +vn 0.995300 -0.052900 0.080900 +vn 0.995800 -0.053500 0.074700 +vn 0.996100 -0.046200 0.074800 +vn 0.994700 -0.044600 0.092800 +vn 0.994300 -0.051700 0.092800 +vn 0.994800 -0.052300 0.087000 +vn 0.995200 -0.045100 0.087000 +vn 0.994100 -0.057500 0.091500 +vn 0.993700 -0.064500 0.091500 +vn 0.994200 -0.065200 0.085700 +vn 0.994600 -0.058200 0.085700 +vn 0.996400 -0.017900 0.082700 +vn 0.996300 -0.025300 0.082700 +vn 0.996700 -0.025600 0.076400 +vn 0.996900 -0.018100 0.076400 +vn 0.995400 -0.017400 0.094600 +vn 0.995200 -0.024600 0.094600 +vn 0.995700 -0.024900 0.088700 +vn 0.995900 -0.017700 0.088700 +vn 0.995100 -0.031200 0.093900 +vn 0.994800 -0.038400 0.093800 +vn 0.995400 -0.038800 0.088000 +vn 0.995600 -0.031600 0.088000 +vn 0.998200 -0.018800 0.056600 +vn 0.998000 -0.026500 0.056600 +vn 0.998400 -0.026800 0.049600 +vn 0.998600 -0.019000 0.049600 +vn 0.997400 -0.018300 0.070000 +vn 0.997200 -0.025900 0.070000 +vn 0.997600 -0.026200 0.063400 +vn 0.997800 -0.018600 0.063400 +vn 0.997100 -0.032700 0.069300 +vn 0.996800 -0.040200 0.069300 +vn 0.997200 -0.040700 0.062700 +vn 0.997500 -0.033100 0.062700 +vn 0.987500 0.002900 -0.157400 +vn 0.988600 0.003000 -0.150700 +vn 0.988000 0.002900 -0.154200 +vn 0.988600 -0.002900 -0.150700 +vn 0.988600 -0.008800 -0.150500 +vn 0.988000 -0.008800 -0.154100 +vn 0.988000 -0.002900 -0.154200 +vn 0.987300 0.025800 -0.156700 +vn 0.987400 0.019800 -0.156700 +vn 0.987000 0.019500 -0.159800 +vn 0.986800 0.025400 -0.159800 +vn 0.988300 0.026600 -0.150000 +vn 0.988500 0.020500 -0.150000 +vn 0.988000 0.020100 -0.153400 +vn 0.987800 0.026200 -0.153400 +vn 0.988500 0.014900 -0.150500 +vn 0.988600 0.008800 -0.150500 +vn 0.988000 0.008700 -0.154000 +vn 0.988000 0.014600 -0.154000 +vn 0.985500 0.024200 -0.168000 +vn 0.985600 0.018500 -0.168000 +vn 0.985200 0.018200 -0.170400 +vn 0.985100 0.023800 -0.170300 +vn 0.986400 0.025000 -0.162700 +vn 0.986500 0.019200 -0.162700 +vn 0.986000 0.018800 -0.165400 +vn 0.985900 0.024600 -0.165400 +vn 0.986500 0.013900 -0.163200 +vn 0.986600 0.008200 -0.163200 +vn 0.986100 0.008100 -0.166000 +vn 0.986000 0.013700 -0.166000 +vn 0.992000 0.003300 -0.126200 +vn 0.993200 0.003400 -0.116500 +vn 0.992600 0.003300 -0.121500 +vn 0.993200 -0.003300 -0.116500 +vn 0.993200 -0.009900 -0.116400 +vn 0.992600 -0.009900 -0.121400 +vn 0.992600 -0.003300 -0.121500 +vn 0.991700 0.029100 -0.125400 +vn 0.991800 0.022400 -0.125500 +vn 0.991300 0.022100 -0.130000 +vn 0.991100 0.028700 -0.130000 +vn 0.992800 0.029900 -0.115800 +vn 0.993000 0.023000 -0.115800 +vn 0.992400 0.022700 -0.120700 +vn 0.992200 0.029500 -0.120700 +vn 0.993100 0.016700 -0.116300 +vn 0.993200 0.009900 -0.116400 +vn 0.992600 0.009800 -0.121300 +vn 0.992500 0.016500 -0.121300 +vn 0.989400 0.027500 -0.142500 +vn 0.989600 0.021100 -0.142500 +vn 0.989000 0.020800 -0.146400 +vn 0.988900 0.027000 -0.146300 +vn 0.990500 0.028300 -0.134300 +vn 0.990700 0.021700 -0.134400 +vn 0.990100 0.021400 -0.138500 +vn 0.990000 0.027900 -0.138500 +vn 0.990700 0.015800 -0.134900 +vn 0.990800 0.009400 -0.134900 +vn 0.990200 0.009200 -0.139100 +vn 0.990200 0.015600 -0.139100 +vn 0.991400 -0.041100 -0.124000 +vn 0.991200 -0.047200 -0.123300 +vn 0.990600 -0.047200 -0.128500 +vn 0.990800 -0.041100 -0.129100 +vn 0.992500 -0.042300 -0.114300 +vn 0.992300 -0.048600 -0.113700 +vn 0.991700 -0.048500 -0.119200 +vn 0.991900 -0.042300 -0.119800 +vn 0.992100 -0.054700 -0.113000 +vn 0.991800 -0.060700 -0.112200 +vn 0.991200 -0.060700 -0.117800 +vn 0.991400 -0.054700 -0.118600 +vn 0.991900 -0.016000 -0.125800 +vn 0.991800 -0.022400 -0.125500 +vn 0.991200 -0.022400 -0.130300 +vn 0.991300 -0.016000 -0.130500 +vn 0.993100 -0.016500 -0.116100 +vn 0.993000 -0.023000 -0.115800 +vn 0.992400 -0.023000 -0.121000 +vn 0.992500 -0.016500 -0.121300 +vn 0.992900 -0.029500 -0.115400 +vn 0.992700 -0.036000 -0.114900 +vn 0.992100 -0.035900 -0.120300 +vn 0.992200 -0.029500 -0.120700 +vn 0.989600 -0.015100 -0.142900 +vn 0.989600 -0.021100 -0.142500 +vn 0.989000 -0.021100 -0.146700 +vn 0.989000 -0.015100 -0.146900 +vn 0.990800 -0.015600 -0.134700 +vn 0.990700 -0.021700 -0.134400 +vn 0.990100 -0.021700 -0.138800 +vn 0.990200 -0.015600 -0.139100 +vn 0.990600 -0.027900 -0.134000 +vn 0.990500 -0.034000 -0.133500 +vn 0.989800 -0.033900 -0.138100 +vn 0.990000 -0.027900 -0.138500 +vn 0.989200 -0.038800 -0.141100 +vn 0.989100 -0.044600 -0.140400 +vn 0.988500 -0.044600 -0.144800 +vn 0.988600 -0.038800 -0.145400 +vn 0.990300 -0.040000 -0.132900 +vn 0.990200 -0.045900 -0.132200 +vn 0.989500 -0.045900 -0.137000 +vn 0.989700 -0.040000 -0.137600 +vn 0.990000 -0.051800 -0.131500 +vn 0.989800 -0.057500 -0.130700 +vn 0.989100 -0.057500 -0.135600 +vn 0.989300 -0.051700 -0.136400 +vn 0.989700 0.003100 -0.143300 +vn 0.989100 0.003000 -0.147100 +vn 0.990800 0.003200 -0.135100 +vn 0.990200 0.003100 -0.139300 +vn 0.990800 -0.003100 -0.135100 +vn 0.990800 -0.009400 -0.134900 +vn 0.990200 -0.009300 -0.139200 +vn 0.990200 -0.003100 -0.139300 +vn 0.985300 0.002700 -0.171100 +vn 0.986600 0.002800 -0.163400 +vn 0.986600 -0.002700 -0.163400 +vn 0.986600 -0.008200 -0.163200 +vn 0.986100 -0.008200 -0.166100 +vn 0.997300 -0.047700 0.055100 +vn 0.997000 -0.055100 0.055100 +vn 0.997300 -0.055500 0.048100 +vn 0.997700 -0.048200 0.048200 +vn 0.996600 -0.046700 0.068400 +vn 0.996200 -0.054000 0.068400 +vn 0.996600 -0.054600 0.061800 +vn 0.997000 -0.047200 0.061800 +vn 0.995900 -0.060100 0.067200 +vn 0.995500 -0.067200 0.067200 +vn 0.995900 -0.067800 0.060700 +vn 0.996300 -0.060700 0.060700 +vn 0.998700 0.003800 0.050000 +vn 0.998000 0.003700 0.063800 +vn 0.997500 -0.011200 0.070400 +vn 0.997900 -0.011300 0.063800 +vn 0.998000 -0.003700 0.063800 +vn 0.999900 -0.012200 0.012200 +vn 0.999900 -0.012200 0.004100 +vn 0.989600 -0.136400 0.045300 +vn 0.989000 -0.141000 0.045200 +vn 0.989100 -0.141600 0.039400 +vn 0.989800 -0.137100 0.039400 +vn 0.989200 -0.134800 0.056700 +vn 0.988600 -0.139600 0.056700 +vn 0.988800 -0.140300 0.051000 +vn 0.989400 -0.135700 0.051000 +vn 0.988200 -0.142600 0.055100 +vn 0.987600 -0.147000 0.055000 +vn 0.987800 -0.147800 0.049500 +vn 0.988400 -0.143500 0.049500 +vn 0.993900 -0.097900 0.050500 +vn 0.993300 -0.103900 0.050400 +vn 0.993600 -0.104500 0.044000 +vn 0.994200 -0.098500 0.044000 +vn 0.993300 -0.096400 0.063100 +vn 0.992700 -0.102600 0.063000 +vn 0.993000 -0.103300 0.056800 +vn 0.993600 -0.097200 0.056800 +vn 0.992300 -0.107100 0.061500 +vn 0.991700 -0.112900 0.061500 +vn 0.992000 -0.113700 0.055400 +vn 0.992600 -0.107900 0.055400 +vn 0.994900 -0.100700 -0.003500 +vn 0.994900 -0.100500 0.010300 +vn 0.994300 -0.106100 0.010300 +vn 0.994900 -0.100600 0.003400 +vn 0.993700 -0.111300 0.010100 +vn 0.993100 -0.116500 0.010000 +vn 0.993200 -0.116500 0.003400 +vn 0.985400 -0.117700 0.122900 +vn 0.984800 -0.122800 0.122800 +vn 0.985100 -0.124300 0.119100 +vn 0.985700 -0.119100 0.119100 +vn 0.984900 -0.114600 0.130000 +vn 0.984300 -0.119800 0.129900 +vn 0.984500 -0.121300 0.126400 +vn 0.985100 -0.116100 0.126500 +vn 0.984400 -0.121800 0.126800 +vn 0.983800 -0.126700 0.126700 +vn 0.984000 -0.128300 0.123300 +vn 0.984700 -0.123400 0.123400 +vn 0.987600 -0.082300 0.133700 +vn 0.987100 -0.088400 0.133700 +vn 0.987500 -0.089500 0.129700 +vn 0.988000 -0.083400 0.129800 +vn 0.986800 -0.080000 0.141100 +vn 0.986300 -0.086000 0.141000 +vn 0.986700 -0.087200 0.137400 +vn 0.987200 -0.081200 0.137500 +vn 0.986300 -0.089500 0.138600 +vn 0.985800 -0.095300 0.138500 +vn 0.986100 -0.096600 0.135000 +vn 0.986700 -0.090700 0.135000 +vn 0.991100 -0.091000 0.097300 +vn 0.990500 -0.097300 0.097300 +vn 0.990900 -0.098300 0.092000 +vn 0.991500 -0.092000 0.092000 +vn 0.990200 -0.089000 0.107500 +vn 0.989600 -0.095200 0.107400 +vn 0.990100 -0.096200 0.102400 +vn 0.990700 -0.090000 0.102500 +vn 0.989500 -0.099200 0.105300 +vn 0.988900 -0.105200 0.105200 +vn 0.989300 -0.106300 0.100300 +vn 0.989900 -0.100300 0.100300 +vn 0.996600 0.061800 0.054600 +vn 0.997000 0.055100 0.055100 +vn 0.997300 0.055100 0.047700 +vn 0.997000 0.061800 0.047200 +vn 0.995900 0.060700 0.067800 +vn 0.996200 0.054000 0.068400 +vn 0.996700 0.054000 0.061300 +vn 0.996300 0.060700 0.060700 +vn 0.996500 0.047200 0.068900 +vn 0.996800 0.040200 0.069300 +vn 0.997200 0.040200 0.062300 +vn 0.997000 0.047200 0.061800 +vn 0.992800 0.109200 0.049800 +vn 0.993300 0.103900 0.050400 +vn 0.993600 0.104000 0.043400 +vn 0.993100 0.109200 0.042900 +vn 0.992200 0.107800 0.062300 +vn 0.992700 0.102600 0.063000 +vn 0.993100 0.102600 0.056100 +vn 0.992600 0.107900 0.055400 +vn 0.993200 0.097100 0.063800 +vn 0.993700 0.091500 0.064500 +vn 0.994100 0.091500 0.057500 +vn 0.993600 0.097200 0.056800 +vn 0.993700 0.111400 0.010200 +vn 0.994300 0.106100 0.010300 +vn 0.994900 0.100600 0.010500 +vn 0.995400 0.094900 0.010600 +vn 0.995500 0.094900 0.003500 +vn 0.994900 0.100600 0.003400 +vn 0.988800 0.051000 0.140300 +vn 0.989000 0.045200 0.141000 +vn 0.989600 0.045300 0.136400 +vn 0.989400 0.051000 0.135700 +vn 0.987800 0.049500 0.147800 +vn 0.987900 0.043900 0.148500 +vn 0.988600 0.043900 0.144200 +vn 0.988400 0.049500 0.143500 +vn 0.988100 0.038200 0.149000 +vn 0.988200 0.032400 0.149500 +vn 0.988800 0.032500 0.145400 +vn 0.988700 0.038200 0.144900 +vn 0.986800 0.093200 0.132500 +vn 0.987100 0.088400 0.133700 +vn 0.987700 0.088400 0.128600 +vn 0.987500 0.093300 0.127400 +vn 0.986000 0.090700 0.139800 +vn 0.986300 0.086000 0.141000 +vn 0.986900 0.086000 0.136300 +vn 0.986700 0.090700 0.135000 +vn 0.986500 0.081100 0.142200 +vn 0.986700 0.076100 0.143300 +vn 0.987400 0.076200 0.138700 +vn 0.987200 0.081200 0.137500 +vn 0.990100 0.102400 0.096200 +vn 0.990500 0.097300 0.097300 +vn 0.991100 0.097300 0.091000 +vn 0.990700 0.102500 0.090000 +vn 0.989300 0.100300 0.106300 +vn 0.989600 0.095200 0.107400 +vn 0.990300 0.095200 0.101400 +vn 0.989900 0.100300 0.100300 +vn 0.990000 0.089900 0.108400 +vn 0.990400 0.084500 0.109400 +vn 0.991000 0.084600 0.103500 +vn 0.990700 0.090000 0.102500 +vn 0.989200 -0.038800 0.141000 +vn 0.989000 -0.045200 0.141000 +vn 0.989500 -0.045900 0.137000 +vn 0.989800 -0.039400 0.137100 +vn 0.988200 -0.037600 0.148500 +vn 0.987900 -0.043900 0.148500 +vn 0.988500 -0.044600 0.144800 +vn 0.988700 -0.038200 0.144900 +vn 0.987900 -0.048800 0.147100 +vn 0.987600 -0.055000 0.147000 +vn 0.988100 -0.055900 0.143400 +vn 0.988400 -0.049500 0.143500 +vn 0.989700 0.003100 0.143300 +vn 0.990300 0.003100 0.139200 +vn 0.988600 0.003000 0.150700 +vn 0.989100 0.003000 0.147000 +vn 0.988600 -0.002900 0.150700 +vn 0.988500 -0.008900 0.150700 +vn 0.989100 -0.009100 0.147000 +vn 0.989100 -0.003000 0.147000 +vn 0.994900 0.003400 0.100600 +vn 0.993200 0.003400 0.116500 +vn 0.993200 -0.003300 0.116500 +vn 0.993100 -0.010000 0.116500 +vn 0.993700 -0.010200 0.111400 +vn 0.988800 0.051000 -0.140300 +vn 0.989100 0.044600 -0.140400 +vn 0.988600 0.043900 -0.144200 +vn 0.988300 0.050300 -0.144200 +vn 0.989800 0.052500 -0.132200 +vn 0.990200 0.045900 -0.132200 +vn 0.989600 0.045300 -0.136400 +vn 0.989300 0.051700 -0.136400 +vn 0.990200 0.040500 -0.133400 +vn 0.990500 0.034000 -0.133500 +vn 0.989900 0.033500 -0.137600 +vn 0.989700 0.040000 -0.137600 +vn 0.986800 0.093200 -0.132500 +vn 0.987300 0.087200 -0.132500 +vn 0.986900 0.086000 -0.136300 +vn 0.986400 0.091900 -0.136200 +vn 0.987600 0.095600 -0.124400 +vn 0.988200 0.089600 -0.124500 +vn 0.987700 0.088400 -0.128600 +vn 0.987200 0.094400 -0.128500 +vn 0.988200 0.085600 -0.126700 +vn 0.988700 0.079400 -0.126800 +vn 0.988300 0.078300 -0.130900 +vn 0.987800 0.084500 -0.130900 +vn 0.984000 0.082900 -0.157600 +vn 0.984500 0.077300 -0.157700 +vn 0.984200 0.076000 -0.160100 +vn 0.983700 0.081500 -0.160000 +vn 0.984600 0.085500 -0.152400 +vn 0.985100 0.079800 -0.152500 +vn 0.984800 0.078600 -0.155200 +vn 0.984300 0.084200 -0.155100 +vn 0.985000 0.076400 -0.154800 +vn 0.985400 0.070600 -0.154900 +vn 0.985100 0.069500 -0.157600 +vn 0.984600 0.075200 -0.157600 +vn 0.996600 0.061800 -0.054600 +vn 0.997000 0.054600 -0.054600 +vn 0.996700 0.054000 -0.061300 +vn 0.996200 0.061300 -0.061300 +vn 0.997200 0.062700 -0.040700 +vn 0.997600 0.055500 -0.040700 +vn 0.997300 0.055100 -0.047700 +vn 0.996900 0.062300 -0.047700 +vn 0.997900 0.049000 -0.041500 +vn 0.998300 0.041500 -0.041500 +vn 0.998000 0.041100 -0.048600 +vn 0.997600 0.048600 -0.048600 +vn 0.992800 0.109200 -0.049800 +vn 0.993400 0.103300 -0.049800 +vn 0.993100 0.102600 -0.056100 +vn 0.992500 0.108600 -0.056100 +vn 0.993200 0.110300 -0.036900 +vn 0.993800 0.104500 -0.036900 +vn 0.993600 0.104000 -0.043400 +vn 0.993000 0.109800 -0.043400 +vn 0.994300 0.099500 -0.037900 +vn 0.994900 0.093400 -0.037900 +vn 0.994700 0.092800 -0.044600 +vn 0.994100 0.099000 -0.044500 +vn 0.990100 0.102400 -0.096200 +vn 0.990700 0.096300 -0.096300 +vn 0.990300 0.095200 -0.101400 +vn 0.989700 0.101400 -0.101400 +vn 0.990900 0.104400 -0.085500 +vn 0.991500 0.098300 -0.085600 +vn 0.991100 0.097300 -0.091000 +vn 0.990500 0.103400 -0.091000 +vn 0.991700 0.093800 -0.087400 +vn 0.992300 0.087500 -0.087500 +vn 0.991900 0.086500 -0.093000 +vn 0.991300 0.092900 -0.092900 +vn 0.985400 -0.117700 -0.122900 +vn 0.985200 -0.121400 -0.121400 +vn 0.984500 -0.121300 -0.126400 +vn 0.984800 -0.117600 -0.128000 +vn 0.986000 -0.120600 -0.115200 +vn 0.985700 -0.124400 -0.113800 +vn 0.985100 -0.124300 -0.119100 +vn 0.985400 -0.120500 -0.120500 +vn 0.985400 -0.128000 -0.112300 +vn 0.985100 -0.131500 -0.110800 +vn 0.984500 -0.131400 -0.116100 +vn 0.984800 -0.128000 -0.117600 +vn 0.987700 -0.128600 -0.088400 +vn 0.987300 -0.132500 -0.087200 +vn 0.986800 -0.132500 -0.093200 +vn 0.987200 -0.128500 -0.094400 +vn 0.988300 -0.130900 -0.078300 +vn 0.987800 -0.134900 -0.077300 +vn 0.987400 -0.134800 -0.083400 +vn 0.987800 -0.130900 -0.084500 +vn 0.987400 -0.138700 -0.076200 +vn 0.987000 -0.142300 -0.075100 +vn 0.986500 -0.142200 -0.081100 +vn 0.986900 -0.138600 -0.082300 +vn 0.983500 -0.104900 -0.147200 +vn 0.983400 -0.108300 -0.145500 +vn 0.982800 -0.108300 -0.149400 +vn 0.982900 -0.104900 -0.151100 +vn 0.983900 -0.108200 -0.142100 +vn 0.983800 -0.111700 -0.140500 +vn 0.983200 -0.111700 -0.144700 +vn 0.983300 -0.108100 -0.146300 +vn 0.983600 -0.115100 -0.138800 +vn 0.983500 -0.118300 -0.137000 +vn 0.982900 -0.118300 -0.141300 +vn 0.983000 -0.115000 -0.143000 +vn 0.993600 -0.043400 -0.104000 +vn 0.993400 -0.049800 -0.103300 +vn 0.992800 -0.049800 -0.109200 +vn 0.993000 -0.043400 -0.109800 +vn 0.994700 -0.044600 -0.092800 +vn 0.994400 -0.051100 -0.092200 +vn 0.993800 -0.051100 -0.098500 +vn 0.994100 -0.044500 -0.099000 +vn 0.994100 -0.057500 -0.091500 +vn 0.993800 -0.063800 -0.090800 +vn 0.993200 -0.063800 -0.097100 +vn 0.993500 -0.057500 -0.097800 +vn 0.993000 0.056800 -0.103300 +vn 0.993400 0.049800 -0.103300 +vn 0.992900 0.049200 -0.108600 +vn 0.992500 0.056100 -0.108600 +vn 0.994000 0.058200 -0.092200 +vn 0.994400 0.051100 -0.092200 +vn 0.993900 0.050500 -0.097900 +vn 0.993500 0.057500 -0.097800 +vn 0.994600 0.045100 -0.093400 +vn 0.994900 0.037900 -0.093400 +vn 0.994400 0.037400 -0.099100 +vn 0.994100 0.044500 -0.099000 +vn 0.985100 0.045000 -0.165800 +vn 0.985400 0.039200 -0.165800 +vn 0.985000 0.038600 -0.168200 +vn 0.984800 0.044300 -0.168200 +vn 0.985900 0.046500 -0.160500 +vn 0.986200 0.040600 -0.160500 +vn 0.985800 0.039900 -0.163300 +vn 0.985500 0.045800 -0.163200 +vn 0.986200 0.035900 -0.161800 +vn 0.986400 0.030000 -0.161800 +vn 0.985900 0.029500 -0.164500 +vn 0.985700 0.035300 -0.164500 +vn 0.993600 -0.043400 0.104000 +vn 0.993300 -0.050400 0.103900 +vn 0.993800 -0.051100 0.098500 +vn 0.994200 -0.044000 0.098500 +vn 0.992500 -0.042300 0.114300 +vn 0.992200 -0.049200 0.114300 +vn 0.992800 -0.049800 0.109200 +vn 0.993100 -0.042900 0.109200 +vn 0.992100 -0.054700 0.113000 +vn 0.991700 -0.061500 0.112900 +vn 0.992200 -0.062300 0.107800 +vn 0.992600 -0.055400 0.107900 +vn 0.993000 0.056800 0.103300 +vn 0.993300 0.050400 0.103900 +vn 0.993900 0.050500 0.097900 +vn 0.993600 0.056800 0.097200 +vn 0.992000 0.055400 0.113700 +vn 0.992200 0.049200 0.114300 +vn 0.992900 0.049200 0.108600 +vn 0.992600 0.055400 0.107900 +vn 0.992500 0.042800 0.114900 +vn 0.992700 0.036400 0.115400 +vn 0.993300 0.036400 0.109800 +vn 0.993100 0.042900 0.109200 +vn 0.998000 0.063800 -0.003800 +vn 0.997900 0.063800 0.011300 +vn 0.998300 0.057000 0.011400 +vn 0.998000 0.063800 0.003700 +vn 0.998700 0.050000 0.011600 +vn 0.999000 0.042800 0.011700 +vn 0.998700 0.050000 0.003800 +vn 0.995500 0.003500 -0.095000 +vn 0.994900 0.003500 -0.100700 +vn 0.995500 -0.003500 -0.094900 +vn 0.995400 -0.010500 -0.094800 +vn 0.994900 -0.010500 -0.100600 +vn 0.994900 -0.003500 -0.100700 +vn 0.987700 -0.128600 0.088400 +vn 0.987100 -0.133700 0.088400 +vn 0.987400 -0.134800 0.083400 +vn 0.988000 -0.129800 0.083400 +vn 0.987200 -0.126100 0.097900 +vn 0.986500 -0.131200 0.097900 +vn 0.986800 -0.132500 0.093200 +vn 0.987500 -0.127400 0.093300 +vn 0.986400 -0.133700 0.095300 +vn 0.985800 -0.138500 0.095300 +vn 0.986000 -0.139800 0.090700 +vn 0.986700 -0.135000 0.090700 +vn 0.989700 -0.143300 -0.003100 +vn 0.990200 -0.139300 -0.003100 +vn 0.990200 -0.139100 0.009200 +vn 0.989600 -0.143200 0.009200 +vn 0.989700 -0.143300 0.003100 +vn 0.990300 -0.139200 0.003100 +vn 0.989100 -0.146900 0.008900 +vn 0.988500 -0.150700 0.008900 +vn 0.988600 -0.150700 0.003000 +vn 0.989100 -0.147000 0.003000 +vn 0.998000 0.003800 -0.063800 +vn 0.998700 0.003900 -0.050000 +vn 0.999000 -0.011600 -0.042700 +vn 0.998700 -0.011600 -0.050000 +vn 0.998700 -0.003900 -0.050000 +vn 0.998700 -0.050000 -0.003900 +vn 0.998700 -0.049800 0.011400 +vn 0.998300 -0.057000 0.011400 +vn 0.998700 -0.050000 0.003800 +vn 0.997900 -0.063600 0.011200 +vn 0.997500 -0.070400 0.011200 +vn 0.998000 -0.063800 0.003700 +vn 0.985500 -0.034100 -0.166500 +vn 0.985400 -0.039200 -0.165800 +vn 0.984900 -0.039200 -0.168800 +vn 0.985000 -0.034100 -0.169400 +vn 0.986300 -0.035300 -0.161200 +vn 0.986200 -0.040600 -0.160500 +vn 0.985600 -0.040600 -0.163900 +vn 0.985700 -0.035300 -0.164500 +vn 0.986100 -0.045800 -0.159800 +vn 0.986000 -0.050900 -0.159000 +vn 0.985400 -0.050900 -0.162500 +vn 0.985500 -0.045800 -0.163200 +vn 0.991100 -0.091000 -0.097300 +vn 0.990700 -0.096300 -0.096300 +vn 0.990100 -0.096200 -0.102400 +vn 0.990500 -0.091000 -0.103400 +vn 0.991900 -0.093000 -0.086500 +vn 0.991500 -0.098300 -0.085600 +vn 0.990900 -0.098300 -0.092000 +vn 0.991300 -0.092900 -0.092900 +vn 0.991000 -0.103500 -0.084600 +vn 0.990600 -0.108500 -0.083600 +vn 0.990000 -0.108400 -0.089900 +vn 0.990500 -0.103400 -0.091000 +vn 0.993900 -0.097900 -0.050500 +vn 0.993400 -0.103300 -0.049800 +vn 0.993000 -0.103300 -0.056800 +vn 0.993500 -0.097800 -0.057500 +vn 0.994400 -0.099000 -0.037400 +vn 0.993800 -0.104500 -0.036900 +vn 0.993600 -0.104500 -0.044000 +vn 0.994100 -0.099000 -0.044500 +vn 0.993300 -0.109800 -0.036400 +vn 0.992700 -0.114900 -0.036000 +vn 0.992500 -0.114900 -0.042800 +vn 0.993000 -0.109800 -0.043400 +vn 0.989600 -0.136400 -0.045300 +vn 0.989100 -0.140400 -0.044600 +vn 0.988800 -0.140300 -0.051000 +vn 0.989300 -0.136400 -0.051700 +vn 0.989900 -0.137600 -0.033500 +vn 0.989400 -0.141600 -0.033000 +vn 0.989100 -0.141600 -0.039400 +vn 0.989700 -0.137600 -0.040000 +vn 0.988800 -0.145400 -0.032500 +vn 0.988300 -0.149100 -0.032000 +vn 0.988100 -0.149000 -0.038200 +vn 0.988600 -0.145400 -0.038800 +vn 0.997300 -0.047700 -0.055100 +vn 0.997000 -0.054600 -0.054600 +vn 0.996600 -0.054600 -0.061800 +vn 0.996900 -0.047700 -0.062300 +vn 0.998000 -0.048600 -0.041100 +vn 0.997600 -0.055500 -0.040700 +vn 0.997300 -0.055500 -0.048100 +vn 0.997600 -0.048600 -0.048600 +vn 0.997200 -0.062300 -0.040200 +vn 0.996800 -0.068900 -0.039800 +vn 0.996500 -0.068900 -0.047200 +vn 0.996900 -0.062300 -0.047700 +vn 0.984600 -0.072900 -0.159000 +vn 0.984500 -0.077300 -0.157700 +vn 0.983900 -0.077200 -0.161300 +vn 0.984000 -0.072800 -0.162500 +vn 0.985200 -0.075300 -0.153700 +vn 0.985100 -0.079800 -0.152500 +vn 0.984500 -0.079800 -0.156400 +vn 0.984600 -0.075200 -0.157600 +vn 0.984900 -0.084300 -0.151100 +vn 0.984700 -0.088600 -0.149800 +vn 0.984100 -0.088500 -0.153800 +vn 0.984300 -0.084200 -0.155100 +vn 0.987600 -0.082300 -0.133700 +vn 0.987300 -0.087200 -0.132500 +vn 0.986700 -0.087200 -0.137400 +vn 0.986900 -0.082300 -0.138600 +vn 0.988500 -0.084600 -0.125700 +vn 0.988200 -0.089600 -0.124500 +vn 0.987500 -0.089500 -0.129700 +vn 0.987800 -0.084500 -0.130900 +vn 0.987900 -0.094500 -0.123300 +vn 0.987600 -0.099200 -0.122000 +vn 0.986900 -0.099200 -0.127300 +vn 0.987200 -0.094400 -0.128500 +s off +f 6/1/1 8/1/1 10/1/1 +f 18/1/2 15/1/2 13/1/2 +f 17/1/3 7/1/3 5/1/3 +f 12/1/4 2/1/4 9/1/4 +f 1/1/5 2/1/5 3/1/5 +f 4/1/6 5/1/6 6/1/6 +f 11/1/7 12/1/7 13/1/7 +f 14/1/8 15/1/8 16/1/8 +f 12/1/9 11/1/9 3/1/9 +f 15/1/10 14/1/10 11/1/10 +f 5/1/11 4/1/11 14/1/11 +f 1/1/12 3/1/12 4/1/12 +f 18/1/13 17/1/13 16/1/13 +f 6/1/14 5/1/14 7/1/14 +f 13/1/15 12/1/15 20/1/15 +f 10/1/16 9/1/16 2/1/16 +f 14/1/17 4/1/17 3/1/17 +f 2771/1/18 1370/1/18 3316/1/18 +f 912/1/19 2725/1/19 3411/1/19 +f 899/1/20 3234/1/20 3402/1/20 +f 1226/1/21 3279/1/21 3391/1/21 +f 2410/1/22 794/1/22 3211/1/22 +f 1344/1/23 3311/1/23 3423/1/23 +f 1213/1/24 2614/1/24 3382/1/24 +f 2732/1/25 3414/1/25 3302/1/25 +f 834/1/26 2647/1/26 3397/1/26 +f 925/1/27 2470/1/27 3364/1/27 +f 2634/1/28 3394/1/28 3226/1/28 +f 1371/1/29 2405/1/29 3334/1/29 +f 2457/1/30 912/1/30 3243/1/30 +f 2444/1/31 3346/1/31 3234/1/31 +f 2470/1/32 1227/1/32 3280/1/32 +f 795/1/33 3212/1/33 3380/1/33 +f 1214/1/34 2457/1/34 3355/1/34 +f 1201/1/35 3262/1/35 3346/1/35 +f 1332/1/36 2410/1/36 3337/1/36 +f 2409/1/37 834/1/37 3229/1/37 +f 926/1/38 3253/1/38 3421/1/38 +f 821/1/39 3226/1/39 3334/1/39 +f 2772/1/40 1371/1/40 3317/1/40 +f 913/1/41 3244/1/41 3412/1/41 +f 2713/1/42 900/1/42 3235/1/42 +f 1227/1/43 2628/1/43 3392/1/43 +f 2383/1/44 3320/1/44 3212/1/44 +f 2615/1/45 1214/1/45 3271/1/45 +f 848/1/46 2661/1/46 3400/1/46 +f 2602/1/47 3374/1/47 3262/1/47 +f 2733/1/48 1332/1/48 3303/1/48 +f 2471/1/49 3365/1/49 3253/1/49 +f 2635/1/50 3395/1/50 3227/1/50 +f 809/1/51 3218/1/51 3386/1/51 +f 2458/1/52 3356/1/52 3244/1/52 +f 2406/1/53 3335/1/53 3314/1/53 +f 1228/1/54 3281/1/54 3365/1/54 +f 900/1/55 2445/1/55 3347/1/55 +f 2429/1/56 848/1/56 3232/1/56 +f 1215/1/57 3272/1/57 3356/1/57 +f 1333/1/58 3304/1/58 3338/1/58 +f 2445/1/59 1202/1/59 3263/1/59 +f 822/1/60 3227/1/60 3335/1/60 +f 2394/1/61 3326/1/61 3218/1/61 +f 2727/1/62 3413/1/62 3245/1/62 +f 1359/1/63 3314/1/63 3426/1/63 +f 2714/1/64 3404/1/64 3236/1/64 +f 2629/1/65 3393/1/65 3281/1/65 +f 849/1/66 2662/1/66 3401/1/66 +f 2616/1/67 3384/1/67 3272/1/67 +f 2734/1/68 3416/1/68 3304/1/68 +f 1202/1/69 2603/1/69 3375/1/69 +f 810/1/70 2623/1/70 3387/1/70 +f 914/1/71 3245/1/71 3357/1/71 +f 2395/1/72 3327/1/72 3315/1/72 +f 901/1/73 3236/1/73 3348/1/73 +f 2430/1/74 849/1/74 3233/1/74 +f 2459/1/75 3357/1/75 3273/1/75 +f 2398/1/76 1334/1/76 3305/1/76 +f 2446/1/77 3348/1/77 3264/1/77 +f 2395/1/78 810/1/78 3219/1/78 +f 1360/1/79 3315/1/79 3427/1/79 +f 2715/1/80 902/1/80 3237/1/80 +f 1216/1/81 3273/1/81 3385/1/81 +f 1334/1/82 2735/1/82 3417/1/82 +f 2650/1/83 3398/1/83 3230/1/83 +f 1203/1/84 3264/1/84 3376/1/84 +f 811/1/85 3220/1/85 3388/1/85 +f 902/1/86 2447/1/86 3349/1/86 +f 2412/1/87 1335/1/87 3306/1/87 +f 837/1/88 3230/1/88 3342/1/88 +f 2447/1/89 1204/1/89 3265/1/89 +f 2400/1/90 1322/1/90 3297/1/90 +f 2396/1/91 3328/1/91 3220/1/91 +f 903/1/92 3238/1/92 3406/1/92 +f 1335/1/93 2736/1/93 3418/1/93 +f 2651/1/94 3399/1/94 3231/1/94 +f 1204/1/95 2605/1/95 3377/1/95 +f 1322/1/96 2723/1/96 3409/1/96 +f 2625/1/97 812/1/97 3221/1/97 +f 2448/1/98 3350/1/98 3238/1/98 +f 2413/1/99 3340/1/99 3307/1/99 +f 838/1/100 3231/1/100 3343/1/100 +f 1205/1/101 3266/1/101 3350/1/101 +f 943/1/102 2756/1/102 3424/1/102 +f 2397/1/103 1323/1/103 3298/1/103 +f 812/1/104 2397/1/104 3329/1/104 +f 904/1/105 2717/1/105 3407/1/105 +f 1336/1/106 3307/1/106 3419/1/106 +f 2606/1/107 3378/1/107 3266/1/107 +f 2488/1/108 943/1/108 3256/1/108 +f 1323/1/109 2724/1/109 3410/1/109 +f 2626/1/110 813/1/110 3222/1/110 +f 1245/1/111 2488/1/111 3368/1/111 +f 2449/1/112 904/1/112 3239/1/112 +f 2613/1/113 800/1/113 3213/1/113 +f 2414/1/114 1337/1/114 3308/1/114 +f 1206/1/115 2449/1/115 3351/1/115 +f 944/1/116 2757/1/116 3425/1/116 +f 2744/1/117 3422/1/117 3254/1/117 +f 2392/1/118 3325/1/118 3299/1/118 +f 2646/1/119 1245/1/119 3284/1/119 +f 1311/1/120 3290/1/120 3333/1/120 +f 813/1/121 2398/1/121 3330/1/121 +f 905/1/122 3240/1/122 3408/1/122 +f 800/1/123 2388/1/123 3321/1/123 +f 1337/1/124 2738/1/124 3420/1/124 +f 2607/1/125 1206/1/125 3267/1/125 +f 2489/1/126 944/1/126 3257/1/126 +f 931/1/127 3254/1/127 3366/1/127 +f 2725/1/128 1324/1/128 3299/1/128 +f 1246/1/129 2489/1/129 3369/1/129 +f 2712/1/130 3402/1/130 3290/1/130 +f 2627/1/131 3391/1/131 3223/1/131 +f 2450/1/132 3352/1/132 3240/1/132 +f 2476/1/133 3366/1/133 3282/1/133 +f 2614/1/134 801/1/134 3214/1/134 +f 958/1/135 2771/1/135 3428/1/135 +f 1338/1/136 3309/1/136 3326/1/136 +f 1207/1/137 3268/1/137 3352/1/137 +f 2745/1/138 3423/1/138 3255/1/138 +f 2388/1/139 1325/1/139 3300/1/139 +f 919/1/140 3246/1/140 3414/1/140 +f 2647/1/141 1246/1/141 3285/1/141 +f 2382/1/142 1312/1/142 3291/1/142 +f 814/1/143 3223/1/143 3331/1/143 +f 1233/1/144 3282/1/144 3394/1/144 +f 801/1/145 2389/1/145 3322/1/145 +f 2503/1/146 958/1/146 3260/1/146 +f 2739/1/147 3421/1/147 3309/1/147 +f 2608/1/148 3380/1/148 3268/1/148 +f 932/1/149 3255/1/149 3367/1/149 +f 1260/1/150 2503/1/150 3372/1/150 +f 2726/1/151 3412/1/151 3300/1/151 +f 2464/1/152 3358/1/152 3246/1/152 +f 1312/1/153 2713/1/153 3403/1/153 +f 2628/1/154 815/1/154 3224/1/154 +f 2477/1/155 3367/1/155 3283/1/155 +f 802/1/156 2615/1/156 3383/1/156 +f 1221/1/157 3274/1/157 3358/1/157 +f 959/1/158 2772/1/158 3429/1/158 +f 789/1/159 3206/1/159 3374/1/159 +f 2661/1/160 1260/1/160 3288/1/160 +f 2399/1/161 3331/1/161 3301/1/161 +f 920/1/162 2733/1/162 3415/1/162 +f 2381/1/163 3318/1/163 3292/1/163 +f 815/1/164 2400/1/164 3332/1/164 +f 1234/1/165 3283/1/165 3395/1/165 +f 2390/1/166 802/1/166 3215/1/166 +f 2622/1/167 3386/1/167 3274/1/167 +f 2504/1/168 959/1/168 3261/1/168 +f 2382/1/169 3319/1/169 3206/1/169 +f 1261/1/170 2504/1/170 3373/1/170 +f 1326/1/171 3301/1/171 3413/1/171 +f 1313/1/172 3292/1/172 3404/1/172 +f 816/1/173 3225/1/173 3393/1/173 +f 2465/1/174 920/1/174 3247/1/174 +f 803/1/175 3216/1/175 3384/1/175 +f 2603/1/176 790/1/176 3207/1/176 +f 1222/1/177 2465/1/177 3359/1/177 +f 2760/1/178 3426/1/178 3258/1/178 +f 2662/1/179 1261/1/179 3289/1/179 +f 2381/1/180 1314/1/180 3293/1/180 +f 2401/1/181 3333/1/181 3225/1/181 +f 921/1/182 3248/1/182 3416/1/182 +f 2391/1/183 3324/1/183 3216/1/183 +f 790/1/184 2414/1/184 3341/1/184 +f 2623/1/185 1222/1/185 3275/1/185 +f 947/1/186 3258/1/186 3370/1/186 +f 1314/1/187 2715/1/187 3405/1/187 +f 2466/1/188 3360/1/188 3248/1/188 +f 2492/1/189 3370/1/189 3286/1/189 +f 2617/1/190 3385/1/190 3217/1/190 +f 2604/1/191 3376/1/191 3208/1/191 +f 1223/1/192 3276/1/192 3360/1/192 +f 2761/1/193 3427/1/193 3259/1/193 +f 1315/1/194 3294/1/194 3324/1/194 +f 2735/1/195 922/1/195 3249/1/195 +f 1249/1/196 3286/1/196 3398/1/196 +f 804/1/197 3217/1/197 3325/1/197 +f 791/1/198 3208/1/198 3340/1/198 +f 2624/1/199 3388/1/199 3276/1/199 +f 948/1/200 3259/1/200 3371/1/200 +f 922/1/201 2467/1/201 3361/1/201 +f 2493/1/202 3371/1/202 3287/1/202 +f 2716/1/203 3406/1/203 3294/1/203 +f 1355/1/204 2429/1/204 3344/1/204 +f 2605/1/205 792/1/205 3209/1/205 +f 2467/1/206 1224/1/206 3277/1/206 +f 2736/1/207 923/1/207 3250/1/207 +f 1250/1/208 3287/1/208 3399/1/208 +f 1316/1/209 2390/1/209 3323/1/209 +f 2723/1/210 910/1/210 3241/1/210 +f 2756/1/211 1355/1/211 3312/1/211 +f 792/1/212 2412/1/212 3339/1/212 +f 1224/1/213 2625/1/213 3389/1/213 +f 923/1/214 2468/1/214 3362/1/214 +f 2717/1/215 1316/1/215 3295/1/215 +f 910/1/216 2455/1/216 3353/1/216 +f 1356/1/217 2430/1/217 3345/1/217 +f 793/1/218 3210/1/218 3378/1/218 +f 2468/1/219 1225/1/219 3278/1/219 +f 2418/1/220 3342/1/220 3310/1/220 +f 2455/1/221 1212/1/221 3269/1/221 +f 2737/1/222 3419/1/222 3251/1/222 +f 1317/1/223 3296/1/223 3322/1/223 +f 2724/1/224 911/1/224 3242/1/224 +f 2757/1/225 1356/1/225 3313/1/225 +f 1225/1/226 2626/1/226 3390/1/226 +f 2411/1/227 3338/1/227 3210/1/227 +f 1343/1/228 3310/1/228 3422/1/228 +f 1212/1/229 2613/1/229 3381/1/229 +f 833/1/230 2646/1/230 3396/1/230 +f 924/1/231 3251/1/231 3363/1/231 +f 2718/1/232 3408/1/232 3296/1/232 +f 1370/1/233 2409/1/233 3336/1/233 +f 911/1/234 2456/1/234 3354/1/234 +f 2469/1/235 3363/1/235 3279/1/235 +f 794/1/236 2607/1/236 3379/1/236 +f 2419/1/237 3343/1/237 3311/1/237 +f 2456/1/238 1213/1/238 3270/1/238 +f 1331/1/239 3302/1/239 3320/1/239 +f 2396/1/240 833/1/240 3228/1/240 +f 2738/1/241 925/1/241 3252/1/241 +f 3216/1/242 3440/1/242 3608/1/242 +f 3393/1/243 3617/1/243 3505/1/243 +f 3380/1/244 3604/1/244 3492/1/244 +f 3255/1/245 3479/1/245 3591/1/245 +f 3341/1/246 3308/1/246 3532/1/246 +f 3242/1/247 3354/1/247 3578/1/247 +f 3336/1/248 3229/1/248 3453/1/248 +f 3295/1/249 3323/1/249 3547/1/249 +f 3324/1/250 3548/1/250 3440/1/250 +f 3366/1/251 3590/1/251 3506/1/251 +f 3353/1/252 3269/1/252 3493/1/252 +f 3256/1/253 3424/1/253 3648/1/253 +f 3308/1/254 3420/1/254 3644/1/254 +f 3243/1/255 3411/1/255 3635/1/255 +f 3398/1/256 3622/1/256 3454/1/256 +f 3407/1/257 3295/1/257 3519/1/257 +f 3385/1/258 3609/1/258 3441/1/258 +f 3282/1/259 3506/1/259 3618/1/259 +f 3269/1/260 3381/1/260 3605/1/260 +f 3368/1/261 3256/1/261 3480/1/261 +f 3309/1/262 3533/1/262 3550/1/262 +f 3355/1/263 3243/1/263 3467/1/263 +f 3230/1/264 3454/1/264 3566/1/264 +f 3296/1/265 3520/1/265 3546/1/265 +f 3217/1/266 3441/1/266 3549/1/266 +f 3367/1/267 3591/1/267 3507/1/267 +f 3354/1/268 3270/1/268 3494/1/268 +f 3257/1/269 3425/1/269 3649/1/269 +f 3421/1/270 3645/1/270 3533/1/270 +f 3244/1/271 3468/1/271 3636/1/271 +f 3399/1/272 3623/1/272 3455/1/272 +f 3408/1/273 3632/1/273 3520/1/273 +f 3218/1/274 3442/1/274 3610/1/274 +f 3283/1/275 3507/1/275 3619/1/275 +f 3270/1/276 3382/1/276 3606/1/276 +f 3369/1/277 3257/1/277 3481/1/277 +f 3342/1/278 3566/1/278 3534/1/278 +f 3356/1/279 3580/1/279 3468/1/279 +f 3231/1/280 3455/1/280 3567/1/280 +f 3332/1/281 3297/1/281 3521/1/281 +f 3326/1/282 3550/1/282 3442/1/282 +f 3284/1/283 3368/1/283 3592/1/283 +f 3271/1/284 3355/1/284 3579/1/284 +f 3426/1/285 3650/1/285 3482/1/285 +f 3310/1/286 3534/1/286 3646/1/286 +f 3413/1/287 3637/1/287 3469/1/287 +f 3232/1/288 3400/1/288 3624/1/288 +f 3297/1/289 3409/1/289 3633/1/289 +f 3219/1/290 3387/1/290 3611/1/290 +f 3396/1/291 3284/1/291 3508/1/291 +f 3206/1/292 3430/1/292 3598/1/292 +f 3383/1/293 3271/1/293 3495/1/293 +f 3258/1/294 3482/1/294 3594/1/294 +f 3343/1/295 3567/1/295 3535/1/295 +f 3245/1/296 3469/1/296 3581/1/296 +f 3344/1/297 3232/1/297 3456/1/297 +f 3329/1/298 3298/1/298 3522/1/298 +f 3327/1/299 3219/1/299 3443/1/299 +f 3285/1/300 3369/1/300 3593/1/300 +f 3319/1/301 3543/1/301 3430/1/301 +f 3272/1/302 3496/1/302 3580/1/302 +f 3427/1/303 3651/1/303 3483/1/303 +f 3311/1/304 3535/1/304 3647/1/304 +f 3246/1/305 3470/1/305 3638/1/305 +f 3233/1/306 3401/1/306 3625/1/306 +f 3298/1/307 3410/1/307 3634/1/307 +f 3220/1/308 3444/1/308 3612/1/308 +f 3397/1/309 3285/1/309 3509/1/309 +f 3384/1/310 3608/1/310 3496/1/310 +f 3375/1/311 3207/1/311 3431/1/311 +f 3259/1/312 3483/1/312 3595/1/312 +f 3312/1/313 3344/1/313 3568/1/313 +f 3358/1/314 3582/1/314 3470/1/314 +f 3345/1/315 3233/1/315 3457/1/315 +f 3299/1/316 3325/1/316 3549/1/316 +f 3370/1/317 3594/1/317 3510/1/317 +f 3328/1/318 3552/1/318 3444/1/318 +f 3357/1/319 3581/1/319 3497/1/319 +f 3207/1/320 3341/1/320 3565/1/320 +f 3260/1/321 3428/1/321 3652/1/321 +f 3424/1/322 3312/1/322 3536/1/322 +f 3247/1/323 3415/1/323 3639/1/323 +f 3411/1/324 3299/1/324 3523/1/324 +f 3234/1/325 3458/1/325 3626/1/325 +f 3286/1/326 3510/1/326 3622/1/326 +f 3389/1/327 3221/1/327 3445/1/327 +f 3273/1/328 3497/1/328 3609/1/328 +f 3376/1/329 3600/1/329 3432/1/329 +f 3372/1/330 3260/1/330 3484/1/330 +f 3313/1/331 3345/1/331 3569/1/331 +f 3359/1/332 3247/1/332 3471/1/332 +f 3300/1/333 3524/1/333 3545/1/333 +f 3346/1/334 3570/1/334 3458/1/334 +f 3371/1/335 3595/1/335 3511/1/335 +f 3221/1/336 3329/1/336 3553/1/336 +f 3208/1/337 3432/1/337 3564/1/337 +f 3274/1/338 3498/1/338 3582/1/338 +f 3261/1/339 3429/1/339 3653/1/339 +f 3425/1/340 3313/1/340 3537/1/340 +f 3248/1/341 3472/1/341 3640/1/341 +f 3412/1/342 3636/1/342 3524/1/342 +f 3403/1/343 3235/1/343 3459/1/343 +f 3390/1/344 3222/1/344 3446/1/344 +f 3287/1/345 3511/1/345 3623/1/345 +f 3377/1/346 3209/1/346 3433/1/346 +f 3386/1/347 3610/1/347 3498/1/347 +f 3373/1/348 3261/1/348 3485/1/348 +f 3335/1/349 3559/1/349 3538/1/349 +f 3360/1/350 3584/1/350 3472/1/350 +f 3235/1/351 3347/1/351 3571/1/351 +f 3331/1/352 3555/1/352 3525/1/352 +f 3222/1/353 3330/1/353 3554/1/353 +f 3288/1/354 3372/1/354 3596/1/354 +f 3209/1/355 3339/1/355 3563/1/355 +f 3275/1/356 3359/1/356 3583/1/356 +f 3262/1/357 3486/1/357 3570/1/357 +f 3314/1/358 3538/1/358 3650/1/358 +f 3417/1/359 3249/1/359 3473/1/359 +f 3404/1/360 3628/1/360 3460/1/360 +f 3301/1/361 3525/1/361 3637/1/361 +f 3391/1/362 3615/1/362 3447/1/362 +f 3400/1/363 3288/1/363 3512/1/363 +f 3210/1/364 3434/1/364 3602/1/364 +f 3387/1/365 3275/1/365 3499/1/365 +f 3374/1/366 3598/1/366 3486/1/366 +f 3327/1/367 3551/1/367 3539/1/367 +f 3249/1/368 3361/1/368 3585/1/368 +f 3236/1/369 3460/1/369 3572/1/369 +f 3302/1/370 3526/1/370 3544/1/370 +f 3223/1/371 3447/1/371 3555/1/371 +f 3289/1/372 3373/1/372 3597/1/372 +f 3338/1/373 3562/1/373 3434/1/373 +f 3276/1/374 3500/1/374 3584/1/374 +f 3347/1/375 3263/1/375 3487/1/375 +f 3315/1/376 3539/1/376 3651/1/376 +f 3418/1/377 3250/1/377 3474/1/377 +f 3405/1/378 3237/1/378 3461/1/378 +f 3414/1/379 3638/1/379 3526/1/379 +f 3392/1/380 3224/1/380 3448/1/380 +f 3401/1/381 3289/1/381 3513/1/381 +f 3211/1/382 3379/1/382 3603/1/382 +f 3388/1/383 3612/1/383 3500/1/383 +f 3263/1/384 3375/1/384 3599/1/384 +f 3316/1/385 3336/1/385 3560/1/385 +f 3250/1/386 3362/1/386 3586/1/386 +f 3237/1/387 3349/1/387 3573/1/387 +f 3303/1/388 3337/1/388 3561/1/388 +f 3224/1/389 3332/1/389 3556/1/389 +f 3290/1/390 3514/1/390 3557/1/390 +f 3337/1/391 3211/1/391 3435/1/391 +f 3361/1/392 3277/1/392 3501/1/392 +f 3348/1/393 3572/1/393 3488/1/393 +f 3428/1/394 3316/1/394 3540/1/394 +f 3419/1/395 3643/1/395 3475/1/395 +f 3238/1/396 3462/1/396 3630/1/396 +f 3415/1/397 3303/1/397 3527/1/397 +f 3225/1/398 3449/1/398 3617/1/398 +f 3402/1/399 3626/1/399 3514/1/399 +f 3212/1/400 3436/1/400 3604/1/400 +f 3277/1/401 3389/1/401 3613/1/401 +f 3264/1/402 3488/1/402 3600/1/402 +f 3317/1/403 3334/1/403 3558/1/403 +f 3251/1/404 3475/1/404 3587/1/404 +f 3350/1/405 3574/1/405 3462/1/405 +f 3304/1/406 3528/1/406 3562/1/406 +f 3333/1/407 3557/1/407 3449/1/407 +f 3319/1/408 3291/1/408 3515/1/408 +f 3320/1/409 3544/1/409 3436/1/409 +f 3362/1/410 3278/1/410 3502/1/410 +f 3349/1/411 3265/1/411 3489/1/411 +f 3429/1/412 3317/1/412 3541/1/412 +f 3420/1/413 3252/1/413 3476/1/413 +f 3239/1/414 3407/1/414 3631/1/414 +f 3416/1/415 3640/1/415 3528/1/415 +f 3394/1/416 3618/1/416 3450/1/416 +f 3291/1/417 3403/1/417 3627/1/417 +f 3381/1/418 3213/1/418 3437/1/418 +f 3278/1/419 3390/1/419 3614/1/419 +f 3265/1/420 3377/1/420 3601/1/420 +f 3252/1/421 3364/1/421 3588/1/421 +f 3351/1/422 3239/1/422 3463/1/422 +f 3330/1/423 3305/1/423 3529/1/423 +f 3226/1/424 3450/1/424 3558/1/424 +f 3318/1/425 3542/1/425 3516/1/425 +f 3213/1/426 3321/1/426 3545/1/426 +f 3363/1/427 3587/1/427 3503/1/427 +f 3266/1/428 3490/1/428 3574/1/428 +f 3253/1/429 3477/1/429 3645/1/429 +f 3240/1/430 3464/1/430 3632/1/430 +f 3305/1/431 3417/1/431 3641/1/431 +f 3292/1/432 3516/1/432 3628/1/432 +f 3395/1/433 3619/1/433 3451/1/433 +f 3279/1/434 3503/1/434 3615/1/434 +f 3382/1/435 3214/1/435 3438/1/435 +f 3378/1/436 3602/1/436 3490/1/436 +f 3365/1/437 3589/1/437 3477/1/437 +f 3339/1/438 3306/1/438 3530/1/438 +f 3352/1/439 3576/1/439 3464/1/439 +f 3318/1/440 3293/1/440 3517/1/440 +f 3227/1/441 3451/1/441 3559/1/441 +f 3364/1/442 3280/1/442 3504/1/442 +f 3214/1/443 3322/1/443 3546/1/443 +f 3267/1/444 3351/1/444 3575/1/444 +f 3422/1/445 3646/1/445 3478/1/445 +f 3306/1/446 3418/1/446 3642/1/446 +f 3409/1/447 3241/1/447 3465/1/447 +f 3293/1/448 3405/1/448 3629/1/448 +f 3228/1/449 3396/1/449 3620/1/449 +f 3280/1/450 3392/1/450 3616/1/450 +f 3215/1/451 3383/1/451 3607/1/451 +f 3379/1/452 3267/1/452 3491/1/452 +f 3254/1/453 3478/1/453 3590/1/453 +f 3340/1/454 3564/1/454 3531/1/454 +f 3241/1/455 3353/1/455 3577/1/455 +f 3328/1/456 3228/1/456 3452/1/456 +f 3294/1/457 3518/1/457 3548/1/457 +f 3323/1/458 3215/1/458 3439/1/458 +f 3281/1/459 3505/1/459 3589/1/459 +f 3268/1/460 3492/1/460 3576/1/460 +f 3423/1/461 3647/1/461 3479/1/461 +f 3307/1/462 3531/1/462 3643/1/462 +f 3410/1/463 3242/1/463 3466/1/463 +f 3229/1/464 3397/1/464 3621/1/464 +f 3406/1/465 3630/1/465 3518/1/465 +f 3445/1/466 3553/1/466 3777/1/466 +f 3595/1/467 3819/1/467 3735/1/467 +f 3432/1/468 3656/1/468 3788/1/468 +f 3498/1/469 3722/1/469 3806/1/469 +f 3485/1/470 3653/1/470 3877/1/470 +f 3649/1/471 3537/1/471 3761/1/471 +f 3472/1/472 3696/1/472 3864/1/472 +f 3627/1/473 3459/1/473 3683/1/473 +f 3636/1/474 3860/1/474 3748/1/474 +f 3614/1/475 3446/1/475 3670/1/475 +f 3511/1/476 3735/1/476 3847/1/476 +f 3601/1/477 3433/1/477 3657/1/477 +f 3610/1/478 3834/1/478 3722/1/478 +f 3597/1/479 3485/1/479 3709/1/479 +f 3559/1/480 3783/1/480 3762/1/480 +f 3584/1/481 3808/1/481 3696/1/481 +f 3459/1/482 3571/1/482 3795/1/482 +f 3555/1/483 3779/1/483 3749/1/483 +f 3446/1/484 3554/1/484 3778/1/484 +f 3512/1/485 3596/1/485 3820/1/485 +f 3433/1/486 3563/1/486 3787/1/486 +f 3499/1/487 3583/1/487 3807/1/487 +f 3486/1/488 3710/1/488 3794/1/488 +f 3538/1/489 3762/1/489 3874/1/489 +f 3641/1/477 3473/1/477 3697/1/477 +f 3628/1/490 3852/1/490 3684/1/490 +f 3525/1/491 3749/1/491 3861/1/491 +f 3615/1/492 3839/1/492 3671/1/492 +f 3624/1/493 3512/1/493 3736/1/493 +f 3434/1/494 3658/1/494 3826/1/494 +f 3611/1/495 3499/1/495 3723/1/495 +f 3598/1/496 3822/1/496 3710/1/496 +f 3551/1/497 3775/1/497 3763/1/497 +f 3473/1/498 3585/1/498 3809/1/498 +f 3460/1/499 3684/1/499 3796/1/499 +f 3526/1/500 3750/1/500 3768/1/500 +f 3447/1/501 3671/1/501 3779/1/501 +f 3513/1/502 3597/1/502 3821/1/502 +f 3562/1/503 3786/1/503 3658/1/503 +f 3500/1/504 3724/1/504 3808/1/504 +f 3571/1/505 3487/1/505 3711/1/505 +f 3539/1/506 3763/1/506 3875/1/506 +f 3642/1/507 3474/1/507 3698/1/507 +f 3629/1/508 3461/1/508 3685/1/508 +f 3638/1/509 3862/1/509 3750/1/509 +f 3616/1/510 3448/1/510 3672/1/510 +f 3625/1/511 3513/1/511 3737/1/511 +f 3435/1/512 3603/1/512 3827/1/512 +f 3612/1/513 3836/1/513 3724/1/513 +f 3487/1/514 3599/1/514 3823/1/514 +f 3540/1/515 3560/1/515 3784/1/515 +f 3474/1/516 3586/1/516 3810/1/516 +f 3461/1/517 3573/1/517 3797/1/517 +f 3527/1/518 3561/1/518 3785/1/518 +f 3448/1/519 3556/1/519 3780/1/519 +f 3514/1/520 3738/1/520 3781/1/520 +f 3561/1/521 3435/1/521 3659/1/521 +f 3585/1/522 3501/1/522 3725/1/522 +f 3572/1/523 3796/1/523 3712/1/523 +f 3652/1/524 3540/1/524 3764/1/524 +f 3643/1/525 3867/1/525 3699/1/525 +f 3462/1/526 3686/1/526 3854/1/526 +f 3639/1/527 3527/1/527 3751/1/527 +f 3449/1/528 3673/1/528 3841/1/528 +f 3626/1/529 3850/1/529 3738/1/529 +f 3436/1/530 3660/1/530 3828/1/530 +f 3501/1/531 3613/1/531 3837/1/531 +f 3488/1/532 3712/1/532 3824/1/532 +f 3541/1/533 3558/1/533 3782/1/533 +f 3475/1/534 3699/1/534 3811/1/534 +f 3574/1/535 3798/1/535 3686/1/535 +f 3528/1/536 3752/1/536 3786/1/536 +f 3557/1/537 3781/1/537 3673/1/537 +f 3543/1/538 3515/1/538 3739/1/538 +f 3586/1/539 3502/1/539 3726/1/539 +f 3544/1/540 3768/1/540 3660/1/540 +f 3573/1/541 3489/1/541 3713/1/541 +f 3653/1/542 3541/1/542 3765/1/542 +f 3644/1/543 3476/1/543 3700/1/543 +f 3463/1/544 3631/1/544 3855/1/544 +f 3640/1/545 3864/1/545 3752/1/545 +f 3515/1/546 3627/1/546 3851/1/546 +f 3618/1/547 3842/1/547 3674/1/547 +f 3502/1/548 3614/1/548 3838/1/548 +f 3437/1/549 3661/1/549 3829/1/549 +f 3489/1/550 3601/1/550 3825/1/550 +f 3476/1/551 3588/1/551 3812/1/551 +f 3554/1/552 3529/1/552 3753/1/552 +f 3575/1/553 3463/1/553 3687/1/553 +f 3542/1/554 3766/1/554 3740/1/554 +f 3558/1/555 3450/1/555 3674/1/555 +f 3587/1/556 3811/1/556 3727/1/556 +f 3545/1/557 3769/1/557 3661/1/557 +f 3490/1/558 3714/1/558 3798/1/558 +f 3477/1/559 3701/1/559 3869/1/559 +f 3529/1/560 3641/1/560 3865/1/560 +f 3464/1/561 3688/1/561 3856/1/561 +f 3516/1/562 3740/1/562 3852/1/562 +f 3619/1/563 3843/1/563 3675/1/563 +f 3606/1/564 3438/1/564 3662/1/564 +f 3503/1/565 3727/1/565 3839/1/565 +f 3602/1/566 3826/1/566 3714/1/566 +f 3589/1/559 3813/1/559 3701/1/559 +f 3563/1/567 3530/1/567 3754/1/567 +f 3576/1/568 3800/1/568 3688/1/568 +f 3451/1/569 3675/1/569 3783/1/569 +f 3542/1/570 3517/1/570 3741/1/570 +f 3546/1/571 3770/1/571 3662/1/571 +f 3588/1/572 3504/1/572 3728/1/572 +f 3491/1/573 3575/1/573 3799/1/573 +f 3646/1/574 3870/1/574 3702/1/574 +f 3633/1/575 3465/1/575 3689/1/575 +f 3530/1/576 3642/1/576 3866/1/576 +f 3452/1/577 3620/1/577 3844/1/577 +f 3517/1/578 3629/1/578 3853/1/578 +f 3439/1/579 3607/1/579 3831/1/579 +f 3504/1/580 3616/1/580 3840/1/580 +f 3603/1/581 3491/1/581 3715/1/581 +f 3478/1/582 3702/1/582 3814/1/582 +f 3564/1/583 3788/1/583 3755/1/583 +f 3465/1/584 3577/1/584 3801/1/584 +f 3552/1/585 3452/1/585 3676/1/585 +f 3518/1/586 3742/1/586 3772/1/586 +f 3547/1/587 3439/1/587 3663/1/587 +f 3505/1/588 3729/1/588 3813/1/588 +f 3492/1/589 3716/1/589 3800/1/589 +f 3647/1/590 3871/1/590 3703/1/590 +f 3531/1/591 3755/1/591 3867/1/591 +f 3634/1/592 3466/1/592 3690/1/592 +f 3453/1/593 3621/1/593 3845/1/593 +f 3630/1/594 3854/1/594 3742/1/594 +f 3440/1/595 3664/1/595 3832/1/595 +f 3617/1/596 3841/1/596 3729/1/596 +f 3604/1/597 3828/1/597 3716/1/597 +f 3479/1/598 3703/1/598 3815/1/598 +f 3565/1/599 3532/1/599 3756/1/599 +f 3466/1/600 3578/1/600 3802/1/600 +f 3560/1/601 3453/1/601 3677/1/601 +f 3519/1/602 3547/1/602 3771/1/602 +f 3548/1/603 3772/1/603 3664/1/603 +f 3590/1/604 3814/1/604 3730/1/604 +f 3577/1/605 3493/1/605 3717/1/605 +f 3480/1/606 3648/1/606 3872/1/606 +f 3532/1/607 3644/1/607 3868/1/607 +f 3467/1/608 3635/1/608 3859/1/608 +f 3622/1/609 3846/1/609 3678/1/609 +f 3631/1/610 3519/1/610 3743/1/610 +f 3441/1/611 3609/1/611 3833/1/611 +f 3506/1/612 3730/1/612 3842/1/612 +f 3605/1/613 3829/1/613 3717/1/613 +f 3592/1/614 3480/1/614 3704/1/614 +f 3533/1/615 3757/1/615 3774/1/615 +f 3579/1/616 3467/1/616 3691/1/616 +f 3454/1/617 3678/1/617 3790/1/617 +f 3520/1/618 3744/1/618 3770/1/618 +f 3549/1/619 3441/1/619 3665/1/619 +f 3591/1/620 3815/1/620 3731/1/620 +f 3578/1/621 3494/1/621 3718/1/621 +f 3481/1/622 3649/1/622 3873/1/622 +f 3645/1/623 3869/1/623 3757/1/623 +f 3468/1/624 3692/1/624 3860/1/624 +f 3623/1/625 3847/1/625 3679/1/625 +f 3632/1/626 3856/1/626 3744/1/626 +f 3442/1/627 3666/1/627 3834/1/627 +f 3507/1/628 3731/1/628 3843/1/628 +f 3494/1/629 3606/1/629 3830/1/629 +f 3593/1/630 3481/1/630 3705/1/630 +f 3566/1/631 3790/1/631 3758/1/631 +f 3580/1/632 3804/1/632 3692/1/632 +f 3455/1/633 3679/1/633 3791/1/633 +f 3556/1/634 3521/1/634 3745/1/634 +f 3550/1/528 3774/1/528 3666/1/528 +f 3508/1/635 3592/1/635 3816/1/635 +f 3495/1/636 3579/1/636 3803/1/636 +f 3650/1/637 3874/1/637 3706/1/637 +f 3534/1/638 3758/1/638 3870/1/638 +f 3637/1/639 3861/1/639 3693/1/639 +f 3456/1/640 3624/1/640 3848/1/640 +f 3521/1/641 3633/1/641 3857/1/641 +f 3620/1/642 3508/1/642 3732/1/642 +f 3443/1/643 3611/1/643 3835/1/643 +f 3607/1/644 3495/1/644 3719/1/644 +f 3430/1/645 3654/1/645 3822/1/645 +f 3482/1/646 3706/1/646 3818/1/646 +f 3567/1/647 3791/1/647 3759/1/647 +f 3469/1/648 3693/1/648 3805/1/648 +f 3553/1/649 3522/1/649 3746/1/649 +f 3568/1/650 3456/1/650 3680/1/650 +f 3509/1/651 3593/1/651 3817/1/651 +f 3551/1/652 3443/1/652 3667/1/652 +f 3496/1/653 3720/1/653 3804/1/653 +f 3543/1/654 3767/1/654 3654/1/654 +f 3651/1/655 3875/1/655 3707/1/655 +f 3535/1/656 3759/1/656 3871/1/656 +f 3470/1/657 3694/1/657 3862/1/657 +f 3522/1/658 3634/1/658 3858/1/658 +f 3457/1/659 3625/1/659 3849/1/659 +f 3621/1/660 3509/1/660 3733/1/660 +f 3444/1/661 3668/1/661 3836/1/661 +f 3608/1/662 3832/1/662 3720/1/662 +f 3599/1/663 3431/1/663 3655/1/663 +f 3483/1/664 3707/1/664 3819/1/664 +f 3536/1/665 3568/1/665 3792/1/665 +f 3582/1/666 3806/1/666 3694/1/666 +f 3523/1/667 3549/1/667 3773/1/667 +f 3569/1/668 3457/1/668 3681/1/668 +f 3552/1/669 3776/1/669 3668/1/669 +f 3594/1/670 3818/1/670 3734/1/670 +f 3431/1/671 3565/1/671 3789/1/671 +f 3581/1/672 3805/1/672 3721/1/672 +f 3484/1/673 3652/1/673 3876/1/673 +f 3648/1/674 3536/1/674 3760/1/674 +f 3471/1/675 3639/1/675 3863/1/675 +f 3458/1/676 3682/1/676 3850/1/676 +f 3635/1/677 3523/1/677 3747/1/677 +f 3613/1/678 3445/1/678 3669/1/678 +f 3510/1/679 3734/1/679 3846/1/679 +f 3600/1/680 3824/1/680 3656/1/680 +f 3497/1/681 3721/1/681 3833/1/681 +f 3596/1/682 3484/1/682 3708/1/682 +f 3537/1/683 3569/1/683 3793/1/683 +f 3583/1/684 3471/1/684 3695/1/684 +f 3570/1/685 3794/1/685 3682/1/685 +f 3524/1/686 3748/1/686 3769/1/686 +f 3692/1/687 3804/1/687 4476/1/687 +f 4061/1/688 3949/1/688 4621/1/688 +f 3898/1/689 4570/1/689 4738/1/689 +f 3718/1/690 4390/1/690 4474/1/690 +f 4009/1/691 3975/1/691 4647/1/691 +f 3666/1/692 3774/1/692 4446/1/692 +f 4035/1/693 4707/1/693 4595/1/693 +f 3743/1/694 4415/1/694 4527/1/694 +f 3860/1/695 3692/1/695 4364/1/695 +f 3949/1/696 4033/1/696 4705/1/696 +f 3897/1/697 4569/1/697 4677/1/697 +f 3829/1/698 4501/1/698 4389/1/698 +f 3974/1/699 4646/1/699 4758/1/699 +f 3834/1/700 3666/1/700 4338/1/700 +f 3923/1/701 4595/1/701 4763/1/701 +f 3771/1/702 4443/1/702 4415/1/702 +f 3691/1/703 4363/1/703 4475/1/703 +f 3948/1/704 4620/1/704 4732/1/704 +f 4065/1/705 4737/1/705 4569/1/705 +f 3717/1/706 4389/1/706 4473/1/706 +f 3992/1/707 4664/1/707 4646/1/707 +f 3773/1/708 3665/1/708 4337/1/708 +f 4034/1/709 3922/1/709 4594/1/709 +f 3742/1/710 3854/1/710 4526/1/710 +f 3859/1/711 4531/1/711 4363/1/711 +f 4032/1/712 4704/1/712 4620/1/712 +f 4004/1/713 3896/1/713 4568/1/713 +f 3716/1/714 3828/1/714 4500/1/714 +f 4085/1/715 4757/1/715 4645/1/715 +f 3665/1/716 3833/1/716 4505/1/716 +f 3922/1/717 4090/1/717 4762/1/717 +f 3772/1/718 3742/1/718 4414/1/718 +f 3802/1/719 4474/1/719 4362/1/719 +f 3947/1/720 4059/1/720 4731/1/720 +f 3896/1/721 4064/1/721 4736/1/721 +f 3800/1/722 3716/1/722 4388/1/722 +f 3973/1/723 4645/1/723 4675/1/723 +f 3664/1/724 3772/1/724 4444/1/724 +f 4033/1/725 3921/1/725 4593/1/725 +f 3853/1/726 4525/1/726 4413/1/726 +f 3690/1/727 4362/1/727 4530/1/727 +f 4031/1/728 3947/1/728 4619/1/728 +f 4003/1/729 4675/1/729 4567/1/729 +f 3715/1/730 4387/1/730 4499/1/730 +f 3972/1/731 4644/1/731 4756/1/731 +f 3832/1/732 3664/1/732 4336/1/732 +f 3921/1/733 4089/1/733 4761/1/733 +f 3741/1/734 4413/1/734 4438/1/734 +f 3801/1/735 4473/1/735 4361/1/735 +f 3946/1/736 4618/1/736 4730/1/736 +f 3895/1/737 4567/1/737 4735/1/737 +f 3799/1/738 4471/1/738 4387/1/738 +f 3993/1/739 4665/1/739 4644/1/739 +f 3663/1/740 4335/1/740 4443/1/740 +f 3920/1/741 4592/1/741 4704/1/741 +f 3852/1/742 3740/1/742 4412/1/742 +f 3689/1/743 4361/1/743 4529/1/743 +f 4030/1/744 4702/1/744 4618/1/744 +f 4002/1/745 3894/1/745 4566/1/745 +f 3714/1/746 3826/1/746 4498/1/746 +f 3971/1/747 4083/1/747 4755/1/747 +f 3831/1/748 4503/1/748 4335/1/748 +f 4088/1/749 4760/1/749 4592/1/749 +f 3740/1/750 3766/1/750 4438/1/750 +f 3688/1/751 3800/1/751 4472/1/751 +f 4057/1/752 4729/1/752 4617/1/752 +f 3894/1/753 4062/1/753 4734/1/753 +f 3765/1/754 4437/1/754 4549/1/754 +f 3798/1/755 3714/1/755 4386/1/755 +f 3997/1/756 3971/1/756 4643/1/756 +f 3770/1/757 4442/1/757 4334/1/757 +f 3919/1/758 4031/1/758 4703/1/758 +f 3851/1/759 4523/1/759 4411/1/759 +f 3945/1/760 4617/1/760 4701/1/760 +f 3856/1/761 3688/1/761 4360/1/761 +f 4001/1/762 3893/1/762 4565/1/762 +f 3782/1/763 4454/1/763 4437/1/763 +f 3825/1/764 4497/1/764 4385/1/764 +f 4082/1/765 3970/1/765 4642/1/765 +f 4087/1/766 3919/1/766 4591/1/766 +f 3662/1/767 4334/1/767 4502/1/767 +f 3739/1/768 4411/1/768 4439/1/768 +f 3944/1/769 4616/1/769 4728/1/769 +f 3687/1/770 4359/1/770 4471/1/770 +f 3893/1/771 4061/1/771 4733/1/771 +f 3764/1/772 4436/1/772 4548/1/772 +f 3713/1/773 4385/1/773 4469/1/773 +f 3970/1/774 4001/1/774 4673/1/774 +f 3918/1/775 4590/1/775 4702/1/775 +f 3769/1/776 4441/1/776 4333/1/776 +f 3738/1/777 3850/1/777 4522/1/777 +f 4028/1/778 4700/1/778 4616/1/778 +f 3855/1/779 4527/1/779 4359/1/779 +f 3892/1/780 4564/1/780 4672/1/780 +f 3784/1/781 4456/1/781 4436/1/781 +f 3824/1/782 3712/1/782 4384/1/782 +f 4081/1/783 3969/1/783 4641/1/783 +f 4086/1/784 4758/1/784 4590/1/784 +f 3661/1/785 4333/1/785 4501/1/785 +f 3781/1/786 3738/1/786 4410/1/786 +f 3943/1/787 4055/1/787 4727/1/787 +f 3686/1/788 3798/1/788 4470/1/788 +f 4060/1/789 4732/1/789 4564/1/789 +f 3875/1/790 3763/1/790 4435/1/790 +f 3712/1/791 3796/1/791 4468/1/791 +f 3969/1/792 4004/1/792 4676/1/792 +f 4029/1/793 4701/1/793 4589/1/793 +f 3660/1/794 3768/1/794 4440/1/794 +f 3737/1/795 4409/1/795 4521/1/795 +f 4027/1/796 3943/1/796 4615/1/796 +f 3854/1/797 3686/1/797 4358/1/797 +f 3891/1/798 3999/1/798 4671/1/798 +f 3763/1/799 3775/1/799 4447/1/799 +f 3823/1/800 4495/1/800 4383/1/800 +f 3968/1/801 4640/1/801 4752/1/801 +f 3917/1/802 4589/1/802 4757/1/802 +f 3828/1/803 3660/1/803 4332/1/803 +f 3821/1/804 4493/1/804 4409/1/804 +f 4054/1/805 3942/1/805 4614/1/805 +f 3797/1/806 4469/1/806 4357/1/806 +f 4059/1/807 3891/1/807 4563/1/807 +f 3874/1/808 3762/1/808 4434/1/808 +f 3711/1/809 4383/1/809 4467/1/809 +f 3994/1/810 4666/1/810 4640/1/810 +f 3916/1/811 4588/1/811 4700/1/811 +f 3659/1/812 4331/1/812 4457/1/812 +f 3736/1/813 4408/1/813 4520/1/813 +f 3942/1/814 4026/1/814 4698/1/814 +f 3685/1/815 4357/1/815 4525/1/815 +f 3890/1/816 4562/1/816 4670/1/816 +f 3762/1/817 3783/1/817 4455/1/817 +f 3710/1/818 3822/1/818 4494/1/818 +f 3967/1/819 4079/1/819 4751/1/819 +f 4084/1/820 4756/1/820 4588/1/820 +f 3827/1/821 4499/1/821 4331/1/821 +f 3820/1/822 4492/1/822 4408/1/822 +f 4053/1/823 3941/1/823 4613/1/823 +f 3796/1/824 3684/1/824 4356/1/824 +f 4058/1/825 4730/1/825 4562/1/825 +f 3761/1/826 4433/1/826 4545/1/826 +f 3794/1/827 3710/1/827 4382/1/827 +f 3995/1/828 3967/1/828 4639/1/828 +f 3915/1/829 4027/1/829 4699/1/829 +f 3658/1/830 3786/1/830 4458/1/830 +f 3847/1/831 3735/1/831 4407/1/831 +f 3941/1/832 4025/1/832 4697/1/832 +f 3684/1/833 3852/1/833 4524/1/833 +f 3997/1/834 4669/1/834 4561/1/834 +f 3793/1/835 4465/1/835 4433/1/835 +f 3709/1/836 4381/1/836 4493/1/836 +f 3966/1/837 4638/1/837 4750/1/837 +f 4083/1/838 3915/1/838 4587/1/838 +f 3826/1/839 3658/1/839 4330/1/839 +f 3735/1/840 3819/1/840 4491/1/840 +f 3940/1/841 4612/1/841 4724/1/841 +f 3795/1/842 4467/1/842 4355/1/842 +f 3889/1/843 4561/1/843 4729/1/843 +f 3760/1/844 4432/1/844 4544/1/844 +f 3877/1/845 4549/1/845 4381/1/845 +f 3996/1/846 4668/1/846 4638/1/846 +f 4026/1/847 3914/1/847 4586/1/847 +f 3787/1/848 4459/1/848 4329/1/848 +f 3846/1/849 3734/1/849 4406/1/849 +f 4024/1/850 4696/1/850 4612/1/850 +f 3683/1/851 4355/1/851 4523/1/851 +f 3888/1/852 4560/1/852 4668/1/852 +f 3792/1/853 4464/1/853 4432/1/853 +f 3708/1/854 4380/1/854 4492/1/854 +f 4077/1/855 3965/1/855 4637/1/855 +f 3914/1/856 4082/1/856 4754/1/856 +f 3657/1/857 4329/1/857 4497/1/857 +f 3734/1/858 3818/1/858 4490/1/858 +f 3939/1/859 4051/1/859 4723/1/859 +f 3682/1/860 3794/1/860 4466/1/860 +f 4056/1/861 4728/1/861 4560/1/861 +f 3871/1/862 3759/1/862 4431/1/862 +f 3876/1/863 4548/1/863 4380/1/863 +f 3965/1/864 3990/1/864 4662/1/864 +f 4025/1/865 3913/1/865 4585/1/865 +f 3788/1/866 3656/1/866 4328/1/866 +f 3733/1/867 4405/1/867 4517/1/867 +f 4023/1/868 3939/1/868 4611/1/868 +f 3850/1/869 3682/1/869 4354/1/869 +f 3887/1/870 3995/1/870 4667/1/870 +f 3759/1/871 3791/1/871 4463/1/871 +f 3819/1/872 3707/1/872 4379/1/872 +f 4076/1/873 4748/1/873 4636/1/873 +f 3913/1/874 4081/1/874 4753/1/874 +f 3656/1/875 3824/1/875 4496/1/875 +f 3817/1/876 4489/1/876 4405/1/876 +f 3938/1/877 4610/1/877 4722/1/877 +f 3681/1/878 4353/1/878 4465/1/878 +f 4055/1/879 3887/1/879 4559/1/879 +f 3870/1/880 3758/1/880 4430/1/880 +f 3707/1/881 3875/1/881 4547/1/881 +f 3964/1/882 4636/1/882 4662/1/882 +f 3912/1/883 4584/1/883 4696/1/883 +f 3789/1/884 4461/1/884 4327/1/884 +f 3732/1/885 4404/1/885 4516/1/885 +f 3989/1/886 4101/1/886 4773/1/886 +f 4022/1/887 4694/1/887 4610/1/887 +f 3849/1/888 4521/1/888 4353/1/888 +f 3994/1/889 3886/1/889 4558/1/889 +f 3758/1/890 3790/1/890 4462/1/890 +f 3818/1/891 3706/1/891 4378/1/891 +f 4075/1/892 3963/1/892 4635/1/892 +f 4080/1/893 4752/1/893 4584/1/893 +f 3655/1/894 4327/1/894 4495/1/894 +f 3816/1/895 4488/1/895 4404/1/895 +f 4006/1/896 3989/1/896 4661/1/896 +f 4049/1/897 3937/1/897 4609/1/897 +f 3680/1/898 4352/1/898 4464/1/898 +f 3886/1/899 4054/1/899 4726/1/899 +f 3757/1/900 3869/1/900 4541/1/900 +f 3706/1/901 3874/1/901 4546/1/901 +f 3963/1/902 3991/1/902 4663/1/902 +f 3911/1/903 4023/1/903 4695/1/903 +f 3654/1/904 3767/1/904 4439/1/904 +f 3843/1/905 3731/1/905 4403/1/905 +f 3988/1/906 4100/1/906 4772/1/906 +f 3848/1/907 4520/1/907 4352/1/907 +f 3937/1/908 4021/1/908 4693/1/908 +f 3993/1/909 3885/1/909 4557/1/909 +f 3774/1/910 3757/1/910 4429/1/910 +f 3992/1/911 4216/1/911 4108/1/911 +f 4034/1/912 3950/1/912 4174/1/912 +f 4021/1/541 3937/1/541 4161/1/541 +f 4101/1/542 3989/1/542 4213/1/542 +f 4092/1/543 3924/1/543 4148/1/543 +f 3911/1/544 4079/1/544 4303/1/544 +f 4088/1/545 4312/1/545 4200/1/545 +f 4066/1/547 4290/1/547 4122/1/547 +f 3963/1/546 4075/1/546 4299/1/546 +f 3885/1/549 4109/1/549 4277/1/549 +f 3950/1/913 4062/1/913 4286/1/913 +f 3937/1/550 4049/1/550 4273/1/550 +f 3924/1/551 4036/1/551 4260/1/551 +f 4023/1/553 3911/1/553 4135/1/553 +f 4002/1/914 3977/1/914 4201/1/914 +f 4006/1/555 3898/1/555 4122/1/555 +f 3990/1/554 4214/1/554 4188/1/554 +f 3993/1/557 4217/1/557 4109/1/557 +f 4035/1/556 4259/1/556 4175/1/556 +f 3938/1/558 4162/1/558 4246/1/558 +f 3925/1/915 4149/1/915 4317/1/915 +f 3912/1/916 4136/1/916 4304/1/916 +f 3977/1/917 4089/1/917 4313/1/917 +f 4067/1/563 4291/1/563 4123/1/563 +f 3964/1/562 4188/1/562 4300/1/562 +f 3886/1/918 4110/1/918 4278/1/918 +f 3951/1/565 4175/1/565 4287/1/565 +f 4050/1/566 4274/1/566 4162/1/566 +f 4037/1/919 4261/1/919 4149/1/919 +f 4024/1/920 4248/1/920 4136/1/920 +f 4011/1/567 3978/1/567 4202/1/567 +f 3899/1/569 4123/1/569 4231/1/569 +f 3990/1/570 3965/1/570 4189/1/570 +f 3994/1/921 4218/1/921 4110/1/921 +f 4036/1/572 3952/1/572 4176/1/572 +f 3939/1/573 4023/1/573 4247/1/573 +f 4094/1/574 4318/1/574 4150/1/574 +f 4081/1/575 3913/1/575 4137/1/575 +f 3978/1/922 4090/1/922 4314/1/922 +f 3900/1/577 4068/1/577 4292/1/577 +f 3965/1/578 4077/1/578 4301/1/578 +f 3887/1/579 4055/1/579 4279/1/579 +f 3952/1/580 4064/1/580 4288/1/580 +f 4051/1/581 3939/1/581 4163/1/581 +f 3926/1/582 4150/1/582 4262/1/582 +f 4012/1/583 4236/1/583 4203/1/583 +f 3913/1/584 4025/1/584 4249/1/584 +f 4000/1/585 3900/1/585 4124/1/585 +f 3966/1/586 4190/1/586 4220/1/586 +f 3953/1/923 4177/1/923 4261/1/923 +f 3995/1/587 3887/1/587 4111/1/587 +f 3940/1/924 4164/1/924 4248/1/924 +f 4095/1/590 4319/1/590 4151/1/590 +f 3979/1/591 4203/1/591 4315/1/591 +f 4082/1/925 3914/1/925 4138/1/925 +f 4078/1/594 4302/1/594 4190/1/594 +f 3901/1/593 4069/1/593 4293/1/593 +f 4065/1/926 4289/1/926 4177/1/926 +f 3888/1/595 4112/1/595 4280/1/595 +f 4052/1/927 4276/1/927 4164/1/927 +f 3927/1/598 4151/1/598 4263/1/598 +f 4013/1/599 3980/1/599 4204/1/599 +f 3914/1/928 4026/1/928 4250/1/928 +f 3967/1/602 3995/1/602 4219/1/602 +f 4008/1/601 3901/1/601 4125/1/601 +f 4038/1/604 4262/1/604 4178/1/604 +f 3996/1/603 4220/1/603 4112/1/603 +f 4025/1/605 3941/1/605 4165/1/605 +f 3928/1/606 4096/1/606 4320/1/606 +f 3980/1/607 4092/1/607 4316/1/607 +f 3915/1/608 4083/1/608 4307/1/608 +f 4079/1/610 3967/1/610 4191/1/610 +f 4070/1/609 4294/1/609 4126/1/609 +f 3889/1/611 4057/1/611 4281/1/611 +f 3954/1/612 4178/1/612 4290/1/612 +f 4053/1/613 4277/1/613 4165/1/613 +f 4040/1/614 3928/1/614 4152/1/614 +f 3981/1/929 4205/1/929 4222/1/929 +f 4027/1/616 3915/1/616 4139/1/616 +f 3902/1/617 4126/1/617 4238/1/617 +f 3968/1/930 4192/1/930 4218/1/930 +f 3997/1/619 3889/1/619 4113/1/619 +f 4039/1/620 4263/1/620 4179/1/620 +f 4026/1/931 3942/1/931 4166/1/931 +f 3929/1/622 4097/1/622 4321/1/622 +f 4093/1/932 4317/1/932 4205/1/932 +f 3916/1/624 4140/1/624 4308/1/624 +f 4071/1/625 4295/1/625 4127/1/625 +f 4080/1/933 4304/1/933 4192/1/933 +f 3890/1/934 4114/1/934 4282/1/934 +f 3955/1/628 4179/1/628 4291/1/628 +f 3942/1/935 4054/1/935 4278/1/935 +f 4041/1/630 3929/1/630 4153/1/630 +f 4014/1/631 4238/1/631 4206/1/631 +f 4028/1/632 4252/1/632 4140/1/632 +f 3903/1/633 4127/1/633 4239/1/633 +f 4004/1/634 3969/1/634 4193/1/634 +f 3998/1/936 4222/1/936 4114/1/936 +f 3956/1/635 4040/1/635 4264/1/635 +f 3943/1/636 4027/1/636 4251/1/636 +f 4098/1/637 4322/1/637 4154/1/637 +f 3982/1/638 4206/1/638 4318/1/638 +f 4085/1/639 4309/1/639 4141/1/639 +f 3904/1/640 4072/1/640 4296/1/640 +f 3969/1/641 4081/1/641 4305/1/641 +f 3891/1/643 4059/1/643 4283/1/643 +f 4068/1/642 3956/1/642 4180/1/642 +f 3878/1/645 4102/1/645 4270/1/645 +f 4055/1/644 3943/1/644 4167/1/644 +f 3930/1/646 4154/1/646 4266/1/646 +f 4015/1/647 4239/1/647 4207/1/647 +f 3917/1/648 4141/1/648 4253/1/648 +f 4016/1/650 3904/1/650 4128/1/650 +f 4001/1/937 3970/1/937 4194/1/937 +f 3999/1/652 3891/1/652 4115/1/652 +f 3957/1/651 4041/1/651 4265/1/651 +f 3991/1/654 4215/1/654 4102/1/654 +f 3944/1/653 4168/1/653 4252/1/653 +f 4099/1/655 4323/1/655 4155/1/655 +f 3983/1/656 4207/1/656 4319/1/656 +f 3918/1/938 4142/1/938 4310/1/938 +f 3905/1/659 4073/1/659 4297/1/659 +f 3970/1/939 4082/1/939 4306/1/939 +f 3892/1/661 4116/1/661 4284/1/661 +f 4069/1/660 3957/1/660 4181/1/660 +f 4047/1/663 3879/1/663 4103/1/663 +f 4056/1/662 4280/1/662 4168/1/662 +f 3931/1/664 4155/1/664 4267/1/664 +f 3984/1/665 4016/1/665 4240/1/665 +f 4030/1/940 4254/1/940 4142/1/940 +f 4017/1/668 3905/1/668 4129/1/668 +f 3971/1/667 3997/1/667 4221/1/667 +f 4000/1/669 4224/1/669 4116/1/669 +f 4042/1/670 4266/1/670 4182/1/670 +f 3879/1/671 4013/1/671 4237/1/671 +f 4029/1/672 4253/1/672 4169/1/672 +f 3932/1/673 4100/1/673 4324/1/673 +f 4096/1/674 3984/1/674 4208/1/674 +f 3919/1/675 4087/1/675 4311/1/675 +f 3906/1/676 4130/1/676 4298/1/676 +f 4083/1/677 3971/1/677 4195/1/677 +f 4061/1/941 3893/1/941 4117/1/941 +f 3958/1/679 4182/1/679 4294/1/679 +f 4048/1/680 4272/1/680 4104/1/680 +f 3945/1/681 4169/1/681 4281/1/681 +f 4044/1/682 3932/1/682 4156/1/682 +f 3985/1/683 4017/1/683 4241/1/683 +f 4031/1/684 3919/1/684 4143/1/684 +f 4018/1/685 4242/1/685 4130/1/685 +f 3972/1/686 4196/1/686 4217/1/686 +f 3893/1/942 4001/1/942 4225/1/942 +f 4043/1/467 4267/1/467 4183/1/467 +f 3946/1/943 4170/1/943 4254/1/943 +f 3880/1/468 4104/1/468 4236/1/468 +f 3933/1/470 4101/1/470 4325/1/470 +f 4097/1/471 3985/1/471 4209/1/471 +f 3920/1/472 4144/1/472 4312/1/472 +f 4075/1/473 3907/1/473 4131/1/473 +f 4084/1/474 4308/1/474 4196/1/474 +f 3959/1/476 4183/1/476 4295/1/476 +f 4062/1/944 3894/1/944 4118/1/944 +f 4058/1/945 4282/1/945 4170/1/945 +f 4049/1/477 3881/1/477 4105/1/477 +f 4045/1/479 3933/1/479 4157/1/479 +f 4007/1/480 4231/1/480 4210/1/480 +f 4032/1/481 4256/1/481 4144/1/481 +f 4003/1/483 4227/1/483 4197/1/483 +f 3907/1/482 4019/1/482 4243/1/482 +f 3960/1/485 4044/1/485 4268/1/485 +f 3894/1/946 4002/1/946 4226/1/946 +f 3947/1/487 4031/1/487 4255/1/487 +f 3881/1/486 4011/1/486 4235/1/486 +f 3934/1/488 4158/1/488 4242/1/488 +f 3986/1/489 4210/1/489 4322/1/489 +f 4089/1/947 3921/1/947 4145/1/947 +f 3973/1/491 4197/1/491 4309/1/491 +f 4076/1/490 4300/1/490 4132/1/490 +f 4072/1/493 3960/1/493 4184/1/493 +f 4063/1/492 4287/1/492 4119/1/492 +f 3882/1/494 4106/1/494 4274/1/494 +f 4059/1/495 3947/1/495 4171/1/495 +f 4046/1/496 4270/1/496 4158/1/496 +f 3999/1/497 4223/1/497 4211/1/497 +f 3921/1/948 4033/1/948 4257/1/948 +f 3974/1/949 4198/1/949 4216/1/949 +f 3908/1/499 4132/1/499 4244/1/499 +f 3895/1/501 4119/1/501 4227/1/501 +f 3961/1/502 4045/1/502 4269/1/502 +f 4010/1/503 4234/1/503 4106/1/503 +f 3948/1/504 4172/1/504 4256/1/504 +f 4019/1/505 3935/1/505 4159/1/505 +f 3987/1/506 4211/1/506 4323/1/506 +f 4090/1/950 3922/1/950 4146/1/950 +f 4077/1/508 3909/1/508 4133/1/508 +f 4086/1/951 4310/1/951 4198/1/951 +f 4064/1/510 3896/1/510 4120/1/510 +f 4073/1/511 3961/1/511 4185/1/511 +f 3883/1/512 4051/1/512 4275/1/512 +f 4060/1/513 4284/1/513 4172/1/513 +f 3935/1/514 4047/1/514 4271/1/514 +f 3988/1/515 4008/1/515 4232/1/515 +f 3922/1/952 4034/1/952 4258/1/952 +f 3909/1/517 4021/1/517 4245/1/517 +f 3975/1/518 4009/1/518 4233/1/518 +f 3896/1/519 4004/1/519 4228/1/519 +f 3962/1/953 4186/1/953 4229/1/953 +f 4009/1/521 3883/1/521 4107/1/521 +f 4033/1/954 3949/1/954 4173/1/954 +f 4020/1/523 4244/1/523 4160/1/523 +f 4100/1/524 3988/1/524 4212/1/524 +f 4091/1/525 4315/1/525 4147/1/525 +f 3910/1/526 4134/1/526 4302/1/526 +f 4087/1/527 3975/1/527 4199/1/527 +f 3897/1/955 4121/1/955 4289/1/955 +f 4074/1/529 4298/1/529 4186/1/529 +f 3884/1/956 4108/1/956 4276/1/956 +f 3949/1/957 4061/1/957 4285/1/957 +f 3936/1/532 4160/1/532 4272/1/532 +f 3989/1/533 4006/1/533 4230/1/533 +f 3923/1/534 4147/1/534 4259/1/534 +f 4022/1/535 4246/1/535 4134/1/535 +f 3976/1/536 4200/1/536 4234/1/536 +f 4005/1/958 4229/1/958 4121/1/958 +f 3991/1/538 3963/1/538 4187/1/538 +f 4360/1/959 4584/1/959 4752/1/959 +f 4425/1/960 4537/1/960 4761/1/960 +f 4515/1/961 4739/1/961 4571/1/961 +f 4412/1/962 4636/1/962 4748/1/962 +f 4502/1/963 4334/1/963 4558/1/963 +f 4399/1/964 4623/1/964 4735/1/964 +f 4498/1/965 4722/1/965 4610/1/965 +f 4485/1/966 4709/1/966 4597/1/966 +f 4472/1/967 4696/1/967 4584/1/967 +f 4459/1/968 4426/1/968 4650/1/968 +f 4347/1/969 4571/1/969 4679/1/969 +f 4438/1/970 4413/1/970 4637/1/970 +f 4442/1/971 4666/1/971 4558/1/971 +f 4484/1/972 4400/1/972 4624/1/972 +f 4387/1/973 4471/1/973 4695/1/973 +f 4542/1/974 4766/1/974 4598/1/974 +f 4529/1/975 4361/1/975 4585/1/975 +f 4426/1/976 4538/1/976 4762/1/976 +f 4348/1/977 4516/1/977 4740/1/977 +f 4413/1/978 4525/1/978 4749/1/978 +f 4335/1/979 4503/1/979 4727/1/979 +f 4400/1/980 4512/1/980 4736/1/980 +f 4499/1/981 4387/1/981 4611/1/981 +f 4374/1/982 4598/1/982 4710/1/982 +f 4460/1/983 4684/1/983 4651/1/983 +f 4361/1/984 4473/1/984 4697/1/984 +f 4448/1/985 4348/1/985 4572/1/985 +f 4414/1/986 4638/1/986 4668/1/986 +f 4443/1/987 4335/1/987 4559/1/987 +f 4401/1/988 4625/1/988 4709/1/988 +f 4388/1/989 4612/1/989 4696/1/989 +f 4543/1/990 4767/1/990 4599/1/990 +f 4427/1/991 4651/1/991 4763/1/991 +f 4530/1/992 4362/1/992 4586/1/992 +f 4349/1/993 4517/1/993 4741/1/993 +f 4526/1/994 4750/1/994 4638/1/994 +f 4336/1/995 4560/1/995 4728/1/995 +f 4513/1/996 4737/1/996 4625/1/996 +f 4500/1/997 4724/1/997 4612/1/997 +f 4375/1/998 4599/1/998 4711/1/998 +f 4461/1/999 4428/1/999 4652/1/999 +f 4362/1/1000 4474/1/1000 4698/1/1000 +f 4456/1/1001 4349/1/1001 4573/1/1001 +f 4415/1/1002 4443/1/1002 4667/1/1002 +f 4444/1/1003 4668/1/1003 4560/1/1003 +f 4486/1/1004 4710/1/1004 4626/1/1004 +f 4473/1/1005 4389/1/1005 4613/1/1005 +f 4376/1/1006 4544/1/1006 4768/1/1006 +f 4428/1/1007 4540/1/1007 4764/1/1007 +f 4363/1/1008 4531/1/1008 4755/1/1008 +f 4518/1/1009 4742/1/1009 4574/1/1009 +f 4527/1/1010 4415/1/1010 4639/1/1010 +f 4337/1/1011 4505/1/1011 4729/1/1011 +f 4402/1/1012 4626/1/1012 4738/1/1012 +f 4501/1/1013 4725/1/1013 4613/1/1013 +f 4488/1/1014 4376/1/1014 4600/1/1014 +f 4429/1/1015 4653/1/1015 4670/1/1015 +f 4475/1/1016 4363/1/1016 4587/1/1016 +f 4350/1/1017 4574/1/1017 4686/1/1017 +f 4416/1/1018 4640/1/1018 4666/1/1018 +f 4445/1/1019 4337/1/1019 4561/1/1019 +f 4487/1/1020 4711/1/1020 4627/1/1020 +f 4474/1/1021 4390/1/1021 4614/1/1021 +f 4377/1/1022 4545/1/1022 4769/1/1022 +f 4541/1/1023 4765/1/1023 4653/1/1023 +f 4364/1/1024 4588/1/1024 4756/1/1024 +f 4519/1/1025 4743/1/1025 4575/1/1025 +f 4528/1/1026 4752/1/1026 4640/1/1026 +f 4338/1/1027 4562/1/1027 4730/1/1027 +f 4403/1/1028 4627/1/1028 4739/1/1028 +f 4390/1/1029 4502/1/1029 4726/1/1029 +f 4489/1/1030 4377/1/1030 4601/1/1030 +f 4462/1/1031 4686/1/1031 4654/1/1031 +f 4476/1/1032 4700/1/1032 4588/1/1032 +f 4452/1/1033 4417/1/1033 4641/1/1033 +f 4351/1/1034 4575/1/1034 4687/1/1034 +f 4404/1/1035 4488/1/1035 4712/1/1035 +f 4446/1/1036 4670/1/1036 4562/1/1036 +f 4391/1/1037 4475/1/1037 4699/1/1037 +f 4546/1/1038 4770/1/1038 4602/1/1038 +f 4430/1/1039 4654/1/1039 4766/1/1039 +f 4533/1/1040 4757/1/1040 4589/1/1040 +f 4417/1/1041 4529/1/1041 4753/1/1041 +f 4352/1/1042 4520/1/1042 4744/1/1042 +f 4516/1/1043 4404/1/1043 4628/1/1043 +f 4339/1/1044 4507/1/1044 4731/1/1044 +f 4503/1/1045 4391/1/1045 4615/1/1045 +f 4326/1/1046 4550/1/1046 4718/1/1046 +f 4378/1/1047 4602/1/1047 4714/1/1047 +f 4463/1/1048 4687/1/1048 4655/1/1048 +f 4365/1/1049 4589/1/1049 4701/1/1049 +f 4449/1/1050 4418/1/1050 4642/1/1050 +f 4464/1/1051 4352/1/1051 4576/1/1051 +f 4405/1/1052 4489/1/1052 4713/1/1052 +f 4447/1/1053 4339/1/1053 4563/1/1053 +f 4439/1/1054 4663/1/1054 4550/1/1054 +f 4392/1/1055 4616/1/1055 4700/1/1055 +f 4547/1/1056 4771/1/1056 4603/1/1056 +f 4431/1/1057 4655/1/1057 4767/1/1057 +f 4366/1/1058 4590/1/1058 4758/1/1058 +f 4353/1/1059 4521/1/1059 4745/1/1059 +f 4418/1/1060 4530/1/1060 4754/1/1060 +f 4340/1/1061 4564/1/1061 4732/1/1061 +f 4517/1/1062 4405/1/1062 4629/1/1062 +f 4495/1/1063 4327/1/1063 4551/1/1063 +f 4504/1/1064 4728/1/1064 4616/1/1064 +f 4379/1/1065 4603/1/1065 4715/1/1065 +f 4432/1/1066 4464/1/1066 4688/1/1066 +f 4478/1/1067 4702/1/1067 4590/1/1067 +f 4465/1/1068 4353/1/1068 4577/1/1068 +f 4419/1/1069 4445/1/1069 4669/1/1069 +f 4448/1/1070 4672/1/1070 4564/1/1070 +f 4490/1/1071 4714/1/1071 4630/1/1071 +f 4327/1/1072 4461/1/1072 4685/1/1072 +f 4477/1/1073 4701/1/1073 4617/1/1073 +f 4380/1/1074 4548/1/1074 4772/1/1074 +f 4544/1/1075 4432/1/1075 4656/1/1075 +f 4367/1/1076 4535/1/1076 4759/1/1076 +f 4354/1/1077 4578/1/1077 4746/1/1077 +f 4531/1/1078 4419/1/1078 4643/1/1078 +f 4509/1/1079 4341/1/1079 4565/1/1079 +f 4406/1/1080 4630/1/1080 4742/1/1080 +f 4496/1/1081 4720/1/1081 4552/1/1081 +f 4393/1/1082 4617/1/1082 4729/1/1082 +f 4492/1/1083 4380/1/1083 4604/1/1083 +f 4433/1/1084 4465/1/1084 4689/1/1084 +f 4479/1/1085 4367/1/1085 4591/1/1085 +f 4466/1/1086 4690/1/1086 4578/1/1086 +f 4420/1/1087 4644/1/1087 4665/1/1087 +f 4341/1/1088 4449/1/1088 4673/1/1088 +f 4491/1/1089 4715/1/1089 4631/1/1089 +f 4328/1/1090 4552/1/1090 4684/1/1090 +f 4394/1/1091 4618/1/1091 4702/1/1091 +f 4381/1/1092 4549/1/1092 4773/1/1092 +f 4545/1/1093 4433/1/1093 4657/1/1093 +f 4368/1/1094 4592/1/1094 4760/1/1094 +f 4523/1/1095 4355/1/1095 4579/1/1095 +f 4532/1/1096 4756/1/1096 4644/1/1096 +f 4510/1/1097 4342/1/1097 4566/1/1097 +f 4407/1/1098 4631/1/1098 4743/1/1098 +f 4497/1/1099 4329/1/1099 4553/1/1099 +f 4506/1/1100 4730/1/1100 4618/1/1100 +f 4493/1/1101 4381/1/1101 4605/1/1101 +f 4455/1/1102 4679/1/1102 4658/1/1102 +f 4480/1/1103 4704/1/1103 4592/1/1103 +f 4355/1/1104 4467/1/1104 4691/1/1104 +f 4451/1/1105 4675/1/1105 4645/1/1105 +f 4342/1/1106 4450/1/1106 4674/1/1106 +f 4408/1/1107 4492/1/1107 4716/1/1107 +f 4329/1/1108 4459/1/1108 4683/1/1108 +f 4395/1/1109 4479/1/1109 4703/1/1109 +f 4382/1/1110 4606/1/1110 4690/1/1110 +f 4434/1/1111 4658/1/1111 4770/1/1111 +f 4537/1/1112 4369/1/1112 4593/1/1112 +f 4524/1/1113 4748/1/1113 4580/1/1113 +f 4421/1/1114 4645/1/1114 4757/1/1114 +f 4511/1/1115 4735/1/1115 4567/1/1115 +f 4520/1/1116 4408/1/1116 4632/1/1116 +f 4330/1/1117 4554/1/1117 4722/1/1117 +f 4507/1/1118 4395/1/1118 4619/1/1118 +f 4494/1/1119 4718/1/1119 4606/1/1119 +f 4447/1/1120 4671/1/1120 4659/1/1120 +f 4369/1/1121 4481/1/1121 4705/1/1121 +f 4356/1/1122 4580/1/1122 4692/1/1122 +f 4422/1/1123 4646/1/1123 4664/1/1123 +f 4343/1/1124 4567/1/1124 4675/1/1124 +f 4409/1/1125 4493/1/1125 4717/1/1125 +f 4458/1/1126 4682/1/1126 4554/1/1126 +f 4396/1/1127 4620/1/1127 4704/1/1127 +f 4467/1/1128 4383/1/1128 4607/1/1128 +f 4435/1/1129 4659/1/1129 4771/1/1129 +f 4538/1/1130 4370/1/1130 4594/1/1130 +f 4525/1/1131 4357/1/1131 4581/1/1131 +f 4534/1/1132 4758/1/1132 4646/1/1132 +f 4512/1/1133 4344/1/1133 4568/1/1133 +f 4521/1/1134 4409/1/1134 4633/1/1134 +f 4331/1/1135 4499/1/1135 4723/1/1135 +f 4508/1/1136 4732/1/1136 4620/1/1136 +f 4383/1/1137 4495/1/1137 4719/1/1137 +f 4436/1/1138 4456/1/1138 4680/1/1138 +f 4370/1/1139 4482/1/1139 4706/1/1139 +f 4357/1/1140 4469/1/1140 4693/1/1140 +f 4423/1/1141 4457/1/1141 4681/1/1141 +f 4344/1/1142 4452/1/1142 4676/1/1142 +f 4410/1/1143 4634/1/1143 4677/1/1143 +f 4481/1/1144 4397/1/1144 4621/1/1144 +f 4457/1/1145 4331/1/1145 4555/1/1145 +f 4468/1/1146 4692/1/1146 4608/1/1146 +f 4548/1/1147 4436/1/1147 4660/1/1147 +f 4539/1/1148 4763/1/1148 4595/1/1148 +f 4358/1/1149 4582/1/1149 4750/1/1149 +f 4535/1/1150 4423/1/1150 4647/1/1150 +f 4522/1/1151 4746/1/1151 4634/1/1151 +f 4345/1/1152 4569/1/1152 4737/1/1152 +f 4397/1/1153 4509/1/1153 4733/1/1153 +f 4332/1/1154 4556/1/1154 4724/1/1154 +f 4384/1/1155 4608/1/1155 4720/1/1155 +f 4437/1/1156 4454/1/1156 4678/1/1156 +f 4371/1/1157 4595/1/1157 4707/1/1157 +f 4424/1/1158 4648/1/1158 4682/1/1158 +f 4470/1/1159 4694/1/1159 4582/1/1159 +f 4439/1/1160 4411/1/1160 4635/1/1160 +f 4453/1/1161 4677/1/1161 4569/1/1161 +f 4482/1/1162 4398/1/1162 4622/1/1162 +f 4440/1/1163 4664/1/1163 4556/1/1163 +f 4469/1/1164 4385/1/1164 4609/1/1164 +f 4549/1/1165 4437/1/1165 4661/1/1165 +f 4540/1/1166 4372/1/1166 4596/1/1166 +f 4536/1/1167 4760/1/1167 4648/1/1167 +f 4359/1/1168 4527/1/1168 4751/1/1168 +f 4411/1/1169 4523/1/1169 4747/1/1169 +f 4514/1/1170 4738/1/1170 4570/1/1170 +f 4333/1/1171 4557/1/1171 4725/1/1171 +f 4398/1/1172 4510/1/1172 4734/1/1172 +f 4385/1/1173 4497/1/1173 4721/1/1173 +f 4372/1/1174 4484/1/1174 4708/1/1174 +f 4450/1/1175 4425/1/1175 4649/1/1175 +f 4471/1/1176 4359/1/1176 4583/1/1176 +f 4454/1/1177 4346/1/1177 4570/1/1177 +f 4438/1/1178 4662/1/1178 4636/1/1178 +f 4441/1/1179 4665/1/1179 4557/1/1179 +f 4483/1/1180 4707/1/1180 4623/1/1180 +f 4386/1/1181 4610/1/1181 4694/1/1181 +f 4373/1/1182 4597/1/1182 4765/1/1182 +f 3770/1/1183 3744/1/1183 4416/1/1183 +f 3924/1/1184 4092/1/1184 4764/1/1184 +f 3835/1/1185 4507/1/1185 4339/1/1185 +f 3975/1/1186 4087/1/1186 4759/1/1186 +f 3830/1/1187 4502/1/1187 4390/1/1187 +f 4006/1/1188 4678/1/1188 4570/1/1188 +f 3950/1/1189 4034/1/1189 4706/1/1189 +f 3693/1/1190 3861/1/1190 4533/1/1190 +f 3744/1/1191 3856/1/1191 4528/1/1191 +f 3667/1/1192 4339/1/1192 4447/1/1192 +f 4036/1/1193 3924/1/1193 4596/1/1193 +f 4010/1/1194 4682/1/1194 4648/1/1194 +f 3803/1/1195 4475/1/1195 4391/1/1195 +f 3899/1/1196 4571/1/1196 4739/1/1196 +f 3805/1/1197 3693/1/1197 4365/1/1197 +f 4062/1/1198 3950/1/1198 4622/1/1198 +f 3745/1/1199 4417/1/1199 4452/1/1199 +f 3836/1/1200 3668/1/1200 4340/1/1200 +f 4093/1/1201 4765/1/1201 4597/1/1201 +f 3976/1/1202 4648/1/1202 4760/1/1202 +f 3719/1/1203 4391/1/1203 4503/1/1203 +f 4007/1/1204 4679/1/1204 4571/1/1204 +f 3862/1/1205 3694/1/1205 4366/1/1205 +f 3951/1/1206 4623/1/1206 4707/1/1206 +f 3857/1/1207 4529/1/1207 4417/1/1207 +f 3668/1/1208 3776/1/1208 4448/1/1208 +f 3925/1/1209 4597/1/1209 4709/1/1209 +f 3977/1/1210 4002/1/1210 4674/1/1210 +f 3804/1/1211 3720/1/1211 4392/1/1211 +f 4068/1/1212 3900/1/1212 4572/1/1212 +f 3694/1/1213 3806/1/1213 4478/1/1213 +f 4063/1/1214 4735/1/1214 4623/1/1214 +f 3746/1/1215 4418/1/1215 4449/1/1215 +f 3669/1/1216 4341/1/1216 4509/1/1216 +f 3926/1/1217 4598/1/1217 4766/1/1217 +f 4089/1/1218 3977/1/1218 4649/1/1218 +f 3720/1/1219 3832/1/1219 4504/1/1219 +f 3900/1/1220 4000/1/1220 4672/1/1220 +f 3863/1/1221 4535/1/1221 4367/1/1221 +f 3952/1/1222 4036/1/1222 4708/1/1222 +f 3858/1/1223 4530/1/1223 4418/1/1223 +f 3777/1/1224 4449/1/1224 4341/1/1224 +f 4038/1/1225 4710/1/1225 4598/1/1225 +f 3978/1/1226 4011/1/1226 4683/1/1226 +f 3721/1/1227 3805/1/1227 4477/1/1227 +f 4069/1/1228 3901/1/1228 4573/1/1228 +f 3695/1/1229 4367/1/1229 4479/1/1229 +f 4064/1/1230 3952/1/1230 4624/1/1230 +f 3773/1/1231 4445/1/1231 4419/1/1231 +f 3670/1/1232 4342/1/1232 4510/1/1232 +f 3927/1/1233 4599/1/1233 4767/1/1233 +f 4090/1/1234 3978/1/1234 4650/1/1234 +f 3833/1/1235 3721/1/1235 4393/1/1235 +f 3901/1/1236 4008/1/1236 4680/1/1236 +f 3864/1/1237 3696/1/1237 4368/1/1237 +f 4037/1/1238 4709/1/1238 4625/1/1238 +f 3747/1/1239 4419/1/1239 4531/1/1239 +f 3778/1/1240 4450/1/1240 4342/1/1240 +f 4039/1/1241 4711/1/1241 4599/1/1241 +f 3979/1/1242 4651/1/1242 4684/1/1242 +f 3806/1/1243 3722/1/1243 4394/1/1243 +f 3902/1/1244 4574/1/1244 4742/1/1244 +f 3696/1/1245 3808/1/1245 4480/1/1245 +f 3953/1/1246 4625/1/1246 4737/1/1246 +f 3769/1/1247 3748/1/1247 4420/1/1247 +f 3671/1/1248 3839/1/1248 4511/1/1248 +f 4096/1/1249 3928/1/1249 4600/1/1249 +f 4091/1/1250 4763/1/1250 4651/1/1250 +f 3722/1/1251 3834/1/1251 4506/1/1251 +f 4014/1/1252 4686/1/1252 4574/1/1252 +f 3697/1/1253 4369/1/1253 4537/1/1253 +f 3954/1/1254 4626/1/1254 4710/1/1254 +f 3748/1/1255 3860/1/1255 4532/1/1255 +f 3779/1/1256 3671/1/1256 4343/1/1256 +f 3928/1/1257 4040/1/1257 4712/1/1257 +f 3980/1/1258 4013/1/1258 4685/1/1258 +f 3807/1/1259 4479/1/1259 4395/1/1259 +f 3903/1/1260 4575/1/1260 4743/1/1260 +f 3809/1/1261 4481/1/1261 4369/1/1261 +f 4066/1/1262 4738/1/1262 4626/1/1262 +f 3749/1/1263 3779/1/1263 4451/1/1263 +f 3672/1/1264 4344/1/1264 4512/1/1264 +f 4097/1/1265 3929/1/1265 4601/1/1265 +f 4092/1/1266 3980/1/1266 4652/1/1266 +f 3723/1/1267 4395/1/1267 4507/1/1267 +f 4015/1/1268 4687/1/1268 4575/1/1268 +f 3698/1/1269 4370/1/1269 4538/1/1269 +f 3955/1/1270 4627/1/1270 4711/1/1270 +f 3861/1/1271 3749/1/1271 4421/1/1271 +f 4046/1/1272 4718/1/1272 4550/1/1272 +f 3780/1/1273 4452/1/1273 4344/1/1273 +f 3929/1/1274 4041/1/1274 4713/1/1274 +f 3998/1/1275 4670/1/1275 4653/1/1275 +f 3808/1/1276 3724/1/1276 4396/1/1276 +f 4072/1/1277 3904/1/1277 4576/1/1277 +f 3810/1/1278 4482/1/1278 4370/1/1278 +f 4067/1/1279 4739/1/1279 4627/1/1279 +f 3768/1/1280 3750/1/1280 4422/1/1280 +f 3878/1/1281 4550/1/1281 4663/1/1281 +f 3841/1/1282 3673/1/1282 4345/1/1282 +f 3930/1/1283 4602/1/1283 4770/1/1283 +f 3981/1/1284 4653/1/1284 4765/1/1284 +f 3724/1/1285 3836/1/1285 4508/1/1285 +f 3904/1/1286 4016/1/1286 4688/1/1286 +f 3699/1/1287 3867/1/1287 4539/1/1287 +f 4040/1/1288 3956/1/1288 4628/1/1288 +f 3750/1/1289 3862/1/1289 4534/1/1289 +f 3879/1/1290 4047/1/1290 4719/1/1290 +f 3673/1/1291 3781/1/1291 4453/1/1291 +f 4042/1/1292 4714/1/1292 4602/1/1292 +f 3982/1/1293 4654/1/1293 4686/1/1293 +f 3725/1/1294 4397/1/1294 4481/1/1294 +f 4073/1/1295 3905/1/1295 4577/1/1295 +f 3811/1/1296 3699/1/1296 4371/1/1296 +f 3956/1/1297 4068/1/1297 4740/1/1297 +f 3785/1/1298 4457/1/1298 4423/1/1298 +f 4013/1/1299 3879/1/1299 4551/1/1299 +f 3674/1/1300 3842/1/1300 4514/1/1300 +f 3931/1/1301 4603/1/1301 4771/1/1301 +f 4094/1/1302 4766/1/1302 4654/1/1302 +f 3837/1/1303 4509/1/1303 4397/1/1303 +f 3905/1/1304 4017/1/1304 4689/1/1304 +f 3700/1/1305 4372/1/1305 4540/1/1305 +f 4041/1/1306 3957/1/1306 4629/1/1306 +f 3751/1/1307 4423/1/1307 4535/1/1307 +f 3880/1/1308 4552/1/1308 4720/1/1308 +f 3782/1/1309 3674/1/1309 4346/1/1309 +f 4043/1/1310 4715/1/1310 4603/1/1310 +f 3983/1/1311 4655/1/1311 4687/1/1311 +f 3726/1/1312 4398/1/1312 4482/1/1312 +f 4074/1/1313 4746/1/1313 4578/1/1313 +f 3812/1/1314 4484/1/1314 4372/1/1314 +f 3957/1/1315 4069/1/1315 4741/1/1315 +f 3786/1/1316 3752/1/1316 4424/1/1316 +f 4012/1/1317 4684/1/1317 4552/1/1317 +f 3675/1/1318 3843/1/1318 4515/1/1318 +f 4100/1/1319 3932/1/1319 4604/1/1319 +f 4095/1/1320 4767/1/1320 4655/1/1320 +f 3838/1/1321 4510/1/1321 4398/1/1321 +f 3906/1/1322 4578/1/1322 4690/1/1322 +f 3869/1/1323 3701/1/1323 4373/1/1323 +f 3958/1/1324 4630/1/1324 4714/1/1324 +f 3752/1/1325 3864/1/1325 4536/1/1325 +f 3881/1/1326 4049/1/1326 4721/1/1326 +f 3932/1/1327 4044/1/1327 4716/1/1327 +f 3783/1/1328 3675/1/1328 4347/1/1328 +f 4016/1/1329 3984/1/1329 4656/1/1329 +f 3727/1/1330 3811/1/1330 4483/1/1330 +f 3907/1/1331 4075/1/1331 4747/1/1331 +f 4070/1/1332 4742/1/1332 4630/1/1332 +f 3701/1/1333 3813/1/1333 4485/1/1333 +f 3753/1/1334 4425/1/1334 4450/1/1334 +f 4011/1/1335 3881/1/1335 4553/1/1335 +f 4101/1/1336 3933/1/1336 4605/1/1336 +f 3844/1/1337 4516/1/1337 4348/1/1337 +f 3984/1/1338 4096/1/1338 4768/1/1338 +f 3839/1/1339 3727/1/1339 4399/1/1339 +f 4019/1/1340 3907/1/1340 4579/1/1340 +f 3959/1/1341 4631/1/1341 4715/1/1341 +f 3702/1/1342 3870/1/1342 4542/1/1342 +f 3865/1/1343 4537/1/1343 4425/1/1343 +f 4050/1/1344 4722/1/1344 4554/1/1344 +f 3933/1/1345 4045/1/1345 4717/1/1345 +f 3676/1/1346 4348/1/1346 4448/1/1346 +f 4017/1/1347 3985/1/1347 4657/1/1347 +f 3728/1/1348 4400/1/1348 4484/1/1348 +f 3908/1/1349 4580/1/1349 4748/1/1349 +f 4071/1/1350 4743/1/1350 4631/1/1350 +f 3814/1/1351 3702/1/1351 4374/1/1351 +f 3882/1/1352 4554/1/1352 4682/1/1352 +f 3754/1/1353 4426/1/1353 4459/1/1353 +f 4018/1/1354 4690/1/1354 4606/1/1354 +f 3845/1/1355 4517/1/1355 4349/1/1355 +f 3985/1/1356 4097/1/1356 4769/1/1356 +f 3840/1/1357 4512/1/1357 4400/1/1357 +f 4020/1/1358 4692/1/1358 4580/1/1358 +f 4044/1/1359 3960/1/1359 4632/1/1359 +f 3703/1/1360 3871/1/1360 4543/1/1360 +f 4051/1/1361 3883/1/1361 4555/1/1361 +f 3866/1/1362 4538/1/1362 4426/1/1362 +f 3934/1/1363 4606/1/1363 4718/1/1363 +f 3677/1/1364 4349/1/1364 4456/1/1364 +f 3986/1/1365 4658/1/1365 4679/1/1365 +f 3813/1/1366 3729/1/1366 4401/1/1366 +f 3909/1/1367 4077/1/1367 4749/1/1367 +f 3960/1/1368 4072/1/1368 4744/1/1368 +f 3815/1/1369 3703/1/1369 4375/1/1369 +f 3883/1/1370 4009/1/1370 4681/1/1370 +f 3755/1/1371 3788/1/1371 4460/1/1371 +f 3935/1/1372 4019/1/1372 4691/1/1372 +f 3678/1/1373 3846/1/1373 4518/1/1373 +f 4098/1/1374 4770/1/1374 4658/1/1374 +f 3729/1/1375 3841/1/1375 4513/1/1375 +f 4021/1/1376 3909/1/1376 4581/1/1376 +f 4045/1/1377 3961/1/1377 4633/1/1377 +f 3872/1/1378 4544/1/1378 4376/1/1378 +f 4052/1/1379 4724/1/1379 4556/1/1379 +f 3867/1/1380 3755/1/1380 4427/1/1380 +f 4047/1/1381 3935/1/1381 4607/1/1381 +f 3790/1/1382 3678/1/1382 4350/1/1382 +f 3987/1/1383 4659/1/1383 4671/1/1383 +f 3730/1/1384 3814/1/1384 4486/1/1384 +f 4078/1/1385 4750/1/1385 4582/1/1385 +f 3961/1/1386 4073/1/1386 4745/1/1386 +f 3704/1/1387 4376/1/1387 4488/1/1387 +f 3884/1/1388 4556/1/1388 4664/1/1388 +f 3756/1/1389 4428/1/1389 4461/1/1389 +f 3936/1/1390 4608/1/1390 4692/1/1390 +f 3679/1/1391 3847/1/1391 4519/1/1391 +f 4099/1/1392 4771/1/1392 4659/1/1392 +f 3842/1/1393 3730/1/1393 4402/1/1393 +f 3910/1/1394 4582/1/1394 4694/1/1394 +f 4005/1/1395 4677/1/1395 4634/1/1395 +f 3873/1/1396 4545/1/1396 4377/1/1396 +f 3868/1/1397 4540/1/1397 4428/1/1397 +f 3885/1/1398 4053/1/1398 4725/1/1398 +f 4048/1/1399 4720/1/1399 4608/1/1399 +f 3791/1/1400 3679/1/1400 4351/1/1400 +f 4008/1/1401 3988/1/1401 4660/1/1401 +f 3731/1/1402 3815/1/1402 4487/1/1402 +f 3822/1/1403 3654/1/1403 4326/1/1403 +f 4079/1/1404 3911/1/1404 4583/1/1404 +f 3962/1/1405 4634/1/1405 4746/1/1405 +f 3705/1/1406 4377/1/1406 4489/1/1406 +f 4323/1/1407 4211/1/1407 4883/1/1407 +f 4274/1/1408 4946/1/1408 4834/1/1408 +f 4198/1/1409 4310/1/1409 4982/1/1409 +f 4149/1/1410 4261/1/1410 4933/1/1410 +f 4185/1/1411 4857/1/1411 4969/1/1411 +f 4136/1/1412 4248/1/1412 4920/1/1412 +f 4231/1/1413 4123/1/1413 4795/1/1413 +f 4218/1/1414 4890/1/1414 4782/1/1414 +f 4232/1/1415 4904/1/1415 4884/1/1415 +f 4163/1/1416 4247/1/1416 4919/1/1416 +f 4199/1/1417 4233/1/1417 4905/1/1417 +f 4150/1/1418 4318/1/1418 4990/1/1418 +f 4229/1/1419 4186/1/1419 4858/1/1419 +f 4137/1/1420 4809/1/1420 4977/1/1420 +f 4292/1/1421 4964/1/1421 4796/1/1421 +f 4173/1/1422 4845/1/1422 4929/1/1422 +f 4111/1/1423 4279/1/1423 4951/1/1423 +f 4212/1/1424 4884/1/1424 4996/1/1424 +f 4275/1/1425 4163/1/1425 4835/1/1425 +f 4311/1/1426 4199/1/1426 4871/1/1426 +f 4262/1/1427 4150/1/1427 4822/1/1427 +f 4249/1/1428 4921/1/1428 4809/1/1428 +f 4186/1/1429 4298/1/1429 4970/1/1429 +f 4124/1/1430 4796/1/1430 4896/1/1430 +f 4285/1/1431 4957/1/1431 4845/1/1431 +f 4219/1/1432 4111/1/1432 4783/1/1432 +f 4230/1/1433 4902/1/1433 4885/1/1433 +f 4248/1/1434 4164/1/1434 4836/1/1434 +f 4151/1/1435 4319/1/1435 4991/1/1435 +f 4200/1/1436 4872/1/1436 4906/1/1436 +f 4138/1/1437 4810/1/1437 4978/1/1437 +f 4187/1/1438 4859/1/1438 4887/1/1438 +f 4293/1/1439 4965/1/1439 4797/1/1439 +f 4174/1/1440 4846/1/1440 4930/1/1440 +f 4112/1/1441 4784/1/1441 4952/1/1441 +f 4213/1/1442 4885/1/1442 4997/1/1442 +f 4164/1/1443 4276/1/1443 4948/1/1443 +f 4263/1/1444 4151/1/1444 4823/1/1444 +f 4312/1/1445 4984/1/1445 4872/1/1445 +f 4250/1/1446 4922/1/1446 4810/1/1446 +f 4299/1/1447 4971/1/1447 4859/1/1447 +f 4125/1/1448 4797/1/1448 4904/1/1448 +f 4286/1/1449 4958/1/1449 4846/1/1449 +f 4220/1/1450 4892/1/1450 4784/1/1450 +f 4165/1/1451 4837/1/1451 4921/1/1451 +f 4320/1/1452 4992/1/1452 4824/1/1452 +f 4201/1/1453 4873/1/1453 4898/1/1453 +f 4139/1/1454 4307/1/1454 4979/1/1454 +f 4188/1/1455 4214/1/1455 4886/1/1455 +f 4126/1/1456 4294/1/1456 4966/1/1456 +f 4175/1/1457 4259/1/1457 4931/1/1457 +f 4113/1/1458 4281/1/1458 4953/1/1458 +f 4277/1/1459 4949/1/1459 4837/1/1459 +f 4152/1/1460 4824/1/1460 4936/1/1460 +f 4313/1/1461 4985/1/1461 4873/1/1461 +f 4251/1/1462 4139/1/1462 4811/1/1462 +f 4300/1/1463 4188/1/1463 4860/1/1463 +f 4238/1/1464 4126/1/1464 4798/1/1464 +f 4287/1/1465 4175/1/1465 4847/1/1465 +f 4221/1/1466 4113/1/1466 4785/1/1466 +f 4166/1/1467 4838/1/1467 4922/1/1467 +f 4321/1/1468 4993/1/1468 4825/1/1468 +f 4202/1/1469 4874/1/1469 4907/1/1469 +f 4140/1/1470 4812/1/1470 4980/1/1470 +f 4189/1/1471 4861/1/1471 4886/1/1471 +f 4127/1/1472 4295/1/1472 4967/1/1472 +f 4176/1/1473 4848/1/1473 4932/1/1473 +f 4282/1/1474 4114/1/1474 4786/1/1474 +f 4278/1/1475 4950/1/1475 4838/1/1475 +f 4153/1/1476 4825/1/1476 4937/1/1476 +f 4314/1/1477 4986/1/1477 4874/1/1477 +f 4252/1/1478 4924/1/1478 4812/1/1478 +f 4301/1/1479 4973/1/1479 4861/1/1479 +f 4288/1/1480 4960/1/1480 4848/1/1480 +f 4239/1/1481 4127/1/1481 4799/1/1481 +f 4114/1/1482 4222/1/1482 4894/1/1482 +f 4167/1/1483 4251/1/1483 4923/1/1483 +f 4203/1/1484 4236/1/1484 4908/1/1484 +f 4154/1/1485 4322/1/1485 4994/1/1485 +f 4190/1/1486 4862/1/1486 4892/1/1486 +f 4141/1/1487 4309/1/1487 4981/1/1487 +f 4261/1/1488 4177/1/1488 4849/1/1488 +f 4296/1/1489 4968/1/1489 4800/1/1489 +f 4283/1/1490 4955/1/1490 4787/1/1490 +f 4270/1/1491 4102/1/1491 4774/1/1491 +f 4279/1/1492 4167/1/1492 4839/1/1492 +f 4315/1/1493 4203/1/1493 4875/1/1493 +f 4266/1/1494 4154/1/1494 4826/1/1494 +f 4302/1/1495 4974/1/1495 4862/1/1495 +f 4253/1/1496 4141/1/1496 4813/1/1496 +f 4177/1/1497 4289/1/1497 4961/1/1497 +f 4128/1/1498 4800/1/1498 4912/1/1498 +f 4223/1/1499 4115/1/1499 4787/1/1499 +f 4102/1/1500 4215/1/1500 4887/1/1500 +f 4168/1/1501 4840/1/1501 4924/1/1501 +f 4204/1/1502 4876/1/1502 4909/1/1502 +f 4155/1/1503 4323/1/1503 4995/1/1503 +f 4191/1/1504 4219/1/1504 4891/1/1504 +f 4310/1/1505 4142/1/1505 4814/1/1505 +f 4178/1/1506 4262/1/1506 4934/1/1506 +f 4297/1/1507 4969/1/1507 4801/1/1507 +f 4284/1/1508 4116/1/1508 4788/1/1508 +f 4103/1/1509 4775/1/1509 4943/1/1509 +f 4280/1/1510 4952/1/1510 4840/1/1510 +f 4316/1/1511 4988/1/1511 4876/1/1511 +f 4267/1/1512 4155/1/1512 4827/1/1512 +f 4303/1/1513 4191/1/1513 4863/1/1513 +f 4142/1/1514 4254/1/1514 4926/1/1514 +f 4290/1/1515 4178/1/1515 4850/1/1515 +f 4129/1/1516 4801/1/1516 4913/1/1516 +f 4224/1/1517 4896/1/1517 4788/1/1517 +f 4237/1/1518 4909/1/1518 4775/1/1518 +f 4169/1/1519 4253/1/1519 4925/1/1519 +f 4222/1/1520 4205/1/1520 4877/1/1520 +f 4324/1/1521 4996/1/1521 4828/1/1521 +f 4218/1/1522 4192/1/1522 4864/1/1522 +f 4143/1/1523 4311/1/1523 4983/1/1523 +f 4179/1/1524 4263/1/1524 4935/1/1524 +f 4298/1/1525 4130/1/1525 4802/1/1525 +f 4117/1/1526 4789/1/1526 4957/1/1526 +f 4104/1/1527 4272/1/1527 4944/1/1527 +f 4281/1/1528 4169/1/1528 4841/1/1528 +f 4205/1/1529 4317/1/1529 4989/1/1529 +f 4156/1/1530 4828/1/1530 4940/1/1530 +f 4192/1/1531 4304/1/1531 4976/1/1531 +f 4255/1/1532 4143/1/1532 4815/1/1532 +f 4291/1/1533 4179/1/1533 4851/1/1533 +f 4130/1/1534 4242/1/1534 4914/1/1534 +f 4225/1/1535 4897/1/1535 4789/1/1535 +f 4236/1/1536 4104/1/1536 4776/1/1536 +f 4254/1/1537 4170/1/1537 4842/1/1537 +f 4206/1/1538 4238/1/1538 4910/1/1538 +f 4325/1/1539 4997/1/1539 4829/1/1539 +f 4193/1/1540 4865/1/1540 4900/1/1540 +f 4144/1/1541 4816/1/1541 4984/1/1541 +f 4131/1/1542 4803/1/1542 4971/1/1542 +f 4264/1/1543 4936/1/1543 4852/1/1543 +f 4118/1/1544 4790/1/1544 4958/1/1544 +f 4105/1/1545 4777/1/1545 4945/1/1545 +f 4170/1/1546 4282/1/1546 4954/1/1546 +f 4318/1/1547 4206/1/1547 4878/1/1547 +f 4157/1/1548 4829/1/1548 4941/1/1548 +f 4256/1/1549 4928/1/1549 4816/1/1549 +f 4305/1/1550 4977/1/1550 4865/1/1550 +f 4243/1/1551 4915/1/1551 4803/1/1551 +f 4180/1/1552 4852/1/1552 4964/1/1552 +f 4226/1/1553 4898/1/1553 4790/1/1553 +f 4235/1/1554 4907/1/1554 4777/1/1554 +f 4171/1/1555 4255/1/1555 4927/1/1555 +f 4207/1/1556 4239/1/1556 4911/1/1556 +f 4242/1/1557 4158/1/1557 4830/1/1557 +f 4145/1/1558 4817/1/1558 4985/1/1558 +f 4194/1/1559 4866/1/1559 4897/1/1559 +f 4132/1/1560 4300/1/1560 4972/1/1560 +f 4265/1/1561 4937/1/1561 4853/1/1561 +f 4119/1/1562 4287/1/1562 4959/1/1562 +f 4106/1/1563 4778/1/1563 4946/1/1563 +f 4171/1/1564 4843/1/1564 4955/1/1564 +f 4319/1/1565 4207/1/1565 4879/1/1565 +f 4158/1/1566 4270/1/1566 4942/1/1566 +f 4257/1/1567 4929/1/1567 4817/1/1567 +f 4306/1/1568 4978/1/1568 4866/1/1568 +f 4244/1/1569 4132/1/1569 4804/1/1569 +f 4181/1/1570 4853/1/1570 4965/1/1570 +f 4227/1/1571 4119/1/1571 4791/1/1571 +f 4234/1/1572 4906/1/1572 4778/1/1572 +f 4256/1/1573 4172/1/1573 4844/1/1573 +f 4240/1/1574 4912/1/1574 4880/1/1574 +f 4159/1/1575 4831/1/1575 4915/1/1575 +f 4146/1/1576 4818/1/1576 4986/1/1576 +f 4195/1/1577 4221/1/1577 4893/1/1577 +f 4133/1/1578 4805/1/1578 4973/1/1578 +f 4182/1/1579 4266/1/1579 4938/1/1579 +f 4120/1/1580 4792/1/1580 4960/1/1580 +f 4107/1/1581 4275/1/1581 4947/1/1581 +f 4172/1/1582 4284/1/1582 4956/1/1582 +f 4208/1/1583 4880/1/1583 4992/1/1583 +f 4271/1/1584 4943/1/1584 4831/1/1584 +f 4258/1/1585 4930/1/1585 4818/1/1585 +f 4307/1/1586 4195/1/1586 4867/1/1586 +f 4245/1/1587 4917/1/1587 4805/1/1587 +f 4294/1/1588 4182/1/1588 4854/1/1588 +f 4228/1/1589 4900/1/1589 4792/1/1589 +f 4233/1/1590 4107/1/1590 4779/1/1590 +f 4241/1/1591 4913/1/1591 4881/1/1591 +f 4160/1/1592 4244/1/1592 4916/1/1592 +f 4147/1/1593 4315/1/1593 4987/1/1593 +f 4196/1/1594 4868/1/1594 4889/1/1594 +f 4183/1/1595 4267/1/1595 4939/1/1595 +f 4134/1/1596 4806/1/1596 4974/1/1596 +f 4289/1/1597 4121/1/1597 4793/1/1597 +f 4276/1/1598 4108/1/1598 4780/1/1598 +f 4209/1/1599 4881/1/1599 4993/1/1599 +f 4272/1/1600 4160/1/1600 4832/1/1600 +f 4308/1/1601 4980/1/1601 4868/1/1601 +f 4259/1/1602 4147/1/1602 4819/1/1602 +f 4295/1/1603 4183/1/1603 4855/1/1603 +f 4246/1/1604 4918/1/1604 4806/1/1604 +f 4121/1/1605 4229/1/1605 4901/1/1605 +f 4108/1/1606 4216/1/1606 4888/1/1606 +f 4210/1/1607 4231/1/1607 4903/1/1607 +f 4161/1/1608 4833/1/1608 4917/1/1608 +f 4197/1/1609 4227/1/1609 4899/1/1609 +f 4148/1/1610 4820/1/1610 4988/1/1610 +f 4268/1/1611 4940/1/1611 4856/1/1611 +f 4135/1/1612 4303/1/1612 4975/1/1612 +f 4122/1/1613 4290/1/1613 4962/1/1613 +f 4109/1/1614 4781/1/1614 4949/1/1614 +f 4322/1/1615 4210/1/1615 4882/1/1615 +f 4273/1/1616 4945/1/1616 4833/1/1616 +f 4309/1/1617 4197/1/1617 4869/1/1617 +f 4260/1/1618 4932/1/1618 4820/1/1618 +f 4184/1/1619 4856/1/1619 4968/1/1619 +f 4247/1/1620 4135/1/1620 4807/1/1620 +f 4230/1/1621 4122/1/1621 4794/1/1621 +f 4217/1/1622 4889/1/1622 4781/1/1622 +f 4211/1/1623 4223/1/1623 4895/1/1623 +f 4162/1/1624 4834/1/1624 4918/1/1624 +f 4216/1/1625 4198/1/1625 4870/1/1625 +f 4317/1/1626 4149/1/1626 4821/1/1626 +f 4269/1/1627 4941/1/1627 4857/1/1627 +f 4304/1/1628 4136/1/1628 4808/1/1628 +f 4123/1/1629 4291/1/1629 4963/1/1629 +f 4110/1/1630 4782/1/1630 4950/1/1630 +f 4978/1/3 4810/1/3 5009/1/3 +f 4898/1/3 4873/1/3 5029/1/3 +f 4817/1/3 4929/1/3 5046/1/3 +f 4920/1/3 4836/1/3 5016/1/3 +f 4780/1/3 4888/1/3 5034/1/3 +f 4982/1/3 4814/1/3 5010/1/3 +f 4945/1/3 4777/1/3 4999/1/3 +f 4894/1/3 4877/1/3 5031/1/3 +f 4821/1/3 4933/1/3 5048/1/3 +f 4858/1/3 4970/1/3 5057/1/3 +f 4897/1/3 4866/1/3 5027/1/3 +f 4810/1/3 4922/1/3 5044/1/3 +f 4873/1/3 4985/1/3 5062/1/3 +f 4986/1/3 4818/1/3 5012/1/3 +f 4836/1/3 4948/1/3 5051/1/3 +f 4888/1/3 4870/1/3 5028/1/3 +f 4777/1/3 4907/1/3 5040/1/3 +f 4814/1/3 4926/1/3 5045/1/3 +f 4917/1/3 4833/1/3 5015/1/3 +f 4877/1/3 4989/1/3 5064/1/3 +f 4887/1/3 4859/1/3 5023/1/3 +f 4866/1/3 4978/1/3 5060/1/3 +f 4942/1/3 4774/1/3 4998/1/3 +f 4907/1/3 4874/1/3 5030/1/3 +f 4818/1/3 4930/1/3 5047/1/3 +f 4957/1/3 4789/1/3 5003/1/3 +f 4870/1/3 4982/1/3 5061/1/3 +f 4833/1/3 4945/1/3 5050/1/3 +f 4774/1/3 4887/1/3 5033/1/3 +f 4961/1/3 4793/1/3 5005/1/3 +f 4914/1/3 4830/1/3 5014/1/3 +f 4874/1/3 4986/1/3 5063/1/3 +f 4950/1/3 4782/1/3 5001/1/3 +f 4789/1/3 4897/1/3 5037/1/3 +f 4976/1/3 4808/1/3 5008/1/3 +f 4929/1/3 4845/1/3 5019/1/3 +f 4860/1/3 4886/1/3 5032/1/3 +f 4954/1/3 4786/1/3 5002/1/3 +f 4793/1/3 4901/1/3 5039/1/3 +f 4830/1/3 4942/1/3 5049/1/3 +f 4933/1/3 4849/1/3 5021/1/3 +f 4782/1/3 4890/1/3 5035/1/3 +f 4922/1/3 4838/1/3 5017/1/3 +f 4890/1/3 4864/1/3 5026/1/3 +f 4958/1/3 4790/1/3 5004/1/3 +f 4808/1/3 4920/1/3 5043/1/3 +f 4845/1/3 4957/1/3 5054/1/3 +f 4786/1/3 4894/1/3 5036/1/3 +f 4973/1/3 4805/1/3 5007/1/3 +f 4926/1/3 4842/1/3 5018/1/3 +f 4849/1/3 4961/1/3 5056/1/3 +f 4838/1/3 4950/1/3 5052/1/3 +f 4864/1/3 4976/1/3 5059/1/3 +f 4930/1/3 4846/1/3 5020/1/3 +f 4790/1/3 4898/1/3 5038/1/3 +f 4886/1/3 4861/1/3 5025/1/3 +f 4805/1/3 4917/1/3 5042/1/3 +f 4842/1/3 4954/1/3 5053/1/3 +f 4970/1/3 4802/1/3 5006/1/3 +f 4846/1/3 4958/1/3 5055/1/3 +f 4948/1/3 4780/1/3 5000/1/3 +f 4985/1/3 4817/1/3 5011/1/3 +f 4861/1/3 4973/1/3 5058/1/3 +f 4901/1/3 4858/1/3 5022/1/3 +f 4802/1/3 4914/1/3 5041/1/3 +f 4989/1/3 4821/1/3 5013/1/3 +f 1/1/1 6/1/1 10/1/1 +f 19/1/2 18/1/2 13/1/2 +f 16/1/3 17/1/3 5/1/3 +f 20/1/4 12/1/4 9/1/4 +f 2/1/9 12/1/9 3/1/9 +f 13/1/10 15/1/10 11/1/10 +f 16/1/11 5/1/11 14/1/11 +f 6/1/12 1/1/12 4/1/12 +f 15/1/13 18/1/13 16/1/13 +f 8/1/14 6/1/14 7/1/14 +f 19/1/15 13/1/15 20/1/15 +f 1/1/16 10/1/16 2/1/16 +f 11/1/17 14/1/17 3/1/17 +f 3428/1/1631 2771/1/1631 3316/1/1631 +f 3243/1/1632 912/1/1632 3411/1/1632 +f 2712/1/1633 899/1/1633 3402/1/1633 +f 2627/1/1634 1226/1/1634 3391/1/1634 +f 3337/1/1635 2410/1/1635 3211/1/1635 +f 2745/1/1636 1344/1/1636 3423/1/1636 +f 3270/1/1637 1213/1/1637 3382/1/1637 +f 1331/1/1638 2732/1/1638 3302/1/1638 +f 3229/1/1639 834/1/1639 3397/1/1639 +f 3252/1/1640 925/1/1640 3364/1/1640 +f 821/1/1641 2634/1/1641 3226/1/1641 +f 3317/1/1642 1371/1/1642 3334/1/1642 +f 3355/1/1643 2457/1/1643 3243/1/1643 +f 899/1/1644 2444/1/1644 3234/1/1644 +f 3364/1/1645 2470/1/1645 3280/1/1645 +f 2608/1/1646 795/1/1646 3380/1/1646 +f 3271/1/1647 1214/1/1647 3355/1/1647 +f 2444/1/1648 1201/1/1648 3346/1/1648 +f 3303/1/1649 1332/1/1649 3337/1/1649 +f 3336/1/1650 2409/1/1650 3229/1/1650 +f 2739/1/1651 926/1/1651 3421/1/1651 +f 2405/1/1652 821/1/1652 3334/1/1652 +f 3429/1/1653 2772/1/1653 3317/1/1653 +f 2726/1/1654 913/1/1654 3412/1/1654 +f 3403/1/1655 2713/1/1655 3235/1/1655 +f 3280/1/1656 1227/1/1656 3392/1/1656 +f 795/1/1657 2383/1/1657 3212/1/1657 +f 3383/1/1658 2615/1/1658 3271/1/1658 +f 3232/1/1659 848/1/1659 3400/1/1659 +f 1201/1/1660 2602/1/1660 3262/1/1660 +f 3415/1/1661 2733/1/1661 3303/1/1661 +f 926/1/1662 2471/1/1662 3253/1/1662 +f 822/1/1663 2635/1/1663 3227/1/1663 +f 2622/1/1664 809/1/1664 3386/1/1664 +f 913/1/1665 2458/1/1665 3244/1/1665 +f 1359/1/1666 2406/1/1666 3314/1/1666 +f 2471/1/1667 1228/1/1667 3365/1/1667 +f 3235/1/1668 900/1/1668 3347/1/1668 +f 3344/1/1669 2429/1/1669 3232/1/1669 +f 2458/1/1670 1215/1/1670 3356/1/1670 +f 2411/1/1671 1333/1/1671 3338/1/1671 +f 3347/1/1672 2445/1/1672 3263/1/1672 +f 2406/1/1673 822/1/1673 3335/1/1673 +f 809/1/1674 2394/1/1674 3218/1/1674 +f 914/1/1675 2727/1/1675 3245/1/1675 +f 2760/1/1676 1359/1/1676 3426/1/1676 +f 901/1/1677 2714/1/1677 3236/1/1677 +f 1228/1/1678 2629/1/1678 3281/1/1678 +f 3233/1/1679 849/1/1679 3401/1/1679 +f 1215/1/1680 2616/1/1680 3272/1/1680 +f 1333/1/1681 2734/1/1681 3304/1/1681 +f 3263/1/1682 1202/1/1682 3375/1/1682 +f 3219/1/1683 810/1/1683 3387/1/1683 +f 2459/1/1684 914/1/1684 3357/1/1684 +f 1360/1/1685 2395/1/1685 3315/1/1685 +f 2446/1/1686 901/1/1686 3348/1/1686 +f 3345/1/1687 2430/1/1687 3233/1/1687 +f 1216/1/1688 2459/1/1688 3273/1/1688 +f 3330/1/1689 2398/1/1689 3305/1/1689 +f 1203/1/1690 2446/1/1690 3264/1/1690 +f 3327/1/1691 2395/1/1691 3219/1/1691 +f 2761/1/1692 1360/1/1692 3427/1/1692 +f 3405/1/1693 2715/1/1693 3237/1/1693 +f 2617/1/1694 1216/1/1694 3385/1/1694 +f 3305/1/1695 1334/1/1695 3417/1/1695 +f 837/1/1696 2650/1/1696 3230/1/1696 +f 2604/1/1697 1203/1/1697 3376/1/1697 +f 2624/1/1698 811/1/1698 3388/1/1698 +f 3237/1/1699 902/1/1699 3349/1/1699 +f 3339/1/1700 2412/1/1700 3306/1/1700 +f 2418/1/1701 837/1/1701 3342/1/1701 +f 3349/1/1702 2447/1/1702 3265/1/1702 +f 3332/1/1703 2400/1/1703 3297/1/1703 +f 811/1/1704 2396/1/1704 3220/1/1704 +f 2716/1/1705 903/1/1705 3406/1/1705 +f 3306/1/1706 1335/1/1706 3418/1/1706 +f 838/1/1707 2651/1/1707 3231/1/1707 +f 3265/1/1708 1204/1/1708 3377/1/1708 +f 3297/1/1709 1322/1/1709 3409/1/1709 +f 3389/1/1710 2625/1/1710 3221/1/1710 +f 903/1/1711 2448/1/1711 3238/1/1711 +f 1336/1/1712 2413/1/1712 3307/1/1712 +f 2419/1/1713 838/1/1713 3343/1/1713 +f 2448/1/1714 1205/1/1714 3350/1/1714 +f 3256/1/1715 943/1/1715 3424/1/1715 +f 3329/1/1716 2397/1/1716 3298/1/1716 +f 3221/1/1717 812/1/1717 3329/1/1717 +f 3239/1/1718 904/1/1718 3407/1/1718 +f 2737/1/1719 1336/1/1719 3419/1/1719 +f 1205/1/1720 2606/1/1720 3266/1/1720 +f 3368/1/1721 2488/1/1721 3256/1/1721 +f 3298/1/1722 1323/1/1722 3410/1/1722 +f 3390/1/1723 2626/1/1723 3222/1/1723 +f 3284/1/1724 1245/1/1724 3368/1/1724 +f 3351/1/1725 2449/1/1725 3239/1/1725 +f 3381/1/1726 2613/1/1726 3213/1/1726 +f 3341/1/1727 2414/1/1727 3308/1/1727 +f 3267/1/1728 1206/1/1728 3351/1/1728 +f 3257/1/1729 944/1/1729 3425/1/1729 +f 931/1/1730 2744/1/1730 3254/1/1730 +f 1324/1/1731 2392/1/1731 3299/1/1731 +f 3396/1/1732 2646/1/1732 3284/1/1732 +f 2401/1/1733 1311/1/1733 3333/1/1733 +f 3222/1/1734 813/1/1734 3330/1/1734 +f 2718/1/1735 905/1/1735 3408/1/1735 +f 3213/1/1736 800/1/1736 3321/1/1736 +f 3308/1/1737 1337/1/1737 3420/1/1737 +f 3379/1/1738 2607/1/1738 3267/1/1738 +f 3369/1/1739 2489/1/1739 3257/1/1739 +f 2476/1/1740 931/1/1740 3366/1/1740 +f 3411/1/1741 2725/1/1741 3299/1/1741 +f 3285/1/1742 1246/1/1742 3369/1/1742 +f 1311/1/1743 2712/1/1743 3290/1/1743 +f 814/1/1744 2627/1/1744 3223/1/1744 +f 905/1/1745 2450/1/1745 3240/1/1745 +f 1233/1/1746 2476/1/1746 3282/1/1746 +f 3382/1/1747 2614/1/1747 3214/1/1747 +f 3260/1/1748 958/1/1748 3428/1/1748 +f 2394/1/1749 1338/1/1749 3326/1/1749 +f 2450/1/1750 1207/1/1750 3352/1/1750 +f 932/1/1751 2745/1/1751 3255/1/1751 +f 3321/1/1752 2388/1/1752 3300/1/1752 +f 2732/1/1753 919/1/1753 3414/1/1753 +f 3397/1/1754 2647/1/1754 3285/1/1754 +f 3319/1/1755 2382/1/1755 3291/1/1755 +f 2399/1/1756 814/1/1756 3331/1/1756 +f 2634/1/1757 1233/1/1757 3394/1/1757 +f 3214/1/1758 801/1/1758 3322/1/1758 +f 3372/1/1759 2503/1/1759 3260/1/1759 +f 1338/1/1760 2739/1/1760 3309/1/1760 +f 1207/1/1761 2608/1/1761 3268/1/1761 +f 2477/1/1762 932/1/1762 3367/1/1762 +f 3288/1/1763 1260/1/1763 3372/1/1763 +f 1325/1/1764 2726/1/1764 3300/1/1764 +f 919/1/1765 2464/1/1765 3246/1/1765 +f 3291/1/1766 1312/1/1766 3403/1/1766 +f 3392/1/1767 2628/1/1767 3224/1/1767 +f 1234/1/1768 2477/1/1768 3283/1/1768 +f 3215/1/1769 802/1/1769 3383/1/1769 +f 2464/1/1770 1221/1/1770 3358/1/1770 +f 3261/1/1771 959/1/1771 3429/1/1771 +f 2602/1/1772 789/1/1772 3374/1/1772 +f 3400/1/1773 2661/1/1773 3288/1/1773 +f 1326/1/1774 2399/1/1774 3301/1/1774 +f 3247/1/1775 920/1/1775 3415/1/1775 +f 1313/1/1776 2381/1/1776 3292/1/1776 +f 3224/1/1777 815/1/1777 3332/1/1777 +f 2635/1/1778 1234/1/1778 3395/1/1778 +f 3323/1/1779 2390/1/1779 3215/1/1779 +f 1221/1/1780 2622/1/1780 3274/1/1780 +f 3373/1/1781 2504/1/1781 3261/1/1781 +f 789/1/1782 2382/1/1782 3206/1/1782 +f 3289/1/1783 1261/1/1783 3373/1/1783 +f 2727/1/1784 1326/1/1784 3413/1/1784 +f 2714/1/1785 1313/1/1785 3404/1/1785 +f 2629/1/1786 816/1/1786 3393/1/1786 +f 3359/1/1787 2465/1/1787 3247/1/1787 +f 2616/1/1788 803/1/1788 3384/1/1788 +f 3375/1/1789 2603/1/1789 3207/1/1789 +f 3275/1/1790 1222/1/1790 3359/1/1790 +f 947/1/1791 2760/1/1791 3258/1/1791 +f 3401/1/1792 2662/1/1792 3289/1/1792 +f 3318/1/1793 2381/1/1793 3293/1/1793 +f 816/1/1794 2401/1/1794 3225/1/1794 +f 2734/1/1795 921/1/1795 3416/1/1795 +f 803/1/1796 2391/1/1796 3216/1/1796 +f 3207/1/1797 790/1/1797 3341/1/1797 +f 3387/1/1798 2623/1/1798 3275/1/1798 +f 2492/1/1799 947/1/1799 3370/1/1799 +f 3293/1/1800 1314/1/1800 3405/1/1800 +f 921/1/1801 2466/1/1801 3248/1/1801 +f 1249/1/1802 2492/1/1802 3286/1/1802 +f 804/1/1803 2617/1/1803 3217/1/1803 +f 791/1/1804 2604/1/1804 3208/1/1804 +f 2466/1/1805 1223/1/1805 3360/1/1805 +f 948/1/1806 2761/1/1806 3259/1/1806 +f 2391/1/1807 1315/1/1807 3324/1/1807 +f 3417/1/1808 2735/1/1808 3249/1/1808 +f 2650/1/1809 1249/1/1809 3398/1/1809 +f 2392/1/1810 804/1/1810 3325/1/1810 +f 2413/1/1811 791/1/1811 3340/1/1811 +f 1223/1/1812 2624/1/1812 3276/1/1812 +f 2493/1/1813 948/1/1813 3371/1/1813 +f 3249/1/1814 922/1/1814 3361/1/1814 +f 1250/1/1815 2493/1/1815 3287/1/1815 +f 1315/1/1816 2716/1/1816 3294/1/1816 +f 3312/1/1817 1355/1/1817 3344/1/1817 +f 3377/1/1818 2605/1/1818 3209/1/1818 +f 3361/1/1819 2467/1/1819 3277/1/1819 +f 3418/1/1820 2736/1/1820 3250/1/1820 +f 2651/1/1821 1250/1/1821 3399/1/1821 +f 3295/1/1822 1316/1/1822 3323/1/1822 +f 3409/1/1823 2723/1/1823 3241/1/1823 +f 3424/1/1824 2756/1/1824 3312/1/1824 +f 3209/1/1825 792/1/1825 3339/1/1825 +f 3277/1/1826 1224/1/1826 3389/1/1826 +f 3250/1/1827 923/1/1827 3362/1/1827 +f 3407/1/1828 2717/1/1828 3295/1/1828 +f 3241/1/1829 910/1/1829 3353/1/1829 +f 3313/1/1830 1356/1/1830 3345/1/1830 +f 2606/1/1831 793/1/1831 3378/1/1831 +f 3362/1/1832 2468/1/1832 3278/1/1832 +f 1343/1/1833 2418/1/1833 3310/1/1833 +f 3353/1/1834 2455/1/1834 3269/1/1834 +f 924/1/1835 2737/1/1835 3251/1/1835 +f 2389/1/1836 1317/1/1836 3322/1/1836 +f 3410/1/1837 2724/1/1837 3242/1/1837 +f 3425/1/1838 2757/1/1838 3313/1/1838 +f 3278/1/1839 1225/1/1839 3390/1/1839 +f 793/1/1840 2411/1/1840 3210/1/1840 +f 2744/1/1841 1343/1/1841 3422/1/1841 +f 3269/1/1842 1212/1/1842 3381/1/1842 +f 3228/1/1843 833/1/1843 3396/1/1843 +f 2469/1/1844 924/1/1844 3363/1/1844 +f 1317/1/1845 2718/1/1845 3296/1/1845 +f 3316/1/1846 1370/1/1846 3336/1/1846 +f 3242/1/1847 911/1/1847 3354/1/1847 +f 1226/1/1848 2469/1/1848 3279/1/1848 +f 3211/1/1849 794/1/1849 3379/1/1849 +f 1344/1/1850 2419/1/1850 3311/1/1850 +f 3354/1/1851 2456/1/1851 3270/1/1851 +f 2383/1/1852 1331/1/1852 3320/1/1852 +f 3328/1/1853 2396/1/1853 3228/1/1853 +f 3420/1/1854 2738/1/1854 3252/1/1854 +f 3384/1/1855 3216/1/1855 3608/1/1855 +f 3281/1/1856 3393/1/1856 3505/1/1856 +f 3268/1/1857 3380/1/1857 3492/1/1857 +f 3367/1/1858 3255/1/1858 3591/1/1858 +f 3565/1/1859 3341/1/1859 3532/1/1859 +f 3466/1/1860 3242/1/1860 3578/1/1860 +f 3560/1/1861 3336/1/1861 3453/1/1861 +f 3519/1/1862 3295/1/1862 3547/1/1862 +f 3216/1/1863 3324/1/1863 3440/1/1863 +f 3282/1/1864 3366/1/1864 3506/1/1864 +f 3577/1/1865 3353/1/1865 3493/1/1865 +f 3480/1/1866 3256/1/1866 3648/1/1866 +f 3532/1/1867 3308/1/1867 3644/1/1867 +f 3467/1/1868 3243/1/1868 3635/1/1868 +f 3230/1/1869 3398/1/1869 3454/1/1869 +f 3631/1/1870 3407/1/1870 3519/1/1870 +f 3217/1/1871 3385/1/1871 3441/1/1871 +f 3394/1/1872 3282/1/1872 3618/1/1872 +f 3493/1/1873 3269/1/1873 3605/1/1873 +f 3592/1/1874 3368/1/1874 3480/1/1874 +f 3326/1/1875 3309/1/1875 3550/1/1875 +f 3579/1/1876 3355/1/1876 3467/1/1876 +f 3342/1/1877 3230/1/1877 3566/1/1877 +f 3322/1/1878 3296/1/1878 3546/1/1878 +f 3325/1/1879 3217/1/1879 3549/1/1879 +f 3283/1/1880 3367/1/1880 3507/1/1880 +f 3578/1/1881 3354/1/1881 3494/1/1881 +f 3481/1/1882 3257/1/1882 3649/1/1882 +f 3309/1/1883 3421/1/1883 3533/1/1883 +f 3412/1/1884 3244/1/1884 3636/1/1884 +f 3231/1/1885 3399/1/1885 3455/1/1885 +f 3296/1/1886 3408/1/1886 3520/1/1886 +f 3386/1/1887 3218/1/1887 3610/1/1887 +f 3395/1/1888 3283/1/1888 3619/1/1888 +f 3494/1/1889 3270/1/1889 3606/1/1889 +f 3593/1/1890 3369/1/1890 3481/1/1890 +f 3310/1/1891 3342/1/1891 3534/1/1891 +f 3244/1/1892 3356/1/1892 3468/1/1892 +f 3343/1/1893 3231/1/1893 3567/1/1893 +f 3556/1/1894 3332/1/1894 3521/1/1894 +f 3218/1/1895 3326/1/1895 3442/1/1895 +f 3508/1/1896 3284/1/1896 3592/1/1896 +f 3495/1/1897 3271/1/1897 3579/1/1897 +f 3258/1/1898 3426/1/1898 3482/1/1898 +f 3422/1/1899 3310/1/1899 3646/1/1899 +f 3245/1/1900 3413/1/1900 3469/1/1900 +f 3456/1/1901 3232/1/1901 3624/1/1901 +f 3521/1/1902 3297/1/1902 3633/1/1902 +f 3443/1/1903 3219/1/1903 3611/1/1903 +f 3620/1/1904 3396/1/1904 3508/1/1904 +f 3374/1/1905 3206/1/1905 3598/1/1905 +f 3607/1/1906 3383/1/1906 3495/1/1906 +f 3370/1/1907 3258/1/1907 3594/1/1907 +f 3311/1/1908 3343/1/1908 3535/1/1908 +f 3357/1/1909 3245/1/1909 3581/1/1909 +f 3568/1/1910 3344/1/1910 3456/1/1910 +f 3553/1/1911 3329/1/1911 3522/1/1911 +f 3551/1/1912 3327/1/1912 3443/1/1912 +f 3509/1/1913 3285/1/1913 3593/1/1913 +f 3206/1/1914 3319/1/1914 3430/1/1914 +f 3356/1/1915 3272/1/1915 3580/1/1915 +f 3259/1/1916 3427/1/1916 3483/1/1916 +f 3423/1/1917 3311/1/1917 3647/1/1917 +f 3414/1/1918 3246/1/1918 3638/1/1918 +f 3457/1/1919 3233/1/1919 3625/1/1919 +f 3522/1/1920 3298/1/1920 3634/1/1920 +f 3388/1/1921 3220/1/1921 3612/1/1921 +f 3621/1/1922 3397/1/1922 3509/1/1922 +f 3272/1/1923 3384/1/1923 3496/1/1923 +f 3599/1/1924 3375/1/1924 3431/1/1924 +f 3371/1/1925 3259/1/1925 3595/1/1925 +f 3536/1/1926 3312/1/1926 3568/1/1926 +f 3246/1/1927 3358/1/1927 3470/1/1927 +f 3569/1/1928 3345/1/1928 3457/1/1928 +f 3523/1/1929 3299/1/1929 3549/1/1929 +f 3286/1/1930 3370/1/1930 3510/1/1930 +f 3220/1/1931 3328/1/1931 3444/1/1931 +f 3273/1/1932 3357/1/1932 3497/1/1932 +f 3431/1/1933 3207/1/1933 3565/1/1933 +f 3484/1/1934 3260/1/1934 3652/1/1934 +f 3648/1/1935 3424/1/1935 3536/1/1935 +f 3471/1/1936 3247/1/1936 3639/1/1936 +f 3635/1/1937 3411/1/1937 3523/1/1937 +f 3402/1/1938 3234/1/1938 3626/1/1938 +f 3398/1/1939 3286/1/1939 3622/1/1939 +f 3613/1/1940 3389/1/1940 3445/1/1940 +f 3385/1/1941 3273/1/1941 3609/1/1941 +f 3208/1/1942 3376/1/1942 3432/1/1942 +f 3596/1/1943 3372/1/1943 3484/1/1943 +f 3537/1/1944 3313/1/1944 3569/1/1944 +f 3583/1/1945 3359/1/1945 3471/1/1945 +f 3321/1/1946 3300/1/1946 3545/1/1946 +f 3234/1/1947 3346/1/1947 3458/1/1947 +f 3287/1/1948 3371/1/1948 3511/1/1948 +f 3445/1/1949 3221/1/1949 3553/1/1949 +f 3340/1/1950 3208/1/1950 3564/1/1950 +f 3358/1/1951 3274/1/1951 3582/1/1951 +f 3485/1/1952 3261/1/1952 3653/1/1952 +f 3649/1/1953 3425/1/1953 3537/1/1953 +f 3416/1/1954 3248/1/1954 3640/1/1954 +f 3300/1/1955 3412/1/1955 3524/1/1955 +f 3627/1/1956 3403/1/1956 3459/1/1956 +f 3614/1/1957 3390/1/1957 3446/1/1957 +f 3399/1/1958 3287/1/1958 3623/1/1958 +f 3601/1/1959 3377/1/1959 3433/1/1959 +f 3274/1/1960 3386/1/1960 3498/1/1960 +f 3597/1/1961 3373/1/1961 3485/1/1961 +f 3314/1/1962 3335/1/1962 3538/1/1962 +f 3248/1/1963 3360/1/1963 3472/1/1963 +f 3459/1/1964 3235/1/1964 3571/1/1964 +f 3301/1/1965 3331/1/1965 3525/1/1965 +f 3446/1/1966 3222/1/1966 3554/1/1966 +f 3512/1/1967 3288/1/1967 3596/1/1967 +f 3433/1/1968 3209/1/1968 3563/1/1968 +f 3499/1/1969 3275/1/1969 3583/1/1969 +f 3346/1/1970 3262/1/1970 3570/1/1970 +f 3426/1/1971 3314/1/1971 3650/1/1971 +f 3641/1/1972 3417/1/1972 3473/1/1972 +f 3236/1/1973 3404/1/1973 3460/1/1973 +f 3413/1/1974 3301/1/1974 3637/1/1974 +f 3223/1/1975 3391/1/1975 3447/1/1975 +f 3624/1/1976 3400/1/1976 3512/1/1976 +f 3378/1/1977 3210/1/1977 3602/1/1977 +f 3611/1/1978 3387/1/1978 3499/1/1978 +f 3262/1/1979 3374/1/1979 3486/1/1979 +f 3315/1/1980 3327/1/1980 3539/1/1980 +f 3473/1/1981 3249/1/1981 3585/1/1981 +f 3348/1/1982 3236/1/1982 3572/1/1982 +f 3320/1/1983 3302/1/1983 3544/1/1983 +f 3331/1/1984 3223/1/1984 3555/1/1984 +f 3513/1/1985 3289/1/1985 3597/1/1985 +f 3210/1/1986 3338/1/1986 3434/1/1986 +f 3360/1/1987 3276/1/1987 3584/1/1987 +f 3571/1/1988 3347/1/1988 3487/1/1988 +f 3427/1/1989 3315/1/1989 3651/1/1989 +f 3642/1/1990 3418/1/1990 3474/1/1990 +f 3629/1/1991 3405/1/1991 3461/1/1991 +f 3302/1/1992 3414/1/1992 3526/1/1992 +f 3616/1/1993 3392/1/1993 3448/1/1993 +f 3625/1/1994 3401/1/1994 3513/1/1994 +f 3435/1/1995 3211/1/1995 3603/1/1995 +f 3276/1/1996 3388/1/1996 3500/1/1996 +f 3487/1/1997 3263/1/1997 3599/1/1997 +f 3540/1/1998 3316/1/1998 3560/1/1998 +f 3474/1/1999 3250/1/1999 3586/1/1999 +f 3461/1/2000 3237/1/2000 3573/1/2000 +f 3527/1/2001 3303/1/2001 3561/1/2001 +f 3448/1/2002 3224/1/2002 3556/1/2002 +f 3333/1/2003 3290/1/2003 3557/1/2003 +f 3561/1/2004 3337/1/2004 3435/1/2004 +f 3585/1/2005 3361/1/2005 3501/1/2005 +f 3264/1/2006 3348/1/2006 3488/1/2006 +f 3652/1/2007 3428/1/2007 3540/1/2007 +f 3251/1/2008 3419/1/2008 3475/1/2008 +f 3406/1/2009 3238/1/2009 3630/1/2009 +f 3639/1/2010 3415/1/2010 3527/1/2010 +f 3393/1/2011 3225/1/2011 3617/1/2011 +f 3290/1/2012 3402/1/2012 3514/1/2012 +f 3380/1/2013 3212/1/2013 3604/1/2013 +f 3501/1/2014 3277/1/2014 3613/1/2014 +f 3376/1/2015 3264/1/2015 3600/1/2015 +f 3541/1/2016 3317/1/2016 3558/1/2016 +f 3363/1/2017 3251/1/2017 3587/1/2017 +f 3238/1/2018 3350/1/2018 3462/1/2018 +f 3338/1/2019 3304/1/2019 3562/1/2019 +f 3225/1/2020 3333/1/2020 3449/1/2020 +f 3543/1/2021 3319/1/2021 3515/1/2021 +f 3212/1/2022 3320/1/2022 3436/1/2022 +f 3586/1/2023 3362/1/2023 3502/1/2023 +f 3573/1/2024 3349/1/2024 3489/1/2024 +f 3653/1/2025 3429/1/2025 3541/1/2025 +f 3644/1/2026 3420/1/2026 3476/1/2026 +f 3463/1/2027 3239/1/2027 3631/1/2027 +f 3304/1/2028 3416/1/2028 3528/1/2028 +f 3226/1/2029 3394/1/2029 3450/1/2029 +f 3515/1/2030 3291/1/2030 3627/1/2030 +f 3605/1/2031 3381/1/2031 3437/1/2031 +f 3502/1/2032 3278/1/2032 3614/1/2032 +f 3489/1/2033 3265/1/2033 3601/1/2033 +f 3476/1/2034 3252/1/2034 3588/1/2034 +f 3575/1/2035 3351/1/2035 3463/1/2035 +f 3554/1/2036 3330/1/2036 3529/1/2036 +f 3334/1/2037 3226/1/2037 3558/1/2037 +f 3292/1/2038 3318/1/2038 3516/1/2038 +f 3437/1/2039 3213/1/2039 3545/1/2039 +f 3279/1/2040 3363/1/2040 3503/1/2040 +f 3350/1/2041 3266/1/2041 3574/1/2041 +f 3421/1/2042 3253/1/2042 3645/1/2042 +f 3408/1/2043 3240/1/2043 3632/1/2043 +f 3529/1/2044 3305/1/2044 3641/1/2044 +f 3404/1/2045 3292/1/2045 3628/1/2045 +f 3227/1/2046 3395/1/2046 3451/1/2046 +f 3391/1/2047 3279/1/2047 3615/1/2047 +f 3606/1/2048 3382/1/2048 3438/1/2048 +f 3266/1/2049 3378/1/2049 3490/1/2049 +f 3253/1/2050 3365/1/2050 3477/1/2050 +f 3563/1/2051 3339/1/2051 3530/1/2051 +f 3240/1/2052 3352/1/2052 3464/1/2052 +f 3542/1/2053 3318/1/2053 3517/1/2053 +f 3335/1/2054 3227/1/2054 3559/1/2054 +f 3588/1/2055 3364/1/2055 3504/1/2055 +f 3438/1/2056 3214/1/2056 3546/1/2056 +f 3491/1/2057 3267/1/2057 3575/1/2057 +f 3254/1/2058 3422/1/2058 3478/1/2058 +f 3530/1/2059 3306/1/2059 3642/1/2059 +f 3633/1/2060 3409/1/2060 3465/1/2060 +f 3517/1/2061 3293/1/2061 3629/1/2061 +f 3452/1/2062 3228/1/2062 3620/1/2062 +f 3504/1/2063 3280/1/2063 3616/1/2063 +f 3439/1/2064 3215/1/2064 3607/1/2064 +f 3603/1/2065 3379/1/2065 3491/1/2065 +f 3366/1/2066 3254/1/2066 3590/1/2066 +f 3307/1/2067 3340/1/2067 3531/1/2067 +f 3465/1/2068 3241/1/2068 3577/1/2068 +f 3552/1/2069 3328/1/2069 3452/1/2069 +f 3324/1/2070 3294/1/2070 3548/1/2070 +f 3547/1/2071 3323/1/2071 3439/1/2071 +f 3365/1/2072 3281/1/2072 3589/1/2072 +f 3352/1/2073 3268/1/2073 3576/1/2073 +f 3255/1/2074 3423/1/2074 3479/1/2074 +f 3419/1/2075 3307/1/2075 3643/1/2075 +f 3634/1/2076 3410/1/2076 3466/1/2076 +f 3453/1/2077 3229/1/2077 3621/1/2077 +f 3294/1/2078 3406/1/2078 3518/1/2078 +f 3669/1/2079 3445/1/2079 3777/1/2079 +f 3511/1/467 3595/1/467 3735/1/467 +f 3564/1/468 3432/1/468 3788/1/468 +f 3582/1/2080 3498/1/2080 3806/1/2080 +f 3709/1/470 3485/1/470 3877/1/470 +f 3873/1/471 3649/1/471 3761/1/471 +f 3640/1/472 3472/1/472 3864/1/472 +f 3851/1/473 3627/1/473 3683/1/473 +f 3524/1/474 3636/1/474 3748/1/474 +f 3838/1/475 3614/1/475 3670/1/475 +f 3623/1/476 3511/1/476 3847/1/476 +f 3825/1/477 3601/1/477 3657/1/477 +f 3498/1/2081 3610/1/2081 3722/1/2081 +f 3821/1/479 3597/1/479 3709/1/479 +f 3538/1/480 3559/1/480 3762/1/480 +f 3472/1/481 3584/1/481 3696/1/481 +f 3683/1/482 3459/1/482 3795/1/482 +f 3525/1/483 3555/1/483 3749/1/483 +f 3670/1/484 3446/1/484 3778/1/484 +f 3736/1/485 3512/1/485 3820/1/485 +f 3657/1/486 3433/1/486 3787/1/486 +f 3723/1/487 3499/1/487 3807/1/487 +f 3570/1/488 3486/1/488 3794/1/488 +f 3650/1/489 3538/1/489 3874/1/489 +f 3865/1/2082 3641/1/2082 3697/1/2082 +f 3460/1/490 3628/1/490 3684/1/490 +f 3637/1/491 3525/1/491 3861/1/491 +f 3447/1/492 3615/1/492 3671/1/492 +f 3848/1/2083 3624/1/2083 3736/1/2083 +f 3602/1/494 3434/1/494 3826/1/494 +f 3835/1/495 3611/1/495 3723/1/495 +f 3486/1/496 3598/1/496 3710/1/496 +f 3539/1/497 3551/1/497 3763/1/497 +f 3697/1/2084 3473/1/2084 3809/1/2084 +f 3572/1/499 3460/1/499 3796/1/499 +f 3544/1/2085 3526/1/2085 3768/1/2085 +f 3555/1/501 3447/1/501 3779/1/501 +f 3737/1/502 3513/1/502 3821/1/502 +f 3434/1/503 3562/1/503 3658/1/503 +f 3584/1/504 3500/1/504 3808/1/504 +f 3795/1/505 3571/1/505 3711/1/505 +f 3651/1/506 3539/1/506 3875/1/506 +f 3866/1/507 3642/1/507 3698/1/507 +f 3853/1/508 3629/1/508 3685/1/508 +f 3526/1/2086 3638/1/2086 3750/1/2086 +f 3840/1/510 3616/1/510 3672/1/510 +f 3849/1/511 3625/1/511 3737/1/511 +f 3659/1/512 3435/1/512 3827/1/512 +f 3500/1/513 3612/1/513 3724/1/513 +f 3711/1/514 3487/1/514 3823/1/514 +f 3764/1/515 3540/1/515 3784/1/515 +f 3698/1/516 3474/1/516 3810/1/516 +f 3685/1/2087 3461/1/2087 3797/1/2087 +f 3751/1/518 3527/1/518 3785/1/518 +f 3672/1/519 3448/1/519 3780/1/519 +f 3557/1/520 3514/1/520 3781/1/520 +f 3785/1/521 3561/1/521 3659/1/521 +f 3809/1/2088 3585/1/2088 3725/1/2088 +f 3488/1/523 3572/1/523 3712/1/523 +f 3876/1/524 3652/1/524 3764/1/524 +f 3475/1/525 3643/1/525 3699/1/525 +f 3630/1/526 3462/1/526 3854/1/526 +f 3863/1/527 3639/1/527 3751/1/527 +f 3617/1/528 3449/1/528 3841/1/528 +f 3514/1/529 3626/1/529 3738/1/529 +f 3604/1/2089 3436/1/2089 3828/1/2089 +f 3725/1/2090 3501/1/2090 3837/1/2090 +f 3600/1/532 3488/1/532 3824/1/532 +f 3765/1/533 3541/1/533 3782/1/533 +f 3587/1/534 3475/1/534 3811/1/534 +f 3462/1/535 3574/1/535 3686/1/535 +f 3562/1/536 3528/1/536 3786/1/536 +f 3449/1/537 3557/1/537 3673/1/537 +f 3767/1/538 3543/1/538 3739/1/538 +f 3810/1/539 3586/1/539 3726/1/539 +f 3436/1/2091 3544/1/2091 3660/1/2091 +f 3797/1/541 3573/1/541 3713/1/541 +f 3877/1/542 3653/1/542 3765/1/542 +f 3868/1/543 3644/1/543 3700/1/543 +f 3687/1/544 3463/1/544 3855/1/544 +f 3528/1/545 3640/1/545 3752/1/545 +f 3739/1/546 3515/1/546 3851/1/546 +f 3450/1/547 3618/1/547 3674/1/547 +f 3726/1/548 3502/1/548 3838/1/548 +f 3605/1/549 3437/1/549 3829/1/549 +f 3713/1/550 3489/1/550 3825/1/550 +f 3700/1/551 3476/1/551 3812/1/551 +f 3778/1/552 3554/1/552 3753/1/552 +f 3799/1/553 3575/1/553 3687/1/553 +f 3516/1/554 3542/1/554 3740/1/554 +f 3782/1/555 3558/1/555 3674/1/555 +f 3503/1/556 3587/1/556 3727/1/556 +f 3437/1/557 3545/1/557 3661/1/557 +f 3574/1/558 3490/1/558 3798/1/558 +f 3645/1/559 3477/1/559 3869/1/559 +f 3753/1/560 3529/1/560 3865/1/560 +f 3632/1/2092 3464/1/2092 3856/1/2092 +f 3628/1/562 3516/1/562 3852/1/562 +f 3451/1/563 3619/1/563 3675/1/563 +f 3830/1/2093 3606/1/2093 3662/1/2093 +f 3615/1/565 3503/1/565 3839/1/565 +f 3490/1/566 3602/1/566 3714/1/566 +f 3477/1/559 3589/1/559 3701/1/559 +f 3787/1/567 3563/1/567 3754/1/567 +f 3464/1/2094 3576/1/2094 3688/1/2094 +f 3559/1/569 3451/1/569 3783/1/569 +f 3766/1/570 3542/1/570 3741/1/570 +f 3438/1/2095 3546/1/2095 3662/1/2095 +f 3812/1/572 3588/1/572 3728/1/572 +f 3715/1/573 3491/1/573 3799/1/573 +f 3478/1/574 3646/1/574 3702/1/574 +f 3857/1/575 3633/1/575 3689/1/575 +f 3754/1/576 3530/1/576 3866/1/576 +f 3676/1/577 3452/1/577 3844/1/577 +f 3741/1/578 3517/1/578 3853/1/578 +f 3663/1/579 3439/1/579 3831/1/579 +f 3728/1/580 3504/1/580 3840/1/580 +f 3827/1/581 3603/1/581 3715/1/581 +f 3590/1/582 3478/1/582 3814/1/582 +f 3531/1/583 3564/1/583 3755/1/583 +f 3689/1/584 3465/1/584 3801/1/584 +f 3776/1/585 3552/1/585 3676/1/585 +f 3548/1/586 3518/1/586 3772/1/586 +f 3771/1/587 3547/1/587 3663/1/587 +f 3589/1/588 3505/1/588 3813/1/588 +f 3576/1/2096 3492/1/2096 3800/1/2096 +f 3479/1/590 3647/1/590 3703/1/590 +f 3643/1/591 3531/1/591 3867/1/591 +f 3858/1/2097 3634/1/2097 3690/1/2097 +f 3677/1/593 3453/1/593 3845/1/593 +f 3518/1/594 3630/1/594 3742/1/594 +f 3608/1/595 3440/1/595 3832/1/595 +f 3505/1/596 3617/1/596 3729/1/596 +f 3492/1/2098 3604/1/2098 3716/1/2098 +f 3591/1/598 3479/1/598 3815/1/598 +f 3789/1/599 3565/1/599 3756/1/599 +f 3690/1/2099 3466/1/2099 3802/1/2099 +f 3784/1/601 3560/1/601 3677/1/601 +f 3743/1/602 3519/1/602 3771/1/602 +f 3440/1/603 3548/1/603 3664/1/603 +f 3506/1/604 3590/1/604 3730/1/604 +f 3801/1/605 3577/1/605 3717/1/605 +f 3704/1/606 3480/1/606 3872/1/606 +f 3756/1/607 3532/1/607 3868/1/607 +f 3691/1/608 3467/1/608 3859/1/608 +f 3454/1/609 3622/1/609 3678/1/609 +f 3855/1/610 3631/1/610 3743/1/610 +f 3665/1/611 3441/1/611 3833/1/611 +f 3618/1/612 3506/1/612 3842/1/612 +f 3493/1/613 3605/1/613 3717/1/613 +f 3816/1/614 3592/1/614 3704/1/614 +f 3550/1/615 3533/1/615 3774/1/615 +f 3803/1/616 3579/1/616 3691/1/616 +f 3566/1/617 3454/1/617 3790/1/617 +f 3546/1/2100 3520/1/2100 3770/1/2100 +f 3773/1/619 3549/1/619 3665/1/619 +f 3507/1/620 3591/1/620 3731/1/620 +f 3802/1/2101 3578/1/2101 3718/1/2101 +f 3705/1/622 3481/1/622 3873/1/622 +f 3533/1/623 3645/1/623 3757/1/623 +f 3636/1/624 3468/1/624 3860/1/624 +f 3455/1/625 3623/1/625 3679/1/625 +f 3520/1/2102 3632/1/2102 3744/1/2102 +f 3610/1/2103 3442/1/2103 3834/1/2103 +f 3619/1/628 3507/1/628 3843/1/628 +f 3718/1/2104 3494/1/2104 3830/1/2104 +f 3817/1/630 3593/1/630 3705/1/630 +f 3534/1/631 3566/1/631 3758/1/631 +f 3468/1/632 3580/1/632 3692/1/632 +f 3567/1/633 3455/1/633 3791/1/633 +f 3780/1/634 3556/1/634 3745/1/634 +f 3442/1/2105 3550/1/2105 3666/1/2105 +f 3732/1/635 3508/1/635 3816/1/635 +f 3719/1/636 3495/1/636 3803/1/636 +f 3482/1/637 3650/1/637 3706/1/637 +f 3646/1/638 3534/1/638 3870/1/638 +f 3469/1/639 3637/1/639 3693/1/639 +f 3680/1/640 3456/1/640 3848/1/640 +f 3745/1/641 3521/1/641 3857/1/641 +f 3844/1/642 3620/1/642 3732/1/642 +f 3667/1/643 3443/1/643 3835/1/643 +f 3831/1/644 3607/1/644 3719/1/644 +f 3598/1/645 3430/1/645 3822/1/645 +f 3594/1/646 3482/1/646 3818/1/646 +f 3535/1/647 3567/1/647 3759/1/647 +f 3581/1/648 3469/1/648 3805/1/648 +f 3777/1/2106 3553/1/2106 3746/1/2106 +f 3792/1/650 3568/1/650 3680/1/650 +f 3733/1/651 3509/1/651 3817/1/651 +f 3775/1/652 3551/1/652 3667/1/652 +f 3580/1/653 3496/1/653 3804/1/653 +f 3430/1/654 3543/1/654 3654/1/654 +f 3483/1/655 3651/1/655 3707/1/655 +f 3647/1/656 3535/1/656 3871/1/656 +f 3638/1/2107 3470/1/2107 3862/1/2107 +f 3746/1/2108 3522/1/2108 3858/1/2108 +f 3681/1/659 3457/1/659 3849/1/659 +f 3845/1/660 3621/1/660 3733/1/660 +f 3612/1/661 3444/1/661 3836/1/661 +f 3496/1/662 3608/1/662 3720/1/662 +f 3823/1/663 3599/1/663 3655/1/663 +f 3595/1/664 3483/1/664 3819/1/664 +f 3760/1/665 3536/1/665 3792/1/665 +f 3470/1/2109 3582/1/2109 3694/1/2109 +f 3747/1/667 3523/1/667 3773/1/667 +f 3793/1/668 3569/1/668 3681/1/668 +f 3444/1/669 3552/1/669 3668/1/669 +f 3510/1/670 3594/1/670 3734/1/670 +f 3655/1/671 3431/1/671 3789/1/671 +f 3497/1/672 3581/1/672 3721/1/672 +f 3708/1/673 3484/1/673 3876/1/673 +f 3872/1/674 3648/1/674 3760/1/674 +f 3695/1/675 3471/1/675 3863/1/675 +f 3626/1/676 3458/1/676 3850/1/676 +f 3859/1/677 3635/1/677 3747/1/677 +f 3837/1/2110 3613/1/2110 3669/1/2110 +f 3622/1/679 3510/1/679 3846/1/679 +f 3432/1/680 3600/1/680 3656/1/680 +f 3609/1/681 3497/1/681 3833/1/681 +f 3820/1/682 3596/1/682 3708/1/682 +f 3761/1/683 3537/1/683 3793/1/683 +f 3807/1/684 3583/1/684 3695/1/684 +f 3458/1/685 3570/1/685 3682/1/685 +f 3545/1/686 3524/1/686 3769/1/686 +f 4364/1/687 3692/1/687 4476/1/687 +f 4733/1/2111 4061/1/2111 4621/1/2111 +f 4066/1/689 3898/1/689 4738/1/689 +f 3802/1/2112 3718/1/2112 4474/1/2112 +f 4681/1/691 4009/1/691 4647/1/691 +f 4338/1/2113 3666/1/2113 4446/1/2113 +f 3923/1/693 4035/1/693 4595/1/693 +f 3855/1/694 3743/1/694 4527/1/694 +f 4532/1/695 3860/1/695 4364/1/695 +f 4621/1/2114 3949/1/2114 4705/1/2114 +f 4005/1/697 3897/1/697 4677/1/697 +f 3717/1/698 3829/1/698 4389/1/698 +f 4086/1/2115 3974/1/2115 4758/1/2115 +f 4506/1/2116 3834/1/2116 4338/1/2116 +f 4091/1/701 3923/1/701 4763/1/701 +f 3743/1/702 3771/1/702 4415/1/702 +f 3803/1/703 3691/1/703 4475/1/703 +f 4060/1/704 3948/1/704 4732/1/704 +f 3897/1/705 4065/1/705 4569/1/705 +f 3801/1/706 3717/1/706 4473/1/706 +f 3974/1/2117 3992/1/2117 4646/1/2117 +f 4445/1/708 3773/1/708 4337/1/708 +f 4706/1/709 4034/1/709 4594/1/709 +f 4414/1/710 3742/1/710 4526/1/710 +f 3691/1/711 3859/1/711 4363/1/711 +f 3948/1/712 4032/1/712 4620/1/712 +f 4676/1/713 4004/1/713 4568/1/713 +f 4388/1/2118 3716/1/2118 4500/1/2118 +f 3973/1/715 4085/1/715 4645/1/715 +f 4337/1/716 3665/1/716 4505/1/716 +f 4594/1/717 3922/1/717 4762/1/717 +f 4444/1/718 3772/1/718 4414/1/718 +f 3690/1/2119 3802/1/2119 4362/1/2119 +f 4619/1/720 3947/1/720 4731/1/720 +f 4568/1/721 3896/1/721 4736/1/721 +f 4472/1/2120 3800/1/2120 4388/1/2120 +f 4003/1/723 3973/1/723 4675/1/723 +f 4336/1/724 3664/1/724 4444/1/724 +f 4705/1/2121 4033/1/2121 4593/1/2121 +f 3741/1/726 3853/1/726 4413/1/726 +f 3858/1/2122 3690/1/2122 4530/1/2122 +f 4703/1/728 4031/1/728 4619/1/728 +f 3895/1/729 4003/1/729 4567/1/729 +f 3827/1/730 3715/1/730 4499/1/730 +f 4084/1/731 3972/1/731 4756/1/731 +f 4504/1/732 3832/1/732 4336/1/732 +f 4593/1/2123 3921/1/2123 4761/1/2123 +f 3766/1/734 3741/1/734 4438/1/734 +f 3689/1/735 3801/1/735 4361/1/735 +f 4058/1/2124 3946/1/2124 4730/1/2124 +f 4063/1/737 3895/1/737 4735/1/737 +f 3715/1/738 3799/1/738 4387/1/738 +f 3972/1/739 3993/1/739 4644/1/739 +f 3771/1/740 3663/1/740 4443/1/740 +f 4032/1/741 3920/1/741 4704/1/741 +f 4524/1/742 3852/1/742 4412/1/742 +f 3857/1/743 3689/1/743 4529/1/743 +f 3946/1/2125 4030/1/2125 4618/1/2125 +f 4674/1/745 4002/1/745 4566/1/745 +f 4386/1/746 3714/1/746 4498/1/746 +f 4643/1/747 3971/1/747 4755/1/747 +f 3663/1/748 3831/1/748 4335/1/748 +f 3920/1/749 4088/1/749 4592/1/749 +f 4412/1/750 3740/1/750 4438/1/750 +f 4360/1/2126 3688/1/2126 4472/1/2126 +f 3945/1/752 4057/1/752 4617/1/752 +f 4566/1/753 3894/1/753 4734/1/753 +f 3877/1/754 3765/1/754 4549/1/754 +f 4470/1/755 3798/1/755 4386/1/755 +f 4669/1/756 3997/1/756 4643/1/756 +f 3662/1/757 3770/1/757 4334/1/757 +f 4591/1/758 3919/1/758 4703/1/758 +f 3739/1/759 3851/1/759 4411/1/759 +f 4029/1/2127 3945/1/2127 4701/1/2127 +f 4528/1/761 3856/1/761 4360/1/761 +f 4673/1/2128 4001/1/2128 4565/1/2128 +f 3765/1/763 3782/1/763 4437/1/763 +f 3713/1/2129 3825/1/2129 4385/1/2129 +f 4754/1/2130 4082/1/2130 4642/1/2130 +f 4759/1/766 4087/1/766 4591/1/766 +f 3830/1/767 3662/1/767 4502/1/767 +f 3767/1/768 3739/1/768 4439/1/768 +f 4056/1/769 3944/1/769 4728/1/769 +f 3799/1/770 3687/1/770 4471/1/770 +f 4565/1/2131 3893/1/2131 4733/1/2131 +f 3876/1/772 3764/1/772 4548/1/772 +f 3797/1/773 3713/1/773 4469/1/773 +f 4642/1/2132 3970/1/2132 4673/1/2132 +f 4030/1/2133 3918/1/2133 4702/1/2133 +f 3661/1/2134 3769/1/2134 4333/1/2134 +f 4410/1/777 3738/1/777 4522/1/777 +f 3944/1/778 4028/1/778 4616/1/778 +f 3687/1/779 3855/1/779 4359/1/779 +f 4000/1/780 3892/1/780 4672/1/780 +f 3764/1/781 3784/1/781 4436/1/781 +f 4496/1/782 3824/1/782 4384/1/782 +f 4753/1/783 4081/1/783 4641/1/783 +f 3918/1/2135 4086/1/2135 4590/1/2135 +f 3829/1/785 3661/1/785 4501/1/785 +f 4453/1/786 3781/1/786 4410/1/786 +f 4615/1/787 3943/1/787 4727/1/787 +f 4358/1/788 3686/1/788 4470/1/788 +f 3892/1/789 4060/1/789 4564/1/789 +f 4547/1/2136 3875/1/2136 4435/1/2136 +f 4384/1/791 3712/1/791 4468/1/791 +f 4641/1/792 3969/1/792 4676/1/792 +f 3917/1/793 4029/1/793 4589/1/793 +f 4332/1/2137 3660/1/2137 4440/1/2137 +f 3849/1/795 3737/1/795 4521/1/795 +f 4699/1/796 4027/1/796 4615/1/796 +f 4526/1/797 3854/1/797 4358/1/797 +f 4563/1/798 3891/1/798 4671/1/798 +f 4435/1/799 3763/1/799 4447/1/799 +f 3711/1/800 3823/1/800 4383/1/800 +f 4080/1/801 3968/1/801 4752/1/801 +f 4085/1/802 3917/1/802 4757/1/802 +f 4500/1/2138 3828/1/2138 4332/1/2138 +f 3737/1/804 3821/1/804 4409/1/804 +f 4726/1/2139 4054/1/2139 4614/1/2139 +f 3685/1/806 3797/1/806 4357/1/806 +f 4731/1/807 4059/1/807 4563/1/807 +f 4546/1/808 3874/1/808 4434/1/808 +f 3795/1/809 3711/1/809 4467/1/809 +f 3968/1/810 3994/1/810 4640/1/810 +f 4028/1/811 3916/1/811 4700/1/811 +f 3785/1/812 3659/1/812 4457/1/812 +f 3848/1/813 3736/1/813 4520/1/813 +f 4614/1/2140 3942/1/2140 4698/1/2140 +f 3853/1/815 3685/1/815 4525/1/815 +f 3998/1/2141 3890/1/2141 4670/1/2141 +f 4434/1/817 3762/1/817 4455/1/817 +f 4382/1/818 3710/1/818 4494/1/818 +f 4639/1/819 3967/1/819 4751/1/819 +f 3916/1/820 4084/1/820 4588/1/820 +f 3659/1/821 3827/1/821 4331/1/821 +f 3736/1/822 3820/1/822 4408/1/822 +f 4725/1/2142 4053/1/2142 4613/1/2142 +f 4468/1/824 3796/1/824 4356/1/824 +f 3890/1/2143 4058/1/2143 4562/1/2143 +f 3873/1/826 3761/1/826 4545/1/826 +f 4466/1/827 3794/1/827 4382/1/827 +f 4667/1/828 3995/1/828 4639/1/828 +f 4587/1/829 3915/1/829 4699/1/829 +f 4330/1/830 3658/1/830 4458/1/830 +f 4519/1/831 3847/1/831 4407/1/831 +f 4613/1/832 3941/1/832 4697/1/832 +f 4356/1/833 3684/1/833 4524/1/833 +f 3889/1/834 3997/1/834 4561/1/834 +f 3761/1/835 3793/1/835 4433/1/835 +f 3821/1/836 3709/1/836 4493/1/836 +f 4078/1/837 3966/1/837 4750/1/837 +f 4755/1/838 4083/1/838 4587/1/838 +f 4498/1/839 3826/1/839 4330/1/839 +f 4407/1/840 3735/1/840 4491/1/840 +f 4052/1/841 3940/1/841 4724/1/841 +f 3683/1/842 3795/1/842 4355/1/842 +f 4057/1/843 3889/1/843 4729/1/843 +f 3872/1/844 3760/1/844 4544/1/844 +f 3709/1/845 3877/1/845 4381/1/845 +f 3966/1/846 3996/1/846 4638/1/846 +f 4698/1/2144 4026/1/2144 4586/1/2144 +f 3657/1/848 3787/1/848 4329/1/848 +f 4518/1/849 3846/1/849 4406/1/849 +f 3940/1/850 4024/1/850 4612/1/850 +f 3851/1/851 3683/1/851 4523/1/851 +f 3996/1/852 3888/1/852 4668/1/852 +f 3760/1/853 3792/1/853 4432/1/853 +f 3820/1/854 3708/1/854 4492/1/854 +f 4749/1/855 4077/1/855 4637/1/855 +f 4586/1/2145 3914/1/2145 4754/1/2145 +f 3825/1/857 3657/1/857 4497/1/857 +f 4406/1/858 3734/1/858 4490/1/858 +f 4611/1/859 3939/1/859 4723/1/859 +f 4354/1/860 3682/1/860 4466/1/860 +f 3888/1/861 4056/1/861 4560/1/861 +f 4543/1/862 3871/1/862 4431/1/862 +f 3708/1/863 3876/1/863 4380/1/863 +f 4637/1/864 3965/1/864 4662/1/864 +f 4697/1/865 4025/1/865 4585/1/865 +f 4460/1/2146 3788/1/2146 4328/1/2146 +f 3845/1/867 3733/1/867 4517/1/867 +f 4695/1/2147 4023/1/2147 4611/1/2147 +f 4522/1/869 3850/1/869 4354/1/869 +f 4559/1/870 3887/1/870 4667/1/870 +f 4431/1/871 3759/1/871 4463/1/871 +f 4491/1/872 3819/1/872 4379/1/872 +f 3964/1/873 4076/1/873 4636/1/873 +f 4585/1/874 3913/1/874 4753/1/874 +f 4328/1/875 3656/1/875 4496/1/875 +f 3733/1/876 3817/1/876 4405/1/876 +f 4050/1/877 3938/1/877 4722/1/877 +f 3793/1/878 3681/1/878 4465/1/878 +f 4727/1/879 4055/1/879 4559/1/879 +f 4542/1/880 3870/1/880 4430/1/880 +f 4379/1/881 3707/1/881 4547/1/881 +f 3990/1/882 3964/1/882 4662/1/882 +f 4024/1/2148 3912/1/2148 4696/1/2148 +f 3655/1/884 3789/1/884 4327/1/884 +f 3844/1/885 3732/1/885 4516/1/885 +f 4661/1/886 3989/1/886 4773/1/886 +f 3938/1/887 4022/1/887 4610/1/887 +f 3681/1/888 3849/1/888 4353/1/888 +f 4666/1/2149 3994/1/2149 4558/1/2149 +f 4430/1/890 3758/1/890 4462/1/890 +f 4490/1/891 3818/1/891 4378/1/891 +f 4747/1/892 4075/1/892 4635/1/892 +f 3912/1/893 4080/1/893 4584/1/893 +f 3823/1/894 3655/1/894 4495/1/894 +f 3732/1/895 3816/1/895 4404/1/895 +f 4678/1/896 4006/1/896 4661/1/896 +f 4721/1/897 4049/1/897 4609/1/897 +f 3792/1/898 3680/1/898 4464/1/898 +f 4558/1/2150 3886/1/2150 4726/1/2150 +f 4429/1/2151 3757/1/2151 4541/1/2151 +f 4378/1/901 3706/1/901 4546/1/901 +f 4635/1/902 3963/1/902 4663/1/902 +f 4583/1/903 3911/1/903 4695/1/903 +f 4326/1/904 3654/1/904 4439/1/904 +f 4515/1/905 3843/1/905 4403/1/905 +f 4660/1/906 3988/1/906 4772/1/906 +f 3680/1/907 3848/1/907 4352/1/907 +f 4609/1/908 3937/1/908 4693/1/908 +f 4665/1/909 3993/1/909 4557/1/909 +f 4446/1/2152 3774/1/2152 4429/1/2152 +f 3884/1/2153 3992/1/2153 4108/1/2153 +f 4258/1/2154 4034/1/2154 4174/1/2154 +f 4245/1/541 4021/1/541 4161/1/541 +f 4325/1/542 4101/1/542 4213/1/542 +f 4316/1/543 4092/1/543 4148/1/543 +f 4135/1/544 3911/1/544 4303/1/544 +f 3976/1/545 4088/1/545 4200/1/545 +f 3898/1/547 4066/1/547 4122/1/547 +f 4187/1/546 3963/1/546 4299/1/546 +f 4053/1/549 3885/1/549 4277/1/549 +f 4174/1/2155 3950/1/2155 4286/1/2155 +f 4161/1/550 3937/1/550 4273/1/550 +f 4148/1/551 3924/1/551 4260/1/551 +f 4247/1/553 4023/1/553 4135/1/553 +f 4226/1/2156 4002/1/2156 4201/1/2156 +f 4230/1/555 4006/1/555 4122/1/555 +f 3964/1/554 3990/1/554 4188/1/554 +f 3885/1/557 3993/1/557 4109/1/557 +f 3951/1/556 4035/1/556 4175/1/556 +f 4022/1/558 3938/1/558 4246/1/558 +f 4093/1/2157 3925/1/2157 4317/1/2157 +f 4080/1/2158 3912/1/2158 4304/1/2158 +f 4201/1/2159 3977/1/2159 4313/1/2159 +f 3899/1/563 4067/1/563 4123/1/563 +f 4076/1/562 3964/1/562 4300/1/562 +f 4054/1/2160 3886/1/2160 4278/1/2160 +f 4063/1/565 3951/1/565 4287/1/565 +f 3938/1/566 4050/1/566 4162/1/566 +f 3925/1/2161 4037/1/2161 4149/1/2161 +f 3912/1/2162 4024/1/2162 4136/1/2162 +f 4235/1/567 4011/1/567 4202/1/567 +f 4007/1/569 3899/1/569 4231/1/569 +f 4214/1/570 3990/1/570 4189/1/570 +f 3886/1/2163 3994/1/2163 4110/1/2163 +f 4260/1/572 4036/1/572 4176/1/572 +f 4163/1/573 3939/1/573 4247/1/573 +f 3926/1/574 4094/1/574 4150/1/574 +f 4305/1/575 4081/1/575 4137/1/575 +f 4202/1/2164 3978/1/2164 4314/1/2164 +f 4124/1/577 3900/1/577 4292/1/577 +f 4189/1/578 3965/1/578 4301/1/578 +f 4111/1/579 3887/1/579 4279/1/579 +f 4176/1/580 3952/1/580 4288/1/580 +f 4275/1/581 4051/1/581 4163/1/581 +f 4038/1/582 3926/1/582 4262/1/582 +f 3979/1/583 4012/1/583 4203/1/583 +f 4137/1/584 3913/1/584 4249/1/584 +f 4224/1/585 4000/1/585 4124/1/585 +f 3996/1/586 3966/1/586 4220/1/586 +f 4037/1/2165 3953/1/2165 4261/1/2165 +f 4219/1/587 3995/1/587 4111/1/587 +f 4024/1/2166 3940/1/2166 4248/1/2166 +f 3927/1/590 4095/1/590 4151/1/590 +f 4091/1/591 3979/1/591 4315/1/591 +f 4306/1/2167 4082/1/2167 4138/1/2167 +f 3966/1/594 4078/1/594 4190/1/594 +f 4125/1/593 3901/1/593 4293/1/593 +f 3953/1/2168 4065/1/2168 4177/1/2168 +f 4056/1/595 3888/1/595 4280/1/595 +f 3940/1/2169 4052/1/2169 4164/1/2169 +f 4039/1/598 3927/1/598 4263/1/598 +f 4237/1/599 4013/1/599 4204/1/599 +f 4138/1/2170 3914/1/2170 4250/1/2170 +f 4191/1/602 3967/1/602 4219/1/602 +f 4232/1/601 4008/1/601 4125/1/601 +f 3954/1/604 4038/1/604 4178/1/604 +f 3888/1/603 3996/1/603 4112/1/603 +f 4249/1/605 4025/1/605 4165/1/605 +f 4152/1/606 3928/1/606 4320/1/606 +f 4204/1/607 3980/1/607 4316/1/607 +f 4139/1/608 3915/1/608 4307/1/608 +f 4303/1/610 4079/1/610 4191/1/610 +f 3902/1/609 4070/1/609 4126/1/609 +f 4113/1/611 3889/1/611 4281/1/611 +f 4066/1/612 3954/1/612 4290/1/612 +f 3941/1/613 4053/1/613 4165/1/613 +f 4264/1/614 4040/1/614 4152/1/614 +f 3998/1/2171 3981/1/2171 4222/1/2171 +f 4251/1/616 4027/1/616 4139/1/616 +f 4014/1/617 3902/1/617 4238/1/617 +f 3994/1/2172 3968/1/2172 4218/1/2172 +f 4221/1/619 3997/1/619 4113/1/619 +f 3955/1/620 4039/1/620 4179/1/620 +f 4250/1/2173 4026/1/2173 4166/1/2173 +f 4153/1/622 3929/1/622 4321/1/622 +f 3981/1/2174 4093/1/2174 4205/1/2174 +f 4084/1/624 3916/1/624 4308/1/624 +f 3903/1/625 4071/1/625 4127/1/625 +f 3968/1/2175 4080/1/2175 4192/1/2175 +f 4058/1/2176 3890/1/2176 4282/1/2176 +f 4067/1/628 3955/1/628 4291/1/628 +f 4166/1/2177 3942/1/2177 4278/1/2177 +f 4265/1/630 4041/1/630 4153/1/630 +f 3982/1/631 4014/1/631 4206/1/631 +f 3916/1/632 4028/1/632 4140/1/632 +f 4015/1/633 3903/1/633 4239/1/633 +f 4228/1/634 4004/1/634 4193/1/634 +f 3890/1/2178 3998/1/2178 4114/1/2178 +f 4180/1/635 3956/1/635 4264/1/635 +f 4167/1/636 3943/1/636 4251/1/636 +f 3930/1/637 4098/1/637 4154/1/637 +f 4094/1/638 3982/1/638 4318/1/638 +f 3917/1/639 4085/1/639 4141/1/639 +f 4128/1/640 3904/1/640 4296/1/640 +f 4193/1/641 3969/1/641 4305/1/641 +f 4115/1/643 3891/1/643 4283/1/643 +f 4292/1/642 4068/1/642 4180/1/642 +f 4046/1/645 3878/1/645 4270/1/645 +f 4279/1/644 4055/1/644 4167/1/644 +f 4042/1/646 3930/1/646 4266/1/646 +f 3983/1/647 4015/1/647 4207/1/647 +f 4029/1/648 3917/1/648 4253/1/648 +f 4240/1/650 4016/1/650 4128/1/650 +f 4225/1/2179 4001/1/2179 4194/1/2179 +f 4223/1/652 3999/1/652 4115/1/652 +f 4181/1/651 3957/1/651 4265/1/651 +f 3878/1/2180 3991/1/2180 4102/1/2180 +f 4028/1/653 3944/1/653 4252/1/653 +f 3931/1/655 4099/1/655 4155/1/655 +f 4095/1/656 3983/1/656 4319/1/656 +f 4086/1/2181 3918/1/2181 4310/1/2181 +f 4129/1/659 3905/1/659 4297/1/659 +f 4194/1/2182 3970/1/2182 4306/1/2182 +f 4060/1/661 3892/1/661 4284/1/661 +f 4293/1/660 4069/1/660 4181/1/660 +f 4271/1/663 4047/1/663 4103/1/663 +f 3944/1/662 4056/1/662 4168/1/662 +f 4043/1/664 3931/1/664 4267/1/664 +f 4208/1/665 3984/1/665 4240/1/665 +f 3918/1/2183 4030/1/2183 4142/1/2183 +f 4241/1/668 4017/1/668 4129/1/668 +f 4195/1/667 3971/1/667 4221/1/667 +f 3892/1/669 4000/1/669 4116/1/669 +f 3958/1/670 4042/1/670 4182/1/670 +f 4103/1/671 3879/1/671 4237/1/671 +f 3945/1/672 4029/1/672 4169/1/672 +f 4156/1/673 3932/1/673 4324/1/673 +f 4320/1/674 4096/1/674 4208/1/674 +f 4143/1/675 3919/1/675 4311/1/675 +f 4074/1/676 3906/1/676 4298/1/676 +f 4307/1/677 4083/1/677 4195/1/677 +f 4285/1/2184 4061/1/2184 4117/1/2184 +f 4070/1/679 3958/1/679 4294/1/679 +f 3880/1/680 4048/1/680 4104/1/680 +f 4057/1/681 3945/1/681 4281/1/681 +f 4268/1/682 4044/1/682 4156/1/682 +f 4209/1/683 3985/1/683 4241/1/683 +f 4255/1/684 4031/1/684 4143/1/684 +f 3906/1/685 4018/1/685 4130/1/685 +f 3993/1/686 3972/1/686 4217/1/686 +f 4117/1/2185 3893/1/2185 4225/1/2185 +f 3959/1/467 4043/1/467 4183/1/467 +f 4030/1/2186 3946/1/2186 4254/1/2186 +f 4012/1/468 3880/1/468 4236/1/468 +f 4157/1/470 3933/1/470 4325/1/470 +f 4321/1/471 4097/1/471 4209/1/471 +f 4088/1/472 3920/1/472 4312/1/472 +f 4299/1/473 4075/1/473 4131/1/473 +f 3972/1/474 4084/1/474 4196/1/474 +f 4071/1/476 3959/1/476 4295/1/476 +f 4286/1/2187 4062/1/2187 4118/1/2187 +f 3946/1/2188 4058/1/2188 4170/1/2188 +f 4273/1/477 4049/1/477 4105/1/477 +f 4269/1/479 4045/1/479 4157/1/479 +f 3986/1/480 4007/1/480 4210/1/480 +f 3920/1/481 4032/1/481 4144/1/481 +f 3973/1/483 4003/1/483 4197/1/483 +f 4131/1/482 3907/1/482 4243/1/482 +f 4184/1/485 3960/1/485 4268/1/485 +f 4118/1/2189 3894/1/2189 4226/1/2189 +f 4171/1/487 3947/1/487 4255/1/487 +f 4105/1/486 3881/1/486 4235/1/486 +f 4018/1/488 3934/1/488 4242/1/488 +f 4098/1/489 3986/1/489 4322/1/489 +f 4313/1/2190 4089/1/2190 4145/1/2190 +f 4085/1/491 3973/1/491 4309/1/491 +f 3908/1/490 4076/1/490 4132/1/490 +f 4296/1/493 4072/1/493 4184/1/493 +f 3895/1/492 4063/1/492 4119/1/492 +f 4050/1/494 3882/1/494 4274/1/494 +f 4283/1/495 4059/1/495 4171/1/495 +f 3934/1/496 4046/1/496 4158/1/496 +f 3987/1/497 3999/1/497 4211/1/497 +f 4145/1/2191 3921/1/2191 4257/1/2191 +f 3992/1/2192 3974/1/2192 4216/1/2192 +f 4020/1/499 3908/1/499 4244/1/499 +f 4003/1/501 3895/1/501 4227/1/501 +f 4185/1/502 3961/1/502 4269/1/502 +f 3882/1/503 4010/1/503 4106/1/503 +f 4032/1/504 3948/1/504 4256/1/504 +f 4243/1/505 4019/1/505 4159/1/505 +f 4099/1/506 3987/1/506 4323/1/506 +f 4314/1/2193 4090/1/2193 4146/1/2193 +f 4301/1/508 4077/1/508 4133/1/508 +f 3974/1/2194 4086/1/2194 4198/1/2194 +f 4288/1/510 4064/1/510 4120/1/510 +f 4297/1/511 4073/1/511 4185/1/511 +f 4107/1/512 3883/1/512 4275/1/512 +f 3948/1/513 4060/1/513 4172/1/513 +f 4159/1/514 3935/1/514 4271/1/514 +f 4212/1/515 3988/1/515 4232/1/515 +f 4146/1/2195 3922/1/2195 4258/1/2195 +f 4133/1/2087 3909/1/2087 4245/1/2087 +f 4199/1/518 3975/1/518 4233/1/518 +f 4120/1/519 3896/1/519 4228/1/519 +f 4005/1/520 3962/1/520 4229/1/520 +f 4233/1/521 4009/1/521 4107/1/521 +f 4257/1/2196 4033/1/2196 4173/1/2196 +f 3936/1/523 4020/1/523 4160/1/523 +f 4324/1/2197 4100/1/2197 4212/1/2197 +f 3923/1/525 4091/1/525 4147/1/525 +f 4078/1/526 3910/1/526 4302/1/526 +f 4311/1/527 4087/1/527 4199/1/527 +f 4065/1/2198 3897/1/2198 4289/1/2198 +f 3962/1/529 4074/1/529 4186/1/529 +f 4052/1/2199 3884/1/2199 4276/1/2199 +f 4173/1/2200 3949/1/2200 4285/1/2200 +f 4048/1/532 3936/1/532 4272/1/532 +f 4213/1/533 3989/1/533 4230/1/533 +f 4035/1/534 3923/1/534 4259/1/534 +f 3910/1/535 4022/1/535 4134/1/535 +f 4010/1/536 3976/1/536 4234/1/536 +f 3897/1/2201 4005/1/2201 4121/1/2201 +f 4215/1/538 3991/1/538 4187/1/538 +f 4528/1/2202 4360/1/2202 4752/1/2202 +f 4649/1/1175 4425/1/1175 4761/1/1175 +f 4347/1/2203 4515/1/2203 4571/1/2203 +f 4524/1/2204 4412/1/2204 4748/1/2204 +f 4726/1/2205 4502/1/2205 4558/1/2205 +f 4511/1/2206 4399/1/2206 4735/1/2206 +f 4386/1/2207 4498/1/2207 4610/1/2207 +f 4373/1/2208 4485/1/2208 4597/1/2208 +f 4360/1/2209 4472/1/2209 4584/1/2209 +f 4683/1/2210 4459/1/2210 4650/1/2210 +f 4455/1/2211 4347/1/2211 4679/1/2211 +f 4662/1/970 4438/1/970 4637/1/970 +f 4334/1/2212 4442/1/2212 4558/1/2212 +f 4708/1/2213 4484/1/2213 4624/1/2213 +f 4611/1/973 4387/1/973 4695/1/973 +f 4374/1/2214 4542/1/2214 4598/1/2214 +f 4753/1/975 4529/1/975 4585/1/975 +f 4650/1/976 4426/1/976 4762/1/976 +f 4572/1/977 4348/1/977 4740/1/977 +f 4637/1/2215 4413/1/2215 4749/1/2215 +f 4559/1/2216 4335/1/2216 4727/1/2216 +f 4624/1/2217 4400/1/2217 4736/1/2217 +f 4723/1/2218 4499/1/2218 4611/1/2218 +f 4486/1/982 4374/1/982 4710/1/982 +f 4427/1/983 4460/1/983 4651/1/983 +f 4585/1/984 4361/1/984 4697/1/984 +f 4672/1/985 4448/1/985 4572/1/985 +f 4444/1/2219 4414/1/2219 4668/1/2219 +f 4667/1/987 4443/1/987 4559/1/987 +f 4485/1/2220 4401/1/2220 4709/1/2220 +f 4472/1/2221 4388/1/2221 4696/1/2221 +f 4375/1/990 4543/1/990 4599/1/990 +f 4539/1/991 4427/1/991 4763/1/991 +f 4754/1/2222 4530/1/2222 4586/1/2222 +f 4573/1/2223 4349/1/2223 4741/1/2223 +f 4414/1/2224 4526/1/2224 4638/1/2224 +f 4504/1/2225 4336/1/2225 4728/1/2225 +f 4401/1/2226 4513/1/2226 4625/1/2226 +f 4388/1/2227 4500/1/2227 4612/1/2227 +f 4487/1/2228 4375/1/2228 4711/1/2228 +f 4685/1/999 4461/1/999 4652/1/999 +f 4586/1/2229 4362/1/2229 4698/1/2229 +f 4680/1/1001 4456/1/1001 4573/1/1001 +f 4639/1/1002 4415/1/1002 4667/1/1002 +f 4336/1/2230 4444/1/2230 4560/1/2230 +f 4402/1/2231 4486/1/2231 4626/1/2231 +f 4697/1/1005 4473/1/1005 4613/1/1005 +f 4600/1/1006 4376/1/1006 4768/1/1006 +f 4652/1/1007 4428/1/1007 4764/1/1007 +f 4587/1/2232 4363/1/2232 4755/1/2232 +f 4350/1/2233 4518/1/2233 4574/1/2233 +f 4751/1/2234 4527/1/2234 4639/1/2234 +f 4561/1/1011 4337/1/1011 4729/1/1011 +f 4514/1/1012 4402/1/1012 4738/1/1012 +f 4389/1/1013 4501/1/1013 4613/1/1013 +f 4712/1/2235 4488/1/2235 4600/1/2235 +f 4446/1/2236 4429/1/2236 4670/1/2236 +f 4699/1/2237 4475/1/2237 4587/1/2237 +f 4462/1/2238 4350/1/2238 4686/1/2238 +f 4442/1/2239 4416/1/2239 4666/1/2239 +f 4669/1/1019 4445/1/1019 4561/1/1019 +f 4403/1/1020 4487/1/1020 4627/1/1020 +f 4698/1/2240 4474/1/2240 4614/1/2240 +f 4601/1/2241 4377/1/2241 4769/1/2241 +f 4429/1/2242 4541/1/2242 4653/1/2242 +f 4532/1/2243 4364/1/2243 4756/1/2243 +f 4351/1/1025 4519/1/1025 4575/1/1025 +f 4416/1/2244 4528/1/2244 4640/1/2244 +f 4506/1/2245 4338/1/2245 4730/1/2245 +f 4515/1/2246 4403/1/2246 4739/1/2246 +f 4614/1/2247 4390/1/2247 4726/1/2247 +f 4713/1/2248 4489/1/2248 4601/1/2248 +f 4430/1/2249 4462/1/2249 4654/1/2249 +f 4364/1/2250 4476/1/2250 4588/1/2250 +f 4676/1/2251 4452/1/2251 4641/1/2251 +f 4463/1/2252 4351/1/2252 4687/1/2252 +f 4628/1/1035 4404/1/1035 4712/1/1035 +f 4338/1/2253 4446/1/2253 4562/1/2253 +f 4615/1/2254 4391/1/2254 4699/1/2254 +f 4378/1/2255 4546/1/2255 4602/1/2255 +f 4542/1/1039 4430/1/1039 4766/1/1039 +f 4365/1/1040 4533/1/1040 4589/1/1040 +f 4641/1/1041 4417/1/1041 4753/1/1041 +f 4576/1/2256 4352/1/2256 4744/1/2256 +f 4740/1/1043 4516/1/1043 4628/1/1043 +f 4563/1/1044 4339/1/1044 4731/1/1044 +f 4727/1/1045 4503/1/1045 4615/1/1045 +f 4494/1/1046 4326/1/1046 4718/1/1046 +f 4490/1/2257 4378/1/2257 4714/1/2257 +f 4431/1/1048 4463/1/1048 4655/1/1048 +f 4477/1/1049 4365/1/1049 4701/1/1049 +f 4673/1/2258 4449/1/2258 4642/1/2258 +f 4688/1/1051 4464/1/1051 4576/1/1051 +f 4629/1/2259 4405/1/2259 4713/1/2259 +f 4671/1/1053 4447/1/1053 4563/1/1053 +f 4326/1/1054 4439/1/1054 4550/1/1054 +f 4476/1/1055 4392/1/1055 4700/1/1055 +f 4379/1/1056 4547/1/1056 4603/1/1056 +f 4543/1/2260 4431/1/2260 4767/1/2260 +f 4534/1/2261 4366/1/2261 4758/1/2261 +f 4577/1/2262 4353/1/2262 4745/1/2262 +f 4642/1/2263 4418/1/2263 4754/1/2263 +f 4508/1/2264 4340/1/2264 4732/1/2264 +f 4741/1/2265 4517/1/2265 4629/1/2265 +f 4719/1/2266 4495/1/2266 4551/1/2266 +f 4392/1/1064 4504/1/1064 4616/1/1064 +f 4491/1/1065 4379/1/1065 4715/1/1065 +f 4656/1/2267 4432/1/2267 4688/1/2267 +f 4366/1/2268 4478/1/2268 4590/1/2268 +f 4689/1/1068 4465/1/1068 4577/1/1068 +f 4643/1/1069 4419/1/1069 4669/1/1069 +f 4340/1/1070 4448/1/1070 4564/1/1070 +f 4406/1/2269 4490/1/2269 4630/1/2269 +f 4551/1/1072 4327/1/1072 4685/1/1072 +f 4393/1/1073 4477/1/1073 4617/1/1073 +f 4604/1/2270 4380/1/2270 4772/1/2270 +f 4768/1/1075 4544/1/1075 4656/1/1075 +f 4591/1/2271 4367/1/2271 4759/1/2271 +f 4522/1/2272 4354/1/2272 4746/1/2272 +f 4755/1/1078 4531/1/1078 4643/1/1078 +f 4733/1/2273 4509/1/2273 4565/1/2273 +f 4518/1/2274 4406/1/2274 4742/1/2274 +f 4328/1/2275 4496/1/2275 4552/1/2275 +f 4505/1/1082 4393/1/1082 4729/1/1082 +f 4716/1/1083 4492/1/1083 4604/1/1083 +f 4657/1/2276 4433/1/2276 4689/1/2276 +f 4703/1/1085 4479/1/1085 4591/1/1085 +f 4354/1/1086 4466/1/1086 4578/1/1086 +f 4441/1/2277 4420/1/2277 4665/1/2277 +f 4565/1/2278 4341/1/2278 4673/1/2278 +f 4407/1/1089 4491/1/1089 4631/1/1089 +f 4460/1/2279 4328/1/2279 4684/1/2279 +f 4478/1/2280 4394/1/2280 4702/1/2280 +f 4605/1/1092 4381/1/1092 4773/1/1092 +f 4769/1/2281 4545/1/2281 4657/1/2281 +f 4536/1/1094 4368/1/1094 4760/1/1094 +f 4747/1/1095 4523/1/1095 4579/1/1095 +f 4420/1/1096 4532/1/1096 4644/1/1096 +f 4734/1/2282 4510/1/2282 4566/1/2282 +f 4519/1/2283 4407/1/2283 4743/1/2283 +f 4721/1/1099 4497/1/1099 4553/1/1099 +f 4394/1/2284 4506/1/2284 4618/1/2284 +f 4717/1/2285 4493/1/2285 4605/1/2285 +f 4434/1/2286 4455/1/2286 4658/1/2286 +f 4368/1/1103 4480/1/1103 4592/1/1103 +f 4579/1/2287 4355/1/2287 4691/1/2287 +f 4421/1/2288 4451/1/2288 4645/1/2288 +f 4566/1/2289 4342/1/2289 4674/1/2289 +f 4632/1/2290 4408/1/2290 4716/1/2290 +f 4553/1/2291 4329/1/2291 4683/1/2291 +f 4619/1/2292 4395/1/2292 4703/1/2292 +f 4466/1/2293 4382/1/2293 4690/1/2293 +f 4546/1/2294 4434/1/2294 4770/1/2294 +f 4761/1/2295 4537/1/2295 4593/1/2295 +f 4356/1/1113 4524/1/1113 4580/1/1113 +f 4533/1/2296 4421/1/2296 4757/1/2296 +f 4343/1/1115 4511/1/1115 4567/1/1115 +f 4744/1/1116 4520/1/1116 4632/1/1116 +f 4498/1/1117 4330/1/1117 4722/1/1117 +f 4731/1/2297 4507/1/2297 4619/1/2297 +f 4382/1/1119 4494/1/1119 4606/1/1119 +f 4435/1/1120 4447/1/1120 4659/1/1120 +f 4593/1/2298 4369/1/2298 4705/1/2298 +f 4468/1/2299 4356/1/2299 4692/1/2299 +f 4440/1/2300 4422/1/2300 4664/1/2300 +f 4451/1/1124 4343/1/1124 4675/1/1124 +f 4633/1/1125 4409/1/1125 4717/1/1125 +f 4330/1/1126 4458/1/1126 4554/1/1126 +f 4480/1/1127 4396/1/1127 4704/1/1127 +f 4691/1/1128 4467/1/1128 4607/1/1128 +f 4547/1/2301 4435/1/2301 4771/1/2301 +f 4762/1/2302 4538/1/2302 4594/1/2302 +f 4749/1/1131 4525/1/1131 4581/1/1131 +f 4422/1/2303 4534/1/2303 4646/1/2303 +f 4736/1/2304 4512/1/2304 4568/1/2304 +f 4745/1/2305 4521/1/2305 4633/1/2305 +f 4555/1/1135 4331/1/1135 4723/1/1135 +f 4396/1/1136 4508/1/1136 4620/1/1136 +f 4607/1/2306 4383/1/2306 4719/1/2306 +f 4660/1/2307 4436/1/2307 4680/1/2307 +f 4594/1/2308 4370/1/2308 4706/1/2308 +f 4581/1/2309 4357/1/2309 4693/1/2309 +f 4647/1/2310 4423/1/2310 4681/1/2310 +f 4568/1/2311 4344/1/2311 4676/1/2311 +f 4453/1/2312 4410/1/2312 4677/1/2312 +f 4705/1/2313 4481/1/2313 4621/1/2313 +f 4681/1/2314 4457/1/2314 4555/1/2314 +f 4384/1/2315 4468/1/2315 4608/1/2315 +f 4772/1/2316 4548/1/2316 4660/1/2316 +f 4371/1/2317 4539/1/2317 4595/1/2317 +f 4526/1/2318 4358/1/2318 4750/1/2318 +f 4759/1/1150 4535/1/1150 4647/1/1150 +f 4410/1/1151 4522/1/1151 4634/1/1151 +f 4513/1/1152 4345/1/1152 4737/1/1152 +f 4621/1/2319 4397/1/2319 4733/1/2319 +f 4500/1/2320 4332/1/2320 4724/1/2320 +f 4496/1/1155 4384/1/1155 4720/1/1155 +f 4661/1/1156 4437/1/1156 4678/1/1156 +f 4483/1/1157 4371/1/1157 4707/1/1157 +f 4458/1/1158 4424/1/1158 4682/1/1158 +f 4358/1/1159 4470/1/1159 4582/1/1159 +f 4663/1/1160 4439/1/1160 4635/1/1160 +f 4345/1/2321 4453/1/2321 4569/1/2321 +f 4706/1/2322 4482/1/2322 4622/1/2322 +f 4332/1/2323 4440/1/2323 4556/1/2323 +f 4693/1/1164 4469/1/1164 4609/1/1164 +f 4773/1/2324 4549/1/2324 4661/1/2324 +f 4764/1/2325 4540/1/2325 4596/1/2325 +f 4424/1/2326 4536/1/2326 4648/1/2326 +f 4583/1/1168 4359/1/1168 4751/1/1168 +f 4635/1/1169 4411/1/1169 4747/1/1169 +f 4346/1/1170 4514/1/1170 4570/1/1170 +f 4501/1/1171 4333/1/1171 4725/1/1171 +f 4622/1/2327 4398/1/2327 4734/1/2327 +f 4609/1/2328 4385/1/2328 4721/1/2328 +f 4596/1/1174 4372/1/1174 4708/1/1174 +f 4674/1/2329 4450/1/2329 4649/1/2329 +f 4695/1/2330 4471/1/2330 4583/1/2330 +f 4678/1/1177 4454/1/1177 4570/1/1177 +f 4412/1/1178 4438/1/1178 4636/1/1178 +f 4333/1/1179 4441/1/1179 4557/1/1179 +f 4399/1/1180 4483/1/1180 4623/1/1180 +f 4470/1/1181 4386/1/1181 4694/1/1181 +f 4541/1/2331 4373/1/2331 4765/1/2331 +f 4442/1/2332 3770/1/2332 4416/1/2332 +f 4596/1/1184 3924/1/1184 4764/1/1184 +f 3667/1/1185 3835/1/1185 4339/1/1185 +f 4647/1/1186 3975/1/1186 4759/1/1186 +f 3718/1/2333 3830/1/2333 4390/1/2333 +f 3898/1/1188 4006/1/1188 4570/1/1188 +f 4622/1/1189 3950/1/1189 4706/1/1189 +f 4365/1/1190 3693/1/1190 4533/1/1190 +f 4416/1/2334 3744/1/2334 4528/1/2334 +f 3775/1/1192 3667/1/1192 4447/1/1192 +f 4708/1/1193 4036/1/1193 4596/1/1193 +f 3976/1/1194 4010/1/1194 4648/1/1194 +f 3719/1/1195 3803/1/1195 4391/1/1195 +f 4067/1/1196 3899/1/1196 4739/1/1196 +f 4477/1/1197 3805/1/1197 4365/1/1197 +f 4734/1/1198 4062/1/1198 4622/1/1198 +f 3780/1/1199 3745/1/1199 4452/1/1199 +f 4508/1/1200 3836/1/1200 4340/1/1200 +f 3925/1/1201 4093/1/1201 4597/1/1201 +f 4088/1/1202 3976/1/1202 4760/1/1202 +f 3831/1/1203 3719/1/1203 4503/1/1203 +f 3899/1/1204 4007/1/1204 4571/1/1204 +f 4534/1/2335 3862/1/2335 4366/1/2335 +f 4035/1/1206 3951/1/1206 4707/1/1206 +f 3745/1/1207 3857/1/1207 4417/1/1207 +f 4340/1/1208 3668/1/1208 4448/1/1208 +f 4037/1/1209 3925/1/1209 4709/1/1209 +f 4649/1/2336 3977/1/2336 4674/1/2336 +f 4476/1/1211 3804/1/1211 4392/1/1211 +f 4740/1/1212 4068/1/1212 4572/1/1212 +f 4366/1/2337 3694/1/2337 4478/1/2337 +f 3951/1/1214 4063/1/1214 4623/1/1214 +f 3777/1/2338 3746/1/2338 4449/1/2338 +f 3837/1/2339 3669/1/2339 4509/1/2339 +f 4094/1/1217 3926/1/1217 4766/1/1217 +f 4761/1/2340 4089/1/2340 4649/1/2340 +f 4392/1/1219 3720/1/1219 4504/1/1219 +f 4572/1/1220 3900/1/1220 4672/1/1220 +f 3695/1/1221 3863/1/1221 4367/1/1221 +f 4624/1/1222 3952/1/1222 4708/1/1222 +f 3746/1/2341 3858/1/2341 4418/1/2341 +f 3669/1/2342 3777/1/2342 4341/1/2342 +f 3926/1/1225 4038/1/1225 4598/1/1225 +f 4650/1/1226 3978/1/1226 4683/1/1226 +f 4393/1/1227 3721/1/1227 4477/1/1227 +f 4741/1/1228 4069/1/1228 4573/1/1228 +f 3807/1/2343 3695/1/2343 4479/1/2343 +f 4736/1/1230 4064/1/1230 4624/1/1230 +f 3747/1/1231 3773/1/1231 4419/1/1231 +f 3838/1/1232 3670/1/1232 4510/1/1232 +f 4095/1/1233 3927/1/1233 4767/1/1233 +f 4762/1/2344 4090/1/2344 4650/1/2344 +f 4505/1/1235 3833/1/1235 4393/1/1235 +f 4573/1/1236 3901/1/1236 4680/1/1236 +f 4536/1/1237 3864/1/1237 4368/1/1237 +f 3953/1/1238 4037/1/1238 4625/1/1238 +f 3859/1/1239 3747/1/1239 4531/1/1239 +f 3670/1/1240 3778/1/1240 4342/1/1240 +f 3927/1/1241 4039/1/1241 4599/1/1241 +f 4012/1/1242 3979/1/1242 4684/1/1242 +f 4478/1/2345 3806/1/2345 4394/1/2345 +f 4070/1/1244 3902/1/1244 4742/1/1244 +f 4368/1/1245 3696/1/1245 4480/1/1245 +f 4065/1/1246 3953/1/1246 4737/1/1246 +f 4441/1/1247 3769/1/1247 4420/1/1247 +f 4343/1/1248 3671/1/1248 4511/1/1248 +f 4768/1/1249 4096/1/1249 4600/1/1249 +f 3979/1/1250 4091/1/1250 4651/1/1250 +f 4394/1/2346 3722/1/2346 4506/1/2346 +f 3902/1/1252 4014/1/1252 4574/1/1252 +f 3865/1/2347 3697/1/2347 4537/1/2347 +f 4038/1/1254 3954/1/1254 4710/1/1254 +f 4420/1/1255 3748/1/1255 4532/1/1255 +f 4451/1/1256 3779/1/1256 4343/1/1256 +f 4600/1/1257 3928/1/1257 4712/1/1257 +f 4652/1/1258 3980/1/1258 4685/1/1258 +f 3723/1/1259 3807/1/1259 4395/1/1259 +f 4071/1/1260 3903/1/1260 4743/1/1260 +f 3697/1/2348 3809/1/2348 4369/1/2348 +f 3954/1/1262 4066/1/1262 4626/1/1262 +f 4421/1/1263 3749/1/1263 4451/1/1263 +f 3840/1/1264 3672/1/1264 4512/1/1264 +f 4769/1/1265 4097/1/1265 4601/1/1265 +f 4764/1/1266 4092/1/1266 4652/1/1266 +f 3835/1/1267 3723/1/1267 4507/1/1267 +f 3903/1/1268 4015/1/1268 4575/1/1268 +f 3866/1/1269 3698/1/1269 4538/1/1269 +f 4039/1/1270 3955/1/1270 4711/1/1270 +f 4533/1/1271 3861/1/1271 4421/1/1271 +f 3878/1/1272 4046/1/1272 4550/1/1272 +f 3672/1/1273 3780/1/1273 4344/1/1273 +f 4601/1/1274 3929/1/1274 4713/1/1274 +f 3981/1/2349 3998/1/2349 4653/1/2349 +f 4480/1/1276 3808/1/1276 4396/1/1276 +f 4744/1/1277 4072/1/1277 4576/1/1277 +f 3698/1/1278 3810/1/1278 4370/1/1278 +f 3955/1/1279 4067/1/1279 4627/1/1279 +f 4440/1/2350 3768/1/2350 4422/1/2350 +f 3991/1/1281 3878/1/1281 4663/1/1281 +f 4513/1/2351 3841/1/2351 4345/1/2351 +f 4098/1/1283 3930/1/1283 4770/1/1283 +f 4093/1/1284 3981/1/1284 4765/1/1284 +f 4396/1/1285 3724/1/1285 4508/1/1285 +f 4576/1/1286 3904/1/1286 4688/1/1286 +f 4371/1/1287 3699/1/1287 4539/1/1287 +f 4712/1/1288 4040/1/1288 4628/1/1288 +f 4422/1/2352 3750/1/2352 4534/1/2352 +f 4551/1/1290 3879/1/1290 4719/1/1290 +f 4345/1/1291 3673/1/1291 4453/1/1291 +f 3930/1/1292 4042/1/1292 4602/1/1292 +f 4014/1/1293 3982/1/1293 4686/1/1293 +f 3809/1/2353 3725/1/2353 4481/1/2353 +f 4745/1/1295 4073/1/1295 4577/1/1295 +f 4483/1/1296 3811/1/1296 4371/1/1296 +f 4628/1/1297 3956/1/1297 4740/1/1297 +f 3751/1/1298 3785/1/1298 4423/1/1298 +f 4685/1/1299 4013/1/1299 4551/1/1299 +f 4346/1/1300 3674/1/1300 4514/1/1300 +f 4099/1/1301 3931/1/1301 4771/1/1301 +f 3982/1/1302 4094/1/1302 4654/1/1302 +f 3725/1/2354 3837/1/2354 4397/1/2354 +f 4577/1/1304 3905/1/1304 4689/1/1304 +f 3868/1/1305 3700/1/1305 4540/1/1305 +f 4713/1/1306 4041/1/1306 4629/1/1306 +f 3863/1/1307 3751/1/1307 4535/1/1307 +f 4048/1/1308 3880/1/1308 4720/1/1308 +f 4454/1/1309 3782/1/1309 4346/1/1309 +f 3931/1/1310 4043/1/1310 4603/1/1310 +f 4015/1/1311 3983/1/1311 4687/1/1311 +f 3810/1/1312 3726/1/1312 4482/1/1312 +f 3906/1/1313 4074/1/1313 4578/1/1313 +f 3700/1/1314 3812/1/1314 4372/1/1314 +f 4629/1/1315 3957/1/1315 4741/1/1315 +f 4458/1/1316 3786/1/1316 4424/1/1316 +f 3880/1/1317 4012/1/1317 4552/1/1317 +f 4347/1/1318 3675/1/1318 4515/1/1318 +f 4772/1/1319 4100/1/1319 4604/1/1319 +f 3983/1/1320 4095/1/1320 4655/1/1320 +f 3726/1/1321 3838/1/1321 4398/1/1321 +f 4018/1/2355 3906/1/2355 4690/1/2355 +f 4541/1/1323 3869/1/1323 4373/1/1323 +f 4042/1/1324 3958/1/1324 4714/1/1324 +f 4424/1/1325 3752/1/1325 4536/1/1325 +f 4553/1/1326 3881/1/1326 4721/1/1326 +f 4604/1/1327 3932/1/1327 4716/1/1327 +f 4455/1/1328 3783/1/1328 4347/1/1328 +f 4688/1/1329 4016/1/1329 4656/1/1329 +f 4399/1/1330 3727/1/1330 4483/1/1330 +f 4579/1/1331 3907/1/1331 4747/1/1331 +f 3958/1/1332 4070/1/1332 4630/1/1332 +f 4373/1/1333 3701/1/1333 4485/1/1333 +f 3778/1/1334 3753/1/1334 4450/1/1334 +f 4683/1/1335 4011/1/1335 4553/1/1335 +f 4773/1/1336 4101/1/1336 4605/1/1336 +f 3676/1/1337 3844/1/1337 4348/1/1337 +f 4656/1/1338 3984/1/1338 4768/1/1338 +f 4511/1/1339 3839/1/1339 4399/1/1339 +f 4691/1/1340 4019/1/1340 4579/1/1340 +f 4043/1/1341 3959/1/1341 4715/1/1341 +f 4374/1/1342 3702/1/1342 4542/1/1342 +f 3753/1/2356 3865/1/2356 4425/1/2356 +f 3882/1/1344 4050/1/1344 4554/1/1344 +f 4605/1/1345 3933/1/1345 4717/1/1345 +f 3776/1/1346 3676/1/1346 4448/1/1346 +f 4689/1/1347 4017/1/1347 4657/1/1347 +f 3812/1/1348 3728/1/1348 4484/1/1348 +f 4076/1/1349 3908/1/1349 4748/1/1349 +f 3959/1/1350 4071/1/1350 4631/1/1350 +f 4486/1/1351 3814/1/1351 4374/1/1351 +f 4010/1/1352 3882/1/1352 4682/1/1352 +f 3787/1/1353 3754/1/1353 4459/1/1353 +f 3934/1/1354 4018/1/1354 4606/1/1354 +f 3677/1/1355 3845/1/1355 4349/1/1355 +f 4657/1/1356 3985/1/1356 4769/1/1356 +f 3728/1/1357 3840/1/1357 4400/1/1357 +f 3908/1/1358 4020/1/1358 4580/1/1358 +f 4716/1/1359 4044/1/1359 4632/1/1359 +f 4375/1/1360 3703/1/1360 4543/1/1360 +f 4723/1/1361 4051/1/1361 4555/1/1361 +f 3754/1/1362 3866/1/1362 4426/1/1362 +f 4046/1/1363 3934/1/1363 4718/1/1363 +f 3784/1/1364 3677/1/1364 4456/1/1364 +f 4007/1/1365 3986/1/1365 4679/1/1365 +f 4485/1/1366 3813/1/1366 4401/1/1366 +f 4581/1/1367 3909/1/1367 4749/1/1367 +f 4632/1/1368 3960/1/1368 4744/1/1368 +f 4487/1/1369 3815/1/1369 4375/1/1369 +f 4555/1/1370 3883/1/1370 4681/1/1370 +f 4427/1/1371 3755/1/1371 4460/1/1371 +f 4607/1/1372 3935/1/1372 4691/1/1372 +f 4350/1/1373 3678/1/1373 4518/1/1373 +f 3986/1/1374 4098/1/1374 4658/1/1374 +f 4401/1/1375 3729/1/1375 4513/1/1375 +f 4693/1/1376 4021/1/1376 4581/1/1376 +f 4717/1/1377 4045/1/1377 4633/1/1377 +f 3704/1/1378 3872/1/1378 4376/1/1378 +f 3884/1/2357 4052/1/2357 4556/1/2357 +f 4539/1/1380 3867/1/1380 4427/1/1380 +f 4719/1/1381 4047/1/1381 4607/1/1381 +f 4462/1/1382 3790/1/1382 4350/1/1382 +f 3999/1/1383 3987/1/1383 4671/1/1383 +f 4402/1/1384 3730/1/1384 4486/1/1384 +f 3910/1/1385 4078/1/1385 4582/1/1385 +f 4633/1/2358 3961/1/2358 4745/1/2358 +f 3816/1/1387 3704/1/1387 4488/1/1387 +f 3992/1/2359 3884/1/2359 4664/1/2359 +f 3789/1/1389 3756/1/1389 4461/1/1389 +f 4020/1/1390 3936/1/1390 4692/1/1390 +f 4351/1/2360 3679/1/2360 4519/1/2360 +f 3987/1/1392 4099/1/1392 4659/1/1392 +f 4514/1/1393 3842/1/1393 4402/1/1393 +f 4022/1/1394 3910/1/1394 4694/1/1394 +f 3962/1/1395 4005/1/1395 4634/1/1395 +f 3705/1/1396 3873/1/1396 4377/1/1396 +f 3756/1/1397 3868/1/1397 4428/1/1397 +f 4557/1/1398 3885/1/1398 4725/1/1398 +f 3936/1/1399 4048/1/1399 4608/1/1399 +f 4463/1/1400 3791/1/1400 4351/1/1400 +f 4680/1/1401 4008/1/1401 4660/1/1401 +f 4403/1/1402 3731/1/1402 4487/1/1402 +f 4494/1/1403 3822/1/1403 4326/1/1403 +f 4751/1/1404 4079/1/1404 4583/1/1404 +f 4074/1/1405 3962/1/1405 4746/1/1405 +f 3817/1/1406 3705/1/1406 4489/1/1406 +f 4995/1/2361 4323/1/2361 4883/1/2361 +f 4162/1/2362 4274/1/2362 4834/1/2362 +f 4870/1/2363 4198/1/2363 4982/1/2363 +f 4821/1/2364 4149/1/2364 4933/1/2364 +f 4297/1/2365 4185/1/2365 4969/1/2365 +f 4808/1/2366 4136/1/2366 4920/1/2366 +f 4903/1/2367 4231/1/2367 4795/1/2367 +f 4110/1/1522 4218/1/1522 4782/1/1522 +f 4212/1/2368 4232/1/2368 4884/1/2368 +f 4835/1/2369 4163/1/2369 4919/1/2369 +f 4871/1/2370 4199/1/2370 4905/1/2370 +f 4822/1/2371 4150/1/2371 4990/1/2371 +f 4901/1/2372 4229/1/2372 4858/1/2372 +f 4305/1/2373 4137/1/2373 4977/1/2373 +f 4124/1/2374 4292/1/2374 4796/1/2374 +f 4257/1/2375 4173/1/2375 4929/1/2375 +f 4783/1/2376 4111/1/2376 4951/1/2376 +f 4324/1/2377 4212/1/2377 4996/1/2377 +f 4947/1/2378 4275/1/2378 4835/1/2378 +f 4983/1/2379 4311/1/2379 4871/1/2379 +f 4934/1/2380 4262/1/2380 4822/1/2380 +f 4137/1/2381 4249/1/2381 4809/1/2381 +f 4858/1/2382 4186/1/2382 4970/1/2382 +f 4224/1/2383 4124/1/2383 4896/1/2383 +f 4173/1/2384 4285/1/2384 4845/1/2384 +f 4891/1/2385 4219/1/2385 4783/1/2385 +f 4213/1/2386 4230/1/2386 4885/1/2386 +f 4920/1/2387 4248/1/2387 4836/1/2387 +f 4823/1/2388 4151/1/2388 4991/1/2388 +f 4234/1/2389 4200/1/2389 4906/1/2389 +f 4306/1/2390 4138/1/2390 4978/1/2390 +f 4215/1/2391 4187/1/2391 4887/1/2391 +f 4125/1/2392 4293/1/2392 4797/1/2392 +f 4258/1/2393 4174/1/2393 4930/1/2393 +f 4280/1/2394 4112/1/2394 4952/1/2394 +f 4325/1/2395 4213/1/2395 4997/1/2395 +f 4836/1/2396 4164/1/2396 4948/1/2396 +f 4935/1/2397 4263/1/2397 4823/1/2397 +f 4200/1/2398 4312/1/2398 4872/1/2398 +f 4138/1/2399 4250/1/2399 4810/1/2399 +f 4187/1/2400 4299/1/2400 4859/1/2400 +f 4232/1/2401 4125/1/2401 4904/1/2401 +f 4174/1/2402 4286/1/2402 4846/1/2402 +f 4112/1/2403 4220/1/2403 4784/1/2403 +f 4249/1/2404 4165/1/2404 4921/1/2404 +f 4152/1/2405 4320/1/2405 4824/1/2405 +f 4226/1/2406 4201/1/2406 4898/1/2406 +f 4811/1/2407 4139/1/2407 4979/1/2407 +f 4860/1/2408 4188/1/2408 4886/1/2408 +f 4798/1/2409 4126/1/2409 4966/1/2409 +f 4847/1/2410 4175/1/2410 4931/1/2410 +f 4785/1/2411 4113/1/2411 4953/1/2411 +f 4165/1/2412 4277/1/2412 4837/1/2412 +f 4264/1/2413 4152/1/2413 4936/1/2413 +f 4201/1/2414 4313/1/2414 4873/1/2414 +f 4923/1/2415 4251/1/2415 4811/1/2415 +f 4972/1/2416 4300/1/2416 4860/1/2416 +f 4910/1/2417 4238/1/2417 4798/1/2417 +f 4959/1/2418 4287/1/2418 4847/1/2418 +f 4893/1/2419 4221/1/2419 4785/1/2419 +f 4250/1/2420 4166/1/2420 4922/1/2420 +f 4153/1/2421 4321/1/2421 4825/1/2421 +f 4235/1/2422 4202/1/2422 4907/1/2422 +f 4308/1/2423 4140/1/2423 4980/1/2423 +f 4214/1/2424 4189/1/2424 4886/1/2424 +f 4799/1/2425 4127/1/2425 4967/1/2425 +f 4260/1/2426 4176/1/2426 4932/1/2426 +f 4954/1/2427 4282/1/2427 4786/1/2427 +f 4166/1/2428 4278/1/2428 4838/1/2428 +f 4265/1/2429 4153/1/2429 4937/1/2429 +f 4202/1/2430 4314/1/2430 4874/1/2430 +f 4140/1/2431 4252/1/2431 4812/1/2431 +f 4189/1/2432 4301/1/2432 4861/1/2432 +f 4176/1/2433 4288/1/2433 4848/1/2433 +f 4911/1/2434 4239/1/2434 4799/1/2434 +f 4786/1/2435 4114/1/2435 4894/1/2435 +f 4839/1/2436 4167/1/2436 4923/1/2436 +f 4875/1/2437 4203/1/2437 4908/1/2437 +f 4826/1/2438 4154/1/2438 4994/1/2438 +f 4220/1/2439 4190/1/2439 4892/1/2439 +f 4813/1/2440 4141/1/2440 4981/1/2440 +f 4933/1/2441 4261/1/2441 4849/1/2441 +f 4128/1/2442 4296/1/2442 4800/1/2442 +f 4115/1/2443 4283/1/2443 4787/1/2443 +f 4942/1/2444 4270/1/2444 4774/1/2444 +f 4951/1/2445 4279/1/2445 4839/1/2445 +f 4987/1/2446 4315/1/2446 4875/1/2446 +f 4938/1/2447 4266/1/2447 4826/1/2447 +f 4190/1/2448 4302/1/2448 4862/1/2448 +f 4925/1/2449 4253/1/2449 4813/1/2449 +f 4849/1/2450 4177/1/2450 4961/1/2450 +f 4240/1/2451 4128/1/2451 4912/1/2451 +f 4895/1/2452 4223/1/2452 4787/1/2452 +f 4774/1/2453 4102/1/2453 4887/1/2453 +f 4252/1/2454 4168/1/2454 4924/1/2454 +f 4237/1/2455 4204/1/2455 4909/1/2455 +f 4827/1/2456 4155/1/2456 4995/1/2456 +f 4863/1/2457 4191/1/2457 4891/1/2457 +f 4982/1/2458 4310/1/2458 4814/1/2458 +f 4850/1/2459 4178/1/2459 4934/1/2459 +f 4129/1/2460 4297/1/2460 4801/1/2460 +f 4956/1/2461 4284/1/2461 4788/1/2461 +f 4271/1/2462 4103/1/2462 4943/1/2462 +f 4168/1/2463 4280/1/2463 4840/1/2463 +f 4204/1/2464 4316/1/2464 4876/1/2464 +f 4939/1/2465 4267/1/2465 4827/1/2465 +f 4975/1/2466 4303/1/2466 4863/1/2466 +f 4814/1/2467 4142/1/2467 4926/1/2467 +f 4962/1/2468 4290/1/2468 4850/1/2468 +f 4241/1/2469 4129/1/2469 4913/1/2469 +f 4116/1/2470 4224/1/2470 4788/1/2470 +f 4103/1/2471 4237/1/2471 4775/1/2471 +f 4841/1/2472 4169/1/2472 4925/1/2472 +f 4894/1/2473 4222/1/2473 4877/1/2473 +f 4156/1/2474 4324/1/2474 4828/1/2474 +f 4890/1/2475 4218/1/2475 4864/1/2475 +f 4815/1/2476 4143/1/2476 4983/1/2476 +f 4851/1/2477 4179/1/2477 4935/1/2477 +f 4970/1/2478 4298/1/2478 4802/1/2478 +f 4285/1/2479 4117/1/2479 4957/1/2479 +f 4776/1/2480 4104/1/2480 4944/1/2480 +f 4953/1/2481 4281/1/2481 4841/1/2481 +f 4877/1/2482 4205/1/2482 4989/1/2482 +f 4268/1/2483 4156/1/2483 4940/1/2483 +f 4864/1/2484 4192/1/2484 4976/1/2484 +f 4927/1/2485 4255/1/2485 4815/1/2485 +f 4963/1/2486 4291/1/2486 4851/1/2486 +f 4802/1/2487 4130/1/2487 4914/1/2487 +f 4117/1/2488 4225/1/2488 4789/1/2488 +f 4908/1/2489 4236/1/2489 4776/1/2489 +f 4926/1/2490 4254/1/2490 4842/1/2490 +f 4878/1/2491 4206/1/2491 4910/1/2491 +f 4157/1/2492 4325/1/2492 4829/1/2492 +f 4228/1/2493 4193/1/2493 4900/1/2493 +f 4312/1/2494 4144/1/2494 4984/1/2494 +f 4299/1/2495 4131/1/2495 4971/1/2495 +f 4180/1/2496 4264/1/2496 4852/1/2496 +f 4286/1/2497 4118/1/2497 4958/1/2497 +f 4273/1/2498 4105/1/2498 4945/1/2498 +f 4842/1/2499 4170/1/2499 4954/1/2499 +f 4990/1/2500 4318/1/2500 4878/1/2500 +f 4269/1/2501 4157/1/2501 4941/1/2501 +f 4144/1/2502 4256/1/2502 4816/1/2502 +f 4193/1/2503 4305/1/2503 4865/1/2503 +f 4131/1/2504 4243/1/2504 4803/1/2504 +f 4292/1/2505 4180/1/2505 4964/1/2505 +f 4118/1/2506 4226/1/2506 4790/1/2506 +f 4105/1/2507 4235/1/2507 4777/1/2507 +f 4843/1/2508 4171/1/2508 4927/1/2508 +f 4879/1/2509 4207/1/2509 4911/1/2509 +f 4914/1/2510 4242/1/2510 4830/1/2510 +f 4313/1/2511 4145/1/2511 4985/1/2511 +f 4225/1/2512 4194/1/2512 4897/1/2512 +f 4804/1/2513 4132/1/2513 4972/1/2513 +f 4181/1/2514 4265/1/2514 4853/1/2514 +f 4791/1/2515 4119/1/2515 4959/1/2515 +f 4274/1/2516 4106/1/2516 4946/1/2516 +f 4283/1/2517 4171/1/2517 4955/1/2517 +f 4991/1/2518 4319/1/2518 4879/1/2518 +f 4830/1/2519 4158/1/2519 4942/1/2519 +f 4145/1/2520 4257/1/2520 4817/1/2520 +f 4194/1/2521 4306/1/2521 4866/1/2521 +f 4916/1/2522 4244/1/2522 4804/1/2522 +f 4293/1/2523 4181/1/2523 4965/1/2523 +f 4899/1/2524 4227/1/2524 4791/1/2524 +f 4106/1/2525 4234/1/2525 4778/1/2525 +f 4928/1/2526 4256/1/2526 4844/1/2526 +f 4208/1/2527 4240/1/2527 4880/1/2527 +f 4243/1/2528 4159/1/2528 4915/1/2528 +f 4314/1/2529 4146/1/2529 4986/1/2529 +f 4867/1/2530 4195/1/2530 4893/1/2530 +f 4301/1/2531 4133/1/2531 4973/1/2531 +f 4854/1/2532 4182/1/2532 4938/1/2532 +f 4288/1/2533 4120/1/2533 4960/1/2533 +f 4779/1/2534 4107/1/2534 4947/1/2534 +f 4844/1/2535 4172/1/2535 4956/1/2535 +f 4320/1/2536 4208/1/2536 4992/1/2536 +f 4159/1/2537 4271/1/2537 4831/1/2537 +f 4146/1/2538 4258/1/2538 4818/1/2538 +f 4979/1/2539 4307/1/2539 4867/1/2539 +f 4133/1/2540 4245/1/2540 4805/1/2540 +f 4966/1/2541 4294/1/2541 4854/1/2541 +f 4120/1/2542 4228/1/2542 4792/1/2542 +f 4905/1/2543 4233/1/2543 4779/1/2543 +f 4209/1/2544 4241/1/2544 4881/1/2544 +f 4832/1/2545 4160/1/2545 4916/1/2545 +f 4819/1/2546 4147/1/2546 4987/1/2546 +f 4217/1/2547 4196/1/2547 4889/1/2547 +f 4855/1/2548 4183/1/2548 4939/1/2548 +f 4302/1/2549 4134/1/2549 4974/1/2549 +f 4961/1/2550 4289/1/2550 4793/1/2550 +f 4948/1/2551 4276/1/2551 4780/1/2551 +f 4321/1/2552 4209/1/2552 4993/1/2552 +f 4944/1/2553 4272/1/2553 4832/1/2553 +f 4196/1/2554 4308/1/2554 4868/1/2554 +f 4931/1/2555 4259/1/2555 4819/1/2555 +f 4967/1/2556 4295/1/2556 4855/1/2556 +f 4134/1/2557 4246/1/2557 4806/1/2557 +f 4793/1/2558 4121/1/2558 4901/1/2558 +f 4780/1/2559 4108/1/2559 4888/1/2559 +f 4882/1/2560 4210/1/2560 4903/1/2560 +f 4245/1/2561 4161/1/2561 4917/1/2561 +f 4869/1/2562 4197/1/2562 4899/1/2562 +f 4316/1/2563 4148/1/2563 4988/1/2563 +f 4184/1/2564 4268/1/2564 4856/1/2564 +f 4807/1/2565 4135/1/2565 4975/1/2565 +f 4794/1/2566 4122/1/2566 4962/1/2566 +f 4277/1/2567 4109/1/2567 4949/1/2567 +f 4994/1/2568 4322/1/2568 4882/1/2568 +f 4161/1/2569 4273/1/2569 4833/1/2569 +f 4981/1/2570 4309/1/2570 4869/1/2570 +f 4148/1/2571 4260/1/2571 4820/1/2571 +f 4296/1/2572 4184/1/2572 4968/1/2572 +f 4919/1/2573 4247/1/2573 4807/1/2573 +f 4902/1/2574 4230/1/2574 4794/1/2574 +f 4109/1/2575 4217/1/2575 4781/1/2575 +f 4883/1/2576 4211/1/2576 4895/1/2576 +f 4246/1/2577 4162/1/2577 4918/1/2577 +f 4888/1/2578 4216/1/2578 4870/1/2578 +f 4989/1/2579 4317/1/2579 4821/1/2579 +f 4185/1/2580 4269/1/2580 4857/1/2580 +f 4976/1/2581 4304/1/2581 4808/1/2581 +f 4795/1/2582 4123/1/2582 4963/1/2582 +f 4278/1/2583 4110/1/2583 4950/1/2583 +f 5060/1/3 4978/1/3 5009/1/3 +f 5038/1/3 4898/1/3 5029/1/3 +f 5011/1/3 4817/1/3 5046/1/3 +f 5043/1/3 4920/1/3 5016/1/3 +f 5000/1/3 4780/1/3 5034/1/3 +f 5061/1/3 4982/1/3 5010/1/3 +f 5050/1/3 4945/1/3 4999/1/3 +f 5036/1/3 4894/1/3 5031/1/3 +f 5013/1/3 4821/1/3 5048/1/3 +f 5022/1/3 4858/1/3 5057/1/3 +f 5037/1/3 4897/1/3 5027/1/3 +f 5009/1/3 4810/1/3 5044/1/3 +f 5029/1/3 4873/1/3 5062/1/3 +f 5063/1/3 4986/1/3 5012/1/3 +f 5016/1/3 4836/1/3 5051/1/3 +f 5034/1/3 4888/1/3 5028/1/3 +f 4999/1/3 4777/1/3 5040/1/3 +f 5010/1/3 4814/1/3 5045/1/3 +f 5042/1/3 4917/1/3 5015/1/3 +f 5031/1/3 4877/1/3 5064/1/3 +f 5033/1/3 4887/1/3 5023/1/3 +f 5027/1/3 4866/1/3 5060/1/3 +f 5049/1/3 4942/1/3 4998/1/3 +f 5040/1/3 4907/1/3 5030/1/3 +f 5012/1/3 4818/1/3 5047/1/3 +f 5054/1/3 4957/1/3 5003/1/3 +f 5028/1/3 4870/1/3 5061/1/3 +f 5015/1/3 4833/1/3 5050/1/3 +f 4998/1/3 4774/1/3 5033/1/3 +f 5056/1/3 4961/1/3 5005/1/3 +f 5041/1/3 4914/1/3 5014/1/3 +f 5030/1/3 4874/1/3 5063/1/3 +f 5052/1/3 4950/1/3 5001/1/3 +f 5003/1/3 4789/1/3 5037/1/3 +f 5059/1/3 4976/1/3 5008/1/3 +f 5046/1/3 4929/1/3 5019/1/3 +f 5024/1/3 4860/1/3 5032/1/3 +f 5053/1/3 4954/1/3 5002/1/3 +f 5005/1/3 4793/1/3 5039/1/3 +f 5014/1/3 4830/1/3 5049/1/3 +f 5048/1/3 4933/1/3 5021/1/3 +f 5001/1/3 4782/1/3 5035/1/3 +f 5044/1/3 4922/1/3 5017/1/3 +f 5035/1/3 4890/1/3 5026/1/3 +f 5055/1/3 4958/1/3 5004/1/3 +f 5008/1/3 4808/1/3 5043/1/3 +f 5019/1/3 4845/1/3 5054/1/3 +f 5002/1/3 4786/1/3 5036/1/3 +f 5058/1/3 4973/1/3 5007/1/3 +f 5045/1/3 4926/1/3 5018/1/3 +f 5021/1/3 4849/1/3 5056/1/3 +f 5017/1/3 4838/1/3 5052/1/3 +f 5026/1/3 4864/1/3 5059/1/3 +f 5047/1/3 4930/1/3 5020/1/3 +f 5004/1/3 4790/1/3 5038/1/3 +f 5032/1/3 4886/1/3 5025/1/3 +f 5007/1/3 4805/1/3 5042/1/3 +f 5018/1/3 4842/1/3 5053/1/3 +f 5057/1/3 4970/1/3 5006/1/3 +f 5020/1/3 4846/1/3 5055/1/3 +f 5051/1/3 4948/1/3 5000/1/3 +f 5062/1/3 4985/1/3 5011/1/3 +f 5025/1/3 4861/1/3 5058/1/3 +f 5039/1/3 4901/1/3 5022/1/3 +f 5006/1/3 4802/1/3 5041/1/3 +f 5064/1/3 4989/1/3 5013/1/3 +f 2377/2/2584 3205/3/2584 2380/4/2584 +f 21/5/2585 2380/4/2585 2669/6/2585 +f 856/7/2586 2433/8/2586 1379/9/2586 +f 21/5/2587 1379/9/2587 2780/10/2587 +f 2373/11/2588 3204/12/2588 2376/13/2588 +f 22/14/2589 2376/13/2589 2668/15/2589 +f 855/16/2590 2411/17/2590 793/18/2590 +f 22/14/2591 793/18/2591 2606/19/2591 +f 2369/20/2592 3203/21/2592 2372/22/2592 +f 23/23/2593 2372/22/2593 2649/24/2593 +f 836/25/2594 2415/26/2594 1384/27/2594 +f 23/23/2595 1384/27/2595 2785/28/2595 +f 2365/29/2596 3202/30/2596 2368/31/2596 +f 24/32/2597 2368/31/2597 2662/33/2597 +f 849/34/2598 2430/35/2598 1376/36/2598 +f 24/32/2599 1376/36/2599 2777/37/2599 +f 2361/38/2600 3201/39/2600 2364/40/2600 +f 25/41/2601 2364/40/2601 2665/42/2601 +f 852/43/2602 2432/44/2602 1375/45/2602 +f 25/41/2603 1375/45/2603 2776/46/2603 +f 2357/47/2604 3200/48/2604 2360/49/2604 +f 26/50/2605 2360/49/2605 2664/51/2605 +f 851/52/2606 2431/53/2606 1357/54/2606 +f 26/50/2607 1357/54/2607 2758/55/2607 +f 2353/56/2608 3199/57/2608 2356/58/2608 +f 27/59/2609 2356/58/2609 2618/60/2609 +f 805/61/2610 2391/62/2610 803/63/2610 +f 27/59/2611 803/63/2611 2616/64/2611 +f 2349/65/2612 3198/66/2612 2352/67/2612 +f 28/68/2613 2352/67/2613 2619/69/2613 +f 806/70/2614 2393/71/2614 1342/72/2614 +f 28/68/2615 1342/72/2615 2743/73/2615 +f 2345/74/2616 3197/75/2616 2348/76/2616 +f 29/77/2617 2348/76/2617 2673/78/2617 +f 860/79/2618 2434/80/2618 1383/81/2618 +f 29/77/2619 1383/81/2619 2784/82/2619 +f 2341/83/2620 3196/84/2620 2344/85/2620 +f 30/86/2621 2344/85/2621 2634/87/2621 +f 821/88/2622 2405/89/2622 1318/90/2622 +f 30/86/2623 1318/90/2623 2719/91/2623 +f 31/92/2624 2337/93/2624 3195/94/2624 +f 2340/95/2625 2635/96/2625 822/97/2625 +f 31/92/2626 822/97/2626 2406/98/2626 +f 1361/99/2627 2762/100/2627 2337/93/2627 +f 2333/101/2628 3194/102/2628 2336/103/2628 +f 32/104/2629 2336/103/2629 2672/105/2629 +f 859/106/2630 2428/107/2630 1354/108/2630 +f 32/104/2631 1354/108/2631 2755/109/2631 +f 2329/110/2632 3193/111/2632 2332/112/2632 +f 33/113/2633 2332/112/2633 2638/114/2633 +f 33/113/2634 825/115/2634 2404/116/2634 +f 1319/117/2635 2720/118/2635 2329/110/2635 +f 2325/119/2636 3192/120/2636 2328/121/2636 +f 34/122/2637 2328/121/2637 2639/123/2637 +f 826/124/2638 2407/125/2638 1364/126/2638 +f 34/122/2639 1364/126/2639 2765/127/2639 +f 35/128/2640 2321/129/2640 3191/130/2640 +f 2324/131/2641 2631/132/2641 818/133/2641 +f 35/128/2642 818/133/2642 2403/134/2642 +f 1365/135/2643 2766/136/2643 2321/129/2643 +f 36/137/2644 2317/138/2644 3190/139/2644 +f 2320/140/2645 2642/141/2645 829/142/2645 +f 36/137/2646 829/142/2646 2400/143/2646 +f 815/144/2647 2628/145/2647 2317/138/2647 +f 37/146/2648 2313/147/2648 3189/148/2648 +f 2316/149/2649 2643/150/2649 830/151/2649 +f 37/146/2650 830/151/2650 2408/152/2650 +f 1368/153/2651 2769/154/2651 2313/147/2651 +f 2309/155/2652 3188/156/2652 2312/157/2652 +f 38/158/2653 2312/157/2653 2630/159/2653 +f 817/160/2654 2402/161/2654 1369/162/2654 +f 38/158/2655 1369/162/2655 2770/163/2655 +f 2305/164/2656 3187/165/2656 2308/166/2656 +f 39/167/2657 2308/166/2657 2646/168/2657 +f 39/167/2658 833/169/2658 2396/170/2658 +f 39/167/2659 811/171/2659 2624/172/2659 +f 2301/173/2660 3186/174/2660 2304/175/2660 +f 40/176/2661 2304/175/2661 2647/177/2661 +f 834/178/2662 2409/179/2662 1372/180/2662 +f 40/176/2663 1372/180/2663 2773/181/2663 +f 2297/182/2664 3185/183/2664 2300/184/2664 +f 41/185/2665 2300/184/2665 2661/186/2665 +f 848/187/2666 2429/188/2666 1380/189/2666 +f 41/185/2667 1380/189/2667 2781/190/2667 +f 42/191/2668 2293/192/2668 3184/193/2668 +f 2296/194/2669 2676/195/2669 863/196/2669 +f 42/191/2670 863/196/2670 2427/197/2670 +f 1353/198/2671 2754/199/2671 2293/192/2671 +f 43/200/2672 2289/201/2672 3183/202/2672 +f 2292/203/2673 2677/204/2673 864/205/2673 +f 43/200/2674 864/205/2674 2435/206/2674 +f 1387/207/2675 2788/208/2675 2289/201/2675 +f 44/209/2676 2285/210/2676 3182/211/2676 +f 2288/212/2677 2658/213/2677 845/214/2677 +f 44/209/2678 845/214/2678 2426/215/2678 +f 1388/216/2679 2789/217/2679 2285/210/2679 +f 45/218/2680 2281/219/2680 3181/220/2680 +f 2284/221/2681 2680/222/2681 867/223/2681 +f 45/218/2682 867/223/2682 2414/224/2682 +f 790/225/2683 2603/226/2683 2281/219/2683 +f 46/227/2684 2277/228/2684 3180/229/2684 +f 2280/230/2685 2681/231/2685 868/232/2685 +f 46/227/2686 868/232/2686 2436/233/2686 +f 1391/234/2687 2792/235/2687 2277/228/2687 +f 47/236/2688 2273/237/2688 3179/238/2688 +f 2276/239/2689 2657/240/2689 844/241/2689 +f 47/236/2690 844/241/2690 2425/242/2690 +f 1392/243/2691 2793/244/2691 2273/237/2691 +f 48/245/2692 2269/246/2692 3178/247/2692 +f 2272/248/2693 2684/249/2693 871/250/2693 +f 48/245/2694 871/250/2694 2424/251/2694 +f 1350/252/2695 2751/253/2695 2269/246/2695 +f 49/254/2696 2265/255/2696 3177/256/2696 +f 2268/257/2697 2685/258/2697 872/259/2697 +f 49/254/2698 872/259/2698 2437/260/2698 +f 1395/261/2699 2796/262/2699 2265/255/2699 +f 50/263/2700 2261/264/2700 3176/265/2700 +f 2264/266/2701 2637/267/2701 824/268/2701 +f 50/263/2702 824/268/2702 2416/269/2702 +f 1396/270/2703 2797/271/2703 2261/264/2703 +f 2257/272/2704 3175/273/2704 2260/274/2704 +f 51/275/2705 2260/274/2705 2688/276/2705 +f 875/277/2706 2423/278/2706 1349/279/2706 +f 51/275/2707 1349/279/2707 2750/280/2707 +f 2253/281/2708 3174/282/2708 2256/283/2708 +f 52/284/2709 2256/283/2709 2689/285/2709 +f 876/286/2710 2438/287/2710 1399/288/2710 +f 52/284/2711 1399/288/2711 2800/289/2711 +f 2249/290/2712 3173/291/2712 2252/292/2712 +f 53/293/2713 2252/292/2713 2654/294/2713 +f 841/295/2714 2422/296/2714 1400/297/2714 +f 53/293/2715 1400/297/2715 2801/298/2715 +f 2245/299/2716 3172/300/2716 2248/301/2716 +f 54/302/2717 2248/301/2717 2692/303/2717 +f 54/302/2718 879/304/2718 2385/305/2718 +f 1329/306/2719 2730/307/2719 2245/299/2719 +f 2241/308/2720 3171/309/2720 2244/310/2720 +f 55/311/2721 2244/310/2721 2693/312/2721 +f 880/313/2722 2439/314/2722 1403/315/2722 +f 55/311/2723 1403/315/2723 2804/316/2723 +f 2237/317/2724 3170/318/2724 2240/319/2724 +f 56/320/2725 2240/319/2725 2653/321/2725 +f 840/322/2726 2421/323/2726 1404/324/2726 +f 56/320/2727 1404/324/2727 2805/325/2727 +f 57/326/2728 2233/327/2728 3169/328/2728 +f 2236/329/2729 2696/330/2729 883/331/2729 +f 57/326/2730 883/331/2730 2420/332/2730 +f 1345/333/2731 2746/334/2731 2233/327/2731 +f 58/335/2732 2229/336/2732 3168/337/2732 +f 2232/338/2733 2697/339/2733 884/340/2733 +f 58/335/2734 884/340/2734 2440/341/2734 +f 1407/342/2735 2808/343/2735 2229/336/2735 +f 59/344/2736 2225/345/2736 3167/346/2736 +f 2228/347/2737 2651/348/2737 838/349/2737 +f 59/344/2738 838/349/2738 2419/350/2738 +f 1408/351/2739 2809/352/2739 2225/345/2739 +f 2221/353/2740 3166/354/2740 2224/355/2740 +f 60/356/2741 2224/355/2741 2700/357/2741 +f 887/358/2742 2384/359/2742 1330/360/2742 +f 60/356/2743 1330/360/2743 2731/361/2743 +f 61/362/2744 2217/363/2744 3165/364/2744 +f 2220/365/2745 2701/366/2745 888/367/2745 +f 61/362/2746 888/367/2746 2441/368/2746 +f 1411/369/2747 2812/370/2747 2217/363/2747 +f 62/371/2748 2213/372/2748 3164/373/2748 +f 2216/374/2749 2650/375/2749 837/376/2749 +f 62/371/2750 837/376/2750 2418/377/2750 +f 1412/378/2751 2813/379/2751 2213/372/2751 +f 2209/380/2752 3163/381/2752 2212/382/2752 +f 63/383/2753 2212/382/2753 2704/384/2753 +f 891/385/2754 2417/386/2754 1341/387/2754 +f 63/383/2755 1341/387/2755 2742/388/2755 +f 64/389/2756 2205/390/2756 3162/391/2756 +f 2208/392/2757 2705/393/2757 892/394/2757 +f 64/389/2758 892/394/2758 2442/395/2758 +f 1415/396/2759 2816/397/2759 2205/390/2759 +f 65/398/2760 2201/399/2760 3161/400/2760 +f 2204/401/2761 2611/402/2761 798/403/2761 +f 65/398/2762 798/403/2762 2386/404/2762 +f 1416/405/2763 2817/406/2763 2201/399/2763 +f 2197/407/2764 3160/408/2764 2200/409/2764 +f 66/410/2765 2200/409/2765 2708/411/2765 +f 895/412/2766 2388/413/2766 800/414/2766 +f 66/410/2767 800/414/2767 2613/415/2767 +f 2193/416/2768 3159/417/2768 2196/418/2768 +f 67/419/2769 2196/418/2769 2709/420/2769 +f 896/421/2770 2443/422/2770 1419/423/2770 +f 67/419/2771 1419/423/2771 2820/424/2771 +f 2189/425/2772 3158/426/2772 2192/427/2772 +f 68/428/2773 2192/427/2773 2612/429/2773 +f 799/430/2774 2387/431/2774 1420/432/2774 +f 68/428/2775 1420/432/2775 2821/433/2775 +f 2185/434/2776 3157/435/2776 2188/436/2776 +f 69/437/2777 2188/436/2777 2822/438/2777 +f 1009/439/2778 2553/440/2778 1310/441/2778 +f 69/437/2779 1310/441/2779 2711/442/2779 +f 2181/443/2780 3156/444/2780 2184/445/2780 +f 70/446/2781 2184/445/2781 2823/447/2781 +f 1010/448/2782 2554/449/2782 1423/450/2782 +f 70/446/2783 1423/450/2783 2824/451/2783 +f 2177/452/2784 3155/453/2784 2180/454/2784 +f 71/455/2785 2180/454/2785 2722/456/2785 +f 909/457/2786 2454/458/2786 1424/459/2786 +f 71/455/2787 1424/459/2787 2825/460/2787 +f 72/461/2788 2173/462/2788 3154/463/2788 +f 2176/464/2789 2826/465/2789 1013/466/2789 +f 72/461/2790 1013/466/2790 2552/467/2790 +f 1309/468/2791 2710/469/2791 2173/462/2791 +f 73/470/2792 2169/471/2792 3153/472/2792 +f 2172/473/2793 2827/474/2793 1014/475/2793 +f 73/470/2794 1014/475/2794 2555/476/2794 +f 1427/477/2795 2828/478/2795 2169/471/2795 +f 2165/479/2796 3152/480/2796 2168/481/2796 +f 74/482/2797 2168/481/2797 2819/483/2797 +f 1006/484/2798 2551/485/2798 1428/486/2798 +f 74/482/2799 1428/486/2799 2829/487/2799 +f 75/488/2800 2161/489/2800 3151/490/2800 +f 2164/491/2801 2830/492/2801 1017/493/2801 +f 75/488/2802 1017/493/2802 2455/494/2802 +f 910/495/2803 2723/496/2803 2161/489/2803 +f 76/497/2804 2157/498/2804 3150/499/2804 +f 2160/500/2805 2831/501/2805 1018/502/2805 +f 76/497/2806 1018/502/2806 2556/503/2806 +f 1431/504/2807 2832/505/2807 2157/498/2807 +f 2153/506/2808 3149/507/2808 2156/508/2808 +f 77/509/2809 2156/508/2809 2818/510/2809 +f 1005/511/2810 2550/512/2810 1432/513/2810 +f 77/509/2811 1432/513/2811 2833/514/2811 +f 78/515/2812 2149/516/2812 3148/517/2812 +f 2152/518/2813 2834/519/2813 1021/520/2813 +f 78/515/2814 1021/520/2814 2549/521/2814 +f 1306/522/2815 2707/523/2815 2149/516/2815 +f 79/524/2816 2145/525/2816 3147/526/2816 +f 2148/527/2817 2835/528/2817 1022/529/2817 +f 79/524/2818 1022/529/2818 2557/530/2818 +f 1435/531/2819 2836/532/2819 2145/525/2819 +f 80/533/2820 2141/534/2820 3146/535/2820 +f 2144/536/2821 2721/537/2821 908/538/2821 +f 80/533/2822 908/538/2822 2453/539/2822 +f 1436/540/2823 2837/541/2823 2141/534/2823 +f 2137/542/2824 3145/543/2824 2140/544/2824 +f 81/545/2825 2140/544/2825 2838/546/2825 +f 1025/547/2826 2548/548/2826 1305/549/2826 +f 81/545/2827 1305/549/2827 2706/550/2827 +f 2133/551/2828 3144/552/2828 2136/553/2828 +f 82/554/2829 2136/553/2829 2839/555/2829 +f 1026/556/2830 2558/557/2830 1439/558/2830 +f 82/554/2831 1439/558/2831 2840/559/2831 +f 83/560/2832 2129/561/2832 3143/562/2832 +f 2132/563/2833 2815/564/2833 1002/565/2833 +f 83/560/2834 1002/565/2834 2547/566/2834 +f 1440/567/2835 2841/568/2835 2129/561/2835 +f 84/569/2836 2125/570/2836 3142/571/2836 +f 2128/572/2837 2842/573/2837 1029/574/2837 +f 84/569/2838 1029/574/2838 2474/575/2838 +f 1231/576/2839 2632/577/2839 2125/570/2839 +f 2121/578/2840 3141/579/2840 2124/580/2840 +f 85/581/2841 2124/580/2841 2843/582/2841 +f 1030/583/2842 2559/584/2842 1443/585/2842 +f 85/581/2843 1443/585/2843 2844/586/2843 +f 86/587/2844 2117/588/2844 3140/589/2844 +f 2120/590/2845 2814/591/2845 1001/592/2845 +f 86/587/2846 1001/592/2846 2546/593/2846 +f 1444/594/2847 2845/595/2847 2117/588/2847 +f 87/596/2848 2113/597/2848 3139/598/2848 +f 2116/599/2849 2846/600/2849 1033/601/2849 +f 87/596/2850 1033/601/2850 2545/602/2850 +f 1302/603/2851 2703/604/2851 2113/597/2851 +f 88/605/2852 2109/606/2852 3138/607/2852 +f 2112/608/2853 2847/609/2853 1034/610/2853 +f 88/605/2854 1034/610/2854 2560/611/2854 +f 1447/612/2855 2848/613/2855 2109/606/2855 +f 89/614/2856 2105/615/2856 3137/616/2856 +f 2108/617/2857 2760/618/2857 947/619/2857 +f 89/614/2858 947/619/2858 2492/620/2858 +f 1448/621/2859 2849/622/2859 2105/615/2859 +f 90/623/2860 2101/624/2860 3136/625/2860 +f 2104/626/2861 2850/627/2861 1037/628/2861 +f 90/623/2862 1037/628/2862 2544/629/2862 +f 1301/630/2863 2702/631/2863 2101/624/2863 +f 91/632/2864 2097/633/2864 3135/634/2864 +f 2100/635/2865 2851/636/2865 1038/637/2865 +f 91/632/2866 1038/637/2866 2561/638/2866 +f 1451/639/2867 2852/640/2867 2097/633/2867 +f 92/641/2868 2093/642/2868 3134/643/2868 +f 2096/644/2869 2811/645/2869 998/646/2869 +f 92/641/2870 998/646/2870 2543/647/2870 +f 1452/648/2871 2853/649/2871 2093/642/2871 +f 2089/650/2872 3133/651/2872 2092/652/2872 +f 93/653/2873 2092/652/2873 2854/654/2873 +f 1041/655/2874 2463/656/2874 1220/657/2874 +f 93/653/2875 1220/657/2875 2621/658/2875 +f 94/659/2876 2085/660/2876 3132/661/2876 +f 2088/662/2877 2855/663/2877 1042/664/2877 +f 94/659/2878 1042/664/2878 2562/665/2878 +f 1455/666/2879 2856/667/2879 2085/660/2879 +f 95/668/2880 2081/669/2880 3131/670/2880 +f 2084/671/2881 2810/672/2881 997/673/2881 +f 95/668/2882 997/673/2882 2542/674/2882 +f 1456/675/2883 2857/676/2883 2081/669/2883 +f 96/677/2884 2077/678/2884 3130/679/2884 +f 2080/680/2885 2858/681/2885 1045/682/2885 +f 96/677/2886 1045/682/2886 2541/683/2886 +f 1298/684/2887 2699/685/2887 2077/678/2887 +f 97/686/2888 2073/687/2888 3129/688/2888 +f 2076/689/2889 2859/690/2889 1046/691/2889 +f 97/686/2890 1046/691/2890 2563/692/2890 +f 1459/693/2891 2860/694/2891 2073/687/2891 +f 98/695/2892 2069/696/2892 3128/697/2892 +f 2072/698/2893 2761/699/2893 948/700/2893 +f 98/695/2894 948/700/2894 2493/701/2894 +f 1460/702/2895 2861/703/2895 2069/696/2895 +f 99/704/2896 2065/705/2896 3127/706/2896 +f 2068/707/2897 2862/708/2897 1049/709/2897 +f 99/704/2898 1049/709/2898 2540/710/2898 +f 1297/711/2899 2698/712/2899 2065/705/2899 +f 100/713/2900 2061/714/2900 3126/715/2900 +f 2064/716/2901 2863/717/2901 1050/718/2901 +f 100/713/2902 1050/718/2902 2564/719/2902 +f 1463/720/2903 2864/721/2903 2061/714/2903 +f 101/722/2904 2057/723/2904 3125/724/2904 +f 2060/725/2905 2807/726/2905 994/727/2905 +f 101/722/2906 994/727/2906 2539/728/2906 +f 1464/729/2907 2865/730/2907 2057/723/2907 +f 102/731/2908 2053/732/2908 3124/733/2908 +f 2056/734/2909 2866/735/2909 1053/736/2909 +f 102/731/2910 1053/736/2910 2478/737/2910 +f 1235/738/2911 2636/739/2911 2053/732/2911 +f 103/740/2912 2049/741/2912 3123/742/2912 +f 2052/743/2913 2867/744/2913 1054/745/2913 +f 103/740/2914 1054/745/2914 2565/746/2914 +f 1467/747/2915 2868/748/2915 2049/741/2915 +f 104/749/2916 2045/750/2916 3122/751/2916 +f 2048/752/2917 2806/753/2917 993/754/2917 +f 104/749/2918 993/754/2918 2538/755/2918 +f 1468/756/2919 2869/757/2919 2045/750/2919 +f 2041/758/2920 3121/759/2920 2044/760/2920 +f 105/761/2921 2044/760/2921 2870/762/2921 +f 1057/763/2922 2537/764/2922 1294/765/2922 +f 105/761/2923 1294/765/2923 2695/766/2923 +f 2037/767/2924 3120/768/2924 2040/769/2924 +f 106/770/2925 2040/769/2925 2871/771/2925 +f 1058/772/2926 2566/773/2926 1471/774/2926 +f 106/770/2927 1471/774/2927 2872/775/2927 +f 2033/776/2928 3119/777/2928 2036/778/2928 +f 107/779/2929 2036/778/2929 2763/780/2929 +f 950/781/2930 2495/782/2930 1472/783/2930 +f 107/779/2931 1472/783/2931 2873/784/2931 +f 2029/785/2932 3118/786/2932 2032/787/2932 +f 108/788/2933 2032/787/2933 2874/789/2933 +f 1061/790/2934 2536/791/2934 1293/792/2934 +f 108/788/2935 1293/792/2935 2694/793/2935 +f 2025/794/2936 3117/795/2936 2028/796/2936 +f 109/797/2937 2028/796/2937 2875/798/2937 +f 1062/799/2938 2567/800/2938 1475/801/2938 +f 109/797/2939 1475/801/2939 2876/802/2939 +f 2021/803/2940 3116/804/2940 2024/805/2940 +f 110/806/2941 2024/805/2941 2803/807/2941 +f 990/808/2942 2535/809/2942 1476/810/2942 +f 110/806/2943 1476/810/2943 2877/811/2943 +f 2017/812/2944 3115/813/2944 2020/814/2944 +f 111/815/2945 2020/814/2945 2878/816/2945 +f 111/815/2946 1065/817/2946 2462/818/2946 +f 1219/819/2947 2620/820/2947 2017/812/2947 +f 2013/821/2948 3114/822/2948 2016/823/2948 +f 112/824/2949 2016/823/2949 2879/825/2949 +f 1066/826/2950 2568/827/2950 1479/828/2950 +f 112/824/2951 1479/828/2951 2880/829/2951 +f 2009/830/2952 3113/831/2952 2012/832/2952 +f 113/833/2953 2012/832/2953 2802/834/2953 +f 989/835/2954 2534/836/2954 1480/837/2954 +f 113/833/2955 1480/837/2955 2881/838/2955 +f 2005/839/2956 3112/840/2956 2008/841/2956 +f 114/842/2957 2008/841/2957 2882/843/2957 +f 1069/844/2958 2533/845/2958 1290/846/2958 +f 114/842/2959 1290/846/2959 2691/847/2959 +f 2001/848/2960 3111/849/2960 2004/850/2960 +f 115/851/2961 2004/850/2961 2883/852/2961 +f 1070/853/2962 2569/854/2962 1483/855/2962 +f 115/851/2963 1483/855/2963 2884/856/2963 +f 1997/857/2964 3110/858/2964 2000/859/2964 +f 116/860/2965 2000/859/2965 2764/861/2965 +f 951/862/2966 2496/863/2966 1484/864/2966 +f 116/860/2967 1484/864/2967 2885/865/2967 +f 1993/866/2968 3109/867/2968 1996/868/2968 +f 117/869/2969 1996/868/2969 2886/870/2969 +f 1073/871/2970 2532/872/2970 1289/873/2970 +f 117/869/2971 1289/873/2971 2690/874/2971 +f 1989/875/2972 3108/876/2972 1992/877/2972 +f 118/878/2973 1992/877/2973 2887/879/2973 +f 1074/880/2974 2570/881/2974 1487/882/2974 +f 118/878/2975 1487/882/2975 2888/883/2975 +f 1985/884/2976 3107/885/2976 1988/886/2976 +f 119/887/2977 1988/886/2977 2799/888/2977 +f 986/889/2978 2531/890/2978 1488/891/2978 +f 119/887/2979 1488/891/2979 2889/892/2979 +f 1981/893/2980 3106/894/2980 1984/895/2980 +f 120/896/2981 1984/895/2981 2890/897/2981 +f 1077/898/2982 2482/899/2982 1239/900/2982 +f 120/896/2983 1239/900/2983 2640/901/2983 +f 1977/902/2984 3105/903/2984 1980/904/2984 +f 121/905/2985 1980/904/2985 2891/906/2985 +f 1078/907/2986 2571/908/2986 1491/909/2986 +f 121/905/2987 1491/909/2987 2892/910/2987 +f 1973/911/2988 3104/912/2988 1976/913/2988 +f 122/914/2989 1976/913/2989 2798/915/2989 +f 985/916/2990 2530/917/2990 1492/918/2990 +f 122/914/2991 1492/918/2991 2893/919/2991 +f 123/920/2992 1969/921/2992 3103/922/2992 +f 1972/923/2993 2894/924/2993 1081/925/2993 +f 123/920/2994 1081/925/2994 2529/926/2994 +f 1286/927/2995 2687/928/2995 1969/921/2995 +f 124/929/2996 1965/930/2996 3102/931/2996 +f 1968/932/2997 2895/933/2997 1082/934/2997 +f 124/929/2998 1082/934/2998 2572/935/2998 +f 1495/936/2999 2896/937/2999 1965/930/2999 +f 125/938/3000 1961/939/3000 3101/940/3000 +f 1964/941/3001 2747/942/3001 934/943/3001 +f 125/938/3002 934/943/3002 2479/944/3002 +f 1496/945/3003 2897/946/3003 1961/939/3003 +f 1957/947/3004 3100/948/3004 1960/949/3004 +f 126/950/3005 1960/949/3005 2898/951/3005 +f 1085/952/3006 2528/953/3006 1285/954/3006 +f 126/950/3007 1285/954/3007 2686/955/3007 +f 1953/956/3008 3099/957/3008 1956/958/3008 +f 127/959/3009 1956/958/3009 2899/960/3009 +f 1086/961/3010 2573/962/3010 1499/963/3010 +f 127/959/3011 1499/963/3011 2900/964/3011 +f 128/965/3012 1949/966/3012 3098/967/3012 +f 1952/968/3013 2795/969/3013 982/970/3013 +f 128/965/3014 982/970/3014 2527/971/3014 +f 1500/972/3015 2901/973/3015 1949/966/3015 +f 1945/974/3016 3097/975/3016 1948/976/3016 +f 129/977/3017 1948/976/3017 2902/978/3017 +f 1089/979/3018 2483/980/3018 1240/981/3018 +f 129/977/3019 1240/981/3019 2641/982/3019 +f 1941/983/3020 3096/984/3020 1944/985/3020 +f 130/986/3021 1944/985/3021 2903/987/3021 +f 1090/988/3022 2574/989/3022 1503/990/3022 +f 130/986/3023 1503/990/3023 2904/991/3023 +f 131/992/3024 1937/993/3024 3095/994/3024 +f 1940/995/3025 2794/996/3025 981/997/3025 +f 131/992/3026 981/997/3026 2526/998/3026 +f 1504/999/3027 2905/1000/3027 1937/993/3027 +f 132/1001/3028 1933/1002/3028 3094/1003/3028 +f 1936/1004/3029 2906/1005/3029 1093/1006/3029 +f 132/1001/3030 1093/1006/3030 2525/1007/3030 +f 1282/1008/3031 2683/1009/3031 1933/1002/3031 +f 133/1010/3032 1929/1011/3032 3093/1012/3032 +f 1932/1013/3033 2907/1014/3033 1094/1015/3033 +f 133/1010/3034 1094/1015/3034 2575/1016/3034 +f 1507/1017/3035 2908/1018/3035 1929/1011/3035 +f 134/1019/3036 1925/1020/3036 3092/1021/3036 +f 1928/1022/3037 2767/1023/3037 954/1024/3037 +f 134/1019/3038 954/1024/3038 2499/1025/3038 +f 1508/1026/3039 2909/1027/3039 1925/1020/3039 +f 135/1028/3040 1921/1029/3040 3091/1030/3040 +f 1924/1031/3041 2910/1032/3041 1097/1033/3041 +f 135/1028/3042 1097/1033/3042 2524/1034/3042 +f 1281/1035/3043 2682/1036/3043 1921/1029/3043 +f 136/1037/3044 1917/1038/3044 3090/1039/3044 +f 1920/1040/3045 2911/1041/3045 1098/1042/3045 +f 136/1037/3046 1098/1042/3046 2576/1043/3046 +f 1511/1044/3047 2912/1045/3047 1917/1038/3047 +f 137/1046/3048 1913/1047/3048 3089/1048/3048 +f 1916/1049/3049 2791/1050/3049 978/1051/3049 +f 137/1046/3050 978/1051/3050 2523/1052/3050 +f 1512/1053/3051 2913/1054/3051 1913/1047/3051 +f 138/1055/3052 1909/1056/3052 3088/1057/3052 +f 1912/1058/3053 2914/1059/3053 1101/1060/3053 +f 138/1055/3054 1101/1060/3054 2445/1061/3054 +f 900/1062/3055 2713/1063/3055 1909/1056/3055 +f 139/1064/3056 1905/1065/3056 3087/1066/3056 +f 1908/1067/3057 2915/1068/3057 1102/1069/3057 +f 139/1064/3058 1102/1069/3058 2577/1070/3058 +f 1515/1071/3059 2916/1072/3059 1905/1065/3059 +f 140/1073/3060 1901/1074/3060 3086/1075/3060 +f 1904/1076/3061 2790/1077/3061 977/1078/3061 +f 140/1073/3062 977/1078/3062 2522/1079/3062 +f 1516/1080/3063 2917/1081/3063 1901/1074/3063 +f 141/1082/3064 1897/1083/3064 3085/1084/3064 +f 1900/1085/3065 2918/1086/3065 1105/1087/3065 +f 141/1082/3066 1105/1087/3066 2521/1088/3066 +f 1278/1089/3067 2679/1090/3067 1897/1083/3067 +f 142/1091/3068 1893/1092/3068 3084/1093/3068 +f 1896/1094/3069 2919/1095/3069 1106/1096/3069 +f 142/1091/3070 1106/1096/3070 2578/1097/3070 +f 1519/1098/3071 2920/1099/3071 1893/1092/3071 +f 143/1100/3072 1889/1101/3072 3083/1102/3072 +f 1892/1103/3073 2768/1104/3073 955/1105/3073 +f 143/1100/3074 955/1105/3074 2500/1106/3074 +f 1520/1107/3075 2921/1108/3075 1889/1101/3075 +f 144/1109/3076 1885/1110/3076 3082/1111/3076 +f 1888/1112/3077 2922/1113/3077 1109/1114/3077 +f 144/1109/3078 1109/1114/3078 2520/1115/3078 +f 1277/1116/3079 2678/1117/3079 1885/1110/3079 +f 145/1118/3080 1881/1119/3080 3081/1120/3080 +f 1884/1121/3081 2923/1122/3081 1110/1123/3081 +f 145/1118/3082 1110/1123/3082 2579/1124/3082 +f 1523/1125/3083 2924/1126/3083 1881/1119/3083 +f 146/1127/3084 1877/1128/3084 3080/1129/3084 +f 1880/1130/3085 2787/1131/3085 974/1132/3085 +f 146/1127/3086 974/1132/3086 2519/1133/3086 +f 1524/1134/3087 2925/1135/3087 1877/1128/3087 +f 147/1136/3088 1873/1137/3088 3079/1138/3088 +f 1876/1139/3089 2926/1140/3089 1113/1141/3089 +f 147/1136/3090 1113/1141/3090 2486/1142/3090 +f 1243/1143/3091 2644/1144/3091 1873/1137/3091 +f 148/1145/3092 1869/1146/3092 3078/1147/3092 +f 1872/1148/3093 2927/1149/3093 1114/1150/3093 +f 148/1145/3094 1114/1150/3094 2580/1151/3094 +f 1527/1152/3095 2928/1153/3095 1869/1146/3095 +f 149/1154/3096 1865/1155/3096 3077/1156/3096 +f 1868/1157/3097 2786/1158/3097 973/1159/3097 +f 149/1154/3098 973/1159/3098 2518/1160/3098 +f 1528/1161/3099 2929/1162/3099 1865/1155/3099 +f 1861/1163/3100 3076/1164/3100 1864/1165/3100 +f 150/1166/3101 1864/1165/3101 2930/1167/3101 +f 1117/1168/3102 2513/1169/3102 1270/1170/3102 +f 150/1166/3103 1270/1170/3103 2671/1171/3103 +f 1857/1172/3104 3075/1173/3104 1860/1174/3104 +f 151/1175/3105 1860/1174/3105 2931/1176/3105 +f 1118/1177/3106 2581/1178/3106 1531/1179/3106 +f 151/1175/3107 1531/1179/3107 2932/1180/3107 +f 1853/1181/3108 3074/1182/3108 1856/1183/3108 +f 152/1184/3109 1856/1183/3109 2771/1185/3109 +f 958/1186/3110 2503/1187/3110 1532/1188/3110 +f 152/1184/3111 1532/1188/3111 2933/1189/3111 +f 1849/1190/3112 3073/1191/3112 1852/1192/3112 +f 153/1193/3113 1852/1192/3113 2934/1194/3113 +f 1121/1195/3114 2505/1196/3114 1262/1197/3114 +f 153/1193/3115 1262/1197/3115 2663/1198/3115 +f 1845/1199/3116 3072/1200/3116 1848/1201/3116 +f 154/1202/3117 1848/1201/3117 2935/1203/3117 +f 1122/1204/3118 2582/1205/3118 1535/1206/3118 +f 154/1202/3119 1535/1206/3119 2936/1207/3119 +f 1841/1208/3120 3071/1209/3120 1844/1210/3120 +f 155/1211/3121 1844/1210/3121 2757/1212/3121 +f 944/1213/3122 2489/1214/3122 1536/1215/3122 +f 155/1211/3123 1536/1215/3123 2937/1216/3123 +f 1837/1217/3124 3070/1218/3124 1840/1219/3124 +f 156/1220/3125 1840/1219/3125 2938/1221/3125 +f 1125/1222/3126 2466/1223/3126 921/1224/3126 +f 156/1220/3127 921/1224/3127 2734/1225/3127 +f 1833/1226/3128 3069/1227/3128 1836/1228/3128 +f 157/1229/3129 1836/1228/3129 2939/1230/3129 +f 1126/1231/3130 2583/1232/3130 1539/1233/3130 +f 157/1229/3131 1539/1233/3131 2940/1234/3131 +f 1829/1235/3132 3068/1236/3132 1832/1237/3132 +f 158/1238/3133 1832/1237/3133 2756/1239/3133 +f 943/1240/3134 2488/1241/3134 1540/1242/3134 +f 158/1238/3135 1540/1242/3135 2941/1243/3135 +f 1825/1244/3136 3067/1245/3136 1828/1246/3136 +f 159/1247/3137 1828/1246/3137 2942/1248/3137 +f 1129/1249/3138 2502/1250/3138 1259/1251/3138 +f 159/1247/3139 1259/1251/3139 2660/1252/3139 +f 1821/1253/3140 3066/1254/3140 1824/1255/3140 +f 160/1256/3141 1824/1255/3141 2943/1257/3141 +f 1130/1258/3142 2584/1259/3142 1543/1260/3142 +f 160/1256/3143 1543/1260/3143 2944/1261/3143 +f 1817/1262/3144 3065/1263/3144 1820/1264/3144 +f 161/1265/3145 1820/1264/3145 2740/1266/3145 +f 927/1267/3146 2472/1268/3146 1544/1269/3146 +f 161/1265/3147 1544/1269/3147 2945/1270/3147 +f 162/1271/3148 1813/1272/3148 3064/1273/3148 +f 1816/1274/3149 2946/1275/3149 1133/1276/3149 +f 162/1271/3150 1133/1276/3150 2501/1277/3150 +f 1258/1278/3151 2659/1279/3151 1813/1272/3151 +f 163/1280/3152 1809/1281/3152 3063/1282/3152 +f 1812/1283/3153 2947/1284/3153 1134/1285/3153 +f 163/1280/3154 1134/1285/3154 2585/1286/3154 +f 1547/1287/3155 2948/1288/3155 1809/1281/3155 +f 164/1289/3156 1805/1290/3156 3062/1291/3156 +f 1808/1292/3157 2753/1293/3157 940/1294/3157 +f 164/1289/3158 940/1294/3158 2485/1295/3158 +f 1548/1296/3159 2949/1297/3159 1805/1290/3159 +f 165/1298/3160 1801/1299/3160 3061/1300/3160 +f 1804/1301/3161 2950/1302/3161 1137/1303/3161 +f 165/1298/3162 1137/1303/3162 2470/1304/3162 +f 925/1305/3163 2738/1306/3163 1801/1299/3163 +f 166/1307/3164 1797/1308/3164 3060/1309/3164 +f 1800/1310/3165 2951/1311/3165 1138/1312/3165 +f 166/1307/3166 1138/1312/3166 2586/1313/3166 +f 1551/1314/3167 2952/1315/3167 1797/1308/3167 +f 167/1316/3168 1793/1317/3168 3059/1318/3168 +f 1796/1319/3169 2752/1320/3169 939/1321/3169 +f 167/1316/3170 939/1321/3170 2484/1322/3170 +f 1552/1323/3171 2953/1324/3171 1793/1317/3171 +f 168/1325/3172 1789/1326/3172 3058/1327/3172 +f 1792/1328/3173 2954/1329/3173 1141/1330/3173 +f 168/1325/3174 1141/1330/3174 2498/1331/3174 +f 1255/1332/3175 2656/1333/3175 1789/1326/3175 +f 169/1334/3176 1785/1335/3176 3057/1336/3176 +f 1788/1337/3177 2955/1338/3177 1142/1339/3177 +f 169/1334/3178 1142/1339/3178 2587/1340/3178 +f 1555/1341/3179 2956/1342/3179 1785/1335/3179 +f 170/1343/3180 1781/1344/3180 3056/1345/3180 +f 1784/1346/3181 2741/1347/3181 928/1348/3181 +f 170/1343/3182 928/1348/3182 2473/1349/3182 +f 1556/1350/3183 2957/1351/3183 1781/1344/3183 +f 1777/1352/3184 3055/1353/3184 1780/1354/3184 +f 171/1355/3185 1780/1354/3185 2958/1356/3185 +f 1145/1357/3186 2497/1358/3186 1254/1359/3186 +f 171/1355/3187 1254/1359/3187 2655/1360/3187 +f 1773/1361/3188 3054/1362/3188 1776/1363/3188 +f 172/1364/3189 1776/1363/3189 2959/1365/3189 +f 1146/1366/3190 2588/1367/3190 1559/1368/3190 +f 172/1364/3191 1559/1368/3191 2960/1369/3191 +f 1769/1370/3192 3053/1371/3192 1772/1372/3192 +f 173/1373/3193 1772/1372/3193 2749/1374/3193 +f 936/1375/3194 2481/1376/3194 1560/1377/3194 +f 173/1373/3195 1560/1377/3195 2961/1378/3195 +f 1765/1379/3196 3052/1380/3196 1768/1381/3196 +f 174/1382/3197 1768/1381/3197 2962/1383/3197 +f 174/1382/3198 1149/1384/3198 2452/1385/3198 +f 1209/1386/3199 2610/1387/3199 1765/1379/3199 +f 1761/1388/3200 3051/1389/3200 1764/1390/3200 +f 175/1391/3201 1764/1390/3201 2963/1392/3201 +f 1150/1393/3202 2589/1394/3202 1563/1395/3202 +f 175/1391/3203 1563/1395/3203 2964/1396/3203 +f 1757/1397/3204 3050/1398/3204 1760/1399/3204 +f 176/1400/3205 1760/1399/3205 2748/1401/3205 +f 935/1402/3206 2480/1403/3206 1564/1404/3206 +f 176/1400/3207 1564/1404/3207 2965/1405/3207 +f 177/1406/3208 1753/1407/3208 3049/1408/3208 +f 1756/1409/3209 2966/1410/3209 1153/1411/3209 +f 177/1406/3210 1153/1411/3210 2487/1412/3210 +f 1244/1413/3211 2645/1414/3211 1753/1407/3211 +f 178/1415/3212 1749/1416/3212 3048/1417/3212 +f 1752/1418/3213 2967/1419/3213 1154/1420/3213 +f 178/1415/3214 1154/1420/3214 2590/1421/3214 +f 1567/1422/3215 2968/1423/3215 1749/1416/3215 +f 1745/1424/3216 3047/1425/3216 1748/1426/3216 +f 179/1427/3217 1748/1426/3217 2782/1428/3217 +f 969/1429/3218 2514/1430/3218 1568/1431/3218 +f 179/1427/3219 1568/1431/3219 2969/1432/3219 +f 180/1433/3220 1741/1434/3220 3046/1435/3220 +f 1744/1436/3221 2970/1437/3221 1157/1438/3221 +f 180/1433/3222 1157/1438/3222 2494/1439/3222 +f 1251/1440/3223 2652/1441/3223 1741/1434/3223 +f 181/1442/3224 1737/1443/3224 3045/1444/3224 +f 1740/1445/3225 2971/1446/3225 1158/1447/3225 +f 181/1442/3226 1158/1447/3226 2591/1448/3226 +f 1571/1449/3227 2972/1450/3227 1737/1443/3227 +f 182/1451/3228 1733/1452/3228 3044/1453/3228 +f 1736/1454/3229 2745/1455/3229 932/1456/3229 +f 182/1451/3230 932/1456/3230 2477/1457/3230 +f 1572/1458/3231 2973/1459/3231 1733/1452/3231 +f 1729/1460/3232 3043/1461/3232 1732/1462/3232 +f 183/1463/3233 1732/1462/3233 2974/1464/3233 +f 1161/1465/3234 2451/1466/3234 1208/1467/3234 +f 183/1463/3235 1208/1467/3235 2609/1468/3235 +f 184/1469/3236 1725/1470/3236 3042/1471/3236 +f 1728/1472/3237 2975/1473/3237 1162/1474/3237 +f 184/1469/3238 1162/1474/3238 2592/1475/3238 +f 1575/1476/3239 2976/1477/3239 1725/1470/3239 +f 185/1478/3240 1721/1479/3240 3041/1480/3240 +f 1724/1481/3241 2744/1482/3241 931/1483/3241 +f 185/1478/3242 931/1483/3242 2476/1484/3242 +f 1576/1485/3243 2977/1486/3243 1721/1479/3243 +f 186/1487/3244 1717/1488/3244 3040/1489/3244 +f 1720/1490/3245 2978/1491/3245 1165/1492/3245 +f 186/1487/3246 1165/1492/3246 2516/1493/3246 +f 1273/1494/3247 2674/1495/3247 1717/1488/3247 +f 187/1496/3248 1713/1497/3248 3039/1498/3248 +f 1716/1499/3249 2979/1500/3249 1166/1501/3249 +f 187/1496/3250 1166/1501/3250 2593/1502/3250 +f 1579/1503/3251 2980/1504/3251 1713/1497/3251 +f 1709/1505/3252 3038/1506/3252 1712/1507/3252 +f 188/1508/3253 1712/1507/3253 2783/1509/3253 +f 970/1510/3254 2515/1511/3254 1580/1512/3254 +f 188/1508/3255 1580/1512/3255 2981/1513/3255 +f 1705/1514/3256 3037/1515/3256 1708/1516/3256 +f 189/1517/3257 1708/1516/3257 2982/1518/3257 +f 1169/1519/3258 2475/1520/3258 1232/1521/3258 +f 189/1517/3259 1232/1521/3259 2633/1522/3259 +f 190/1523/3260 1701/1524/3260 3036/1525/3260 +f 1704/1526/3261 2983/1527/3261 1170/1528/3261 +f 190/1523/3262 1170/1528/3262 2594/1529/3262 +f 1583/1530/3263 2984/1531/3263 1701/1524/3263 +f 191/1532/3264 1697/1533/3264 3035/1534/3264 +f 1700/1535/3265 2729/1536/3265 916/1537/3265 +f 191/1532/3266 916/1537/3266 2461/1538/3266 +f 1584/1539/3267 2985/1540/3267 1697/1533/3267 +f 1693/1541/3268 3034/1542/3268 1696/1543/3268 +f 192/1544/3269 1696/1543/3269 2986/1545/3269 +f 1173/1546/3270 2458/1547/3270 913/1548/3270 +f 192/1544/3271 913/1548/3271 2726/1549/3271 +f 1689/1550/3272 3033/1551/3272 1692/1552/3272 +f 193/1553/3273 1692/1552/3273 2987/1554/3273 +f 1174/1555/3274 2595/1556/3274 1587/1557/3274 +f 193/1553/3275 1587/1557/3275 2988/1558/3275 +f 1685/1559/3276 3032/1560/3276 1688/1561/3276 +f 194/1562/3277 1688/1561/3277 2728/1563/3277 +f 915/1564/3278 2460/1565/3278 1588/1566/3278 +f 194/1562/3279 1588/1566/3279 2989/1567/3279 +f 1681/1568/3280 3031/1569/3280 1684/1570/3280 +f 195/1571/3281 1684/1570/3281 2990/1572/3281 +f 1177/1573/3282 2490/1574/3282 1247/1575/3282 +f 195/1571/3283 1247/1575/3283 2648/1576/3283 +f 1677/1577/3284 3030/1578/3284 1680/1579/3284 +f 196/1580/3285 1680/1579/3285 2991/1581/3285 +f 1178/1582/3286 2596/1583/3286 1591/1584/3286 +f 196/1580/3287 1591/1584/3287 2992/1585/3287 +f 1673/1586/3288 3029/1587/3288 1676/1588/3288 +f 197/1589/3289 1676/1588/3289 2774/1590/3289 +f 961/1591/3290 2506/1592/3290 1592/1593/3290 +f 197/1589/3291 1592/1593/3291 2993/1594/3291 +f 1669/1595/3292 3028/1596/3292 1672/1597/3292 +f 198/1598/3293 1672/1597/3293 2994/1599/3293 +f 1181/1600/3294 2508/1601/3294 1265/1602/3294 +f 198/1598/3295 1265/1602/3295 2666/1603/3295 +f 1665/1604/3296 3027/1605/3296 1668/1606/3296 +f 199/1607/3297 1668/1606/3297 2995/1608/3297 +f 1182/1609/3298 2597/1610/3298 1595/1611/3298 +f 199/1607/3299 1595/1611/3299 2996/1612/3299 +f 1661/1613/3300 3026/1614/3300 1664/1615/3300 +f 200/1616/3301 1664/1615/3301 2775/1617/3301 +f 962/1618/3302 2507/1619/3302 1596/1620/3302 +f 200/1616/3303 1596/1620/3303 2997/1621/3303 +f 1657/1622/3304 3025/1623/3304 1660/1624/3304 +f 201/1625/3305 1660/1624/3305 2998/1626/3305 +f 1185/1627/3306 2509/1628/3306 1266/1629/3306 +f 201/1625/3307 1266/1629/3307 2667/1630/3307 +f 1653/1631/3308 3024/1632/3308 1656/1633/3308 +f 202/1634/3309 1656/1633/3309 2999/1635/3309 +f 1186/1636/3310 2598/1637/3310 1599/1638/3310 +f 202/1634/3311 1599/1638/3311 3000/1639/3311 +f 1649/1640/3312 3023/1641/3312 1652/1642/3312 +f 203/1643/3313 1652/1642/3313 2772/1644/3313 +f 959/1645/3314 2504/1646/3314 1600/1647/3314 +f 203/1643/3315 1600/1647/3315 3001/1648/3315 +f 1645/1649/3316 3022/1650/3316 1648/1651/3316 +f 204/1652/3317 1648/1651/3317 3002/1653/3317 +f 1189/1654/3318 2517/1655/3318 1274/1656/3318 +f 204/1652/3319 1274/1656/3319 2675/1657/3319 +f 1641/1658/3320 3021/1659/3320 1644/1660/3320 +f 205/1661/3321 1644/1660/3321 3003/1662/3321 +f 1190/1663/3322 2599/1664/3322 1603/1665/3322 +f 205/1661/3323 1603/1665/3323 3004/1666/3323 +f 1637/1667/3324 3020/1668/3324 1640/1669/3324 +f 206/1670/3325 1640/1669/3325 2759/1671/3325 +f 946/1672/3326 2491/1673/3326 1604/1674/3326 +f 206/1670/3327 1604/1674/3327 3005/1675/3327 +f 1633/1676/3328 3019/1677/3328 1636/1678/3328 +f 207/1679/3329 1636/1678/3329 3006/1680/3329 +f 1193/1681/3330 2448/1682/3330 903/1683/3330 +f 207/1679/3331 903/1683/3331 2716/1684/3331 +f 1629/1685/3332 3018/1686/3332 1632/1687/3332 +f 208/1688/3333 1632/1687/3333 3007/1689/3333 +f 1194/1690/3334 2600/1691/3334 1607/1692/3334 +f 208/1688/3335 1607/1692/3335 3008/1693/3335 +f 1625/1694/3336 3017/1695/3336 1628/1696/3336 +f 209/1697/3337 1628/1696/3337 2778/1698/3337 +f 965/1699/3338 2510/1700/3338 1608/1701/3338 +f 209/1697/3339 1608/1701/3339 3009/1702/3339 +f 1621/1703/3340 3016/1704/3340 1624/1705/3340 +f 210/1706/3341 1624/1705/3341 3010/1707/3341 +f 1197/1708/3342 2512/1709/3342 1269/1710/3342 +f 210/1706/3343 1269/1710/3343 2670/1711/3343 +f 1617/1712/3344 3015/1713/3344 1620/1714/3344 +f 211/1715/3345 1620/1714/3345 3011/1716/3345 +f 1198/1717/3346 2601/1718/3346 1611/1719/3346 +f 211/1715/3347 1611/1719/3347 3012/1720/3347 +f 1613/1721/3348 3014/1722/3348 1616/1723/3348 +f 212/1724/3349 1616/1723/3349 2779/1725/3349 +f 966/1726/3350 2511/1727/3350 1612/1728/3350 +f 212/1724/3351 1612/1728/3351 3013/1729/3351 +f 1198/1717/3352 3011/1716/3352 1615/1730/3352 +f 213/1731/3353 1615/1730/3353 3014/1722/3353 +f 1613/1721/3354 3013/1729/3354 1200/1732/3354 +f 213/1731/3355 1200/1732/3355 2601/1718/3355 +f 1610/1733/3356 2490/1574/3356 945/1734/3356 +f 214/1735/3357 945/1734/3357 2758/55/3357 +f 1614/1736/3358 3014/1722/3358 1615/1730/3358 +f 214/1735/3359 1615/1730/3359 3011/1716/3359 +f 1614/1736/3360 2758/55/3360 1357/54/3360 +f 215/1737/3361 1357/54/3361 2431/53/3361 +f 1378/1738/3362 2779/1725/3362 1616/1723/3362 +f 215/1737/3363 1616/1723/3363 3014/1722/3363 +f 909/457/3364 2722/456/3364 1619/1739/3364 +f 216/1740/3365 1619/1739/3365 3015/1713/3365 +f 1617/1712/3366 3012/1720/3366 1199/1741/3366 +f 216/1740/3367 1199/1741/3367 2454/458/3367 +f 1321/1742/3368 2402/161/3368 835/1743/3368 +f 217/1744/3369 835/1743/3369 2648/1576/3369 +f 1618/1745/3370 3015/1713/3370 1619/1739/3370 +f 217/1744/3371 1619/1739/3371 2722/456/3371 +f 1618/1745/3372 2648/1576/3372 1247/1575/3372 +f 218/1746/3373 1247/1575/3373 2490/1574/3373 +f 1610/1733/3374 3011/1716/3374 1620/1714/3374 +f 218/1746/3375 1620/1714/3375 3015/1713/3375 +f 799/430/3376 2612/429/3376 1623/1747/3376 +f 219/1748/3377 1623/1747/3377 3016/1704/3377 +f 1621/1703/3378 2670/1711/3378 857/1749/3378 +f 219/1748/3379 857/1749/3379 2387/431/3379 +f 1211/1750/3380 2454/458/3380 1199/1741/3380 +f 220/1751/3381 1199/1741/3381 3012/1720/3381 +f 1622/1752/3382 3016/1704/3382 1623/1747/3382 +f 220/1751/3383 1623/1747/3383 2612/429/3383 +f 1622/1752/3384 3012/1720/3384 1611/1719/3384 +f 221/1753/3385 1611/1719/3385 2601/1718/3385 +f 1609/1754/3386 3010/1707/3386 1624/1705/3386 +f 221/1753/3387 1624/1705/3387 3016/1704/3387 +f 1194/1690/3388 3007/1689/3388 1627/1755/3388 +f 222/1756/3389 1627/1755/3389 3017/1695/3389 +f 1625/1694/3390 3009/1702/3390 1196/1757/3390 +f 222/1756/3391 1196/1757/3391 2600/1691/3391 +f 1606/1758/3392 2512/1709/3392 967/1759/3392 +f 223/1760/3393 967/1759/3393 2780/10/3393 +f 1626/1761/3394 3017/1695/3394 1627/1755/3394 +f 223/1760/3395 1627/1755/3395 3007/1689/3395 +f 1626/1761/3396 2780/10/3396 1379/9/3396 +f 224/1762/3397 1379/9/3397 2433/8/3397 +f 1377/1763/3398 2778/1698/3398 1628/1696/3398 +f 224/1762/3399 1628/1696/3399 3017/1695/3399 +f 915/1564/3400 2728/1563/3400 1631/1764/3400 +f 225/1765/3401 1631/1764/3401 3018/1686/3401 +f 1629/1685/3402 3008/1693/3402 1195/1766/3402 +f 225/1765/3403 1195/1766/3403 2460/1565/3403 +f 1327/1767/3404 2387/431/3404 857/1749/3404 +f 226/1768/3405 857/1749/3405 2670/1711/3405 +f 1630/1769/3406 3018/1686/3406 1631/1764/3406 +f 226/1768/3407 1631/1764/3407 2728/1563/3407 +f 1630/1769/3408 2670/1711/3408 1269/1710/3408 +f 227/1770/3409 1269/1710/3409 2512/1709/3409 +f 1606/1758/3410 3007/1689/3410 1632/1687/3410 +f 227/1770/3411 1632/1687/3411 3018/1686/3411 +f 805/61/3412 2618/60/3412 1635/1771/3412 +f 228/1772/3413 1635/1771/3413 3019/1677/3413 +f 1633/1676/3414 2716/1684/3414 1315/1773/3414 +f 228/1772/3415 1315/1773/3415 2391/62/3415 +f 1217/1774/3416 2460/1565/3416 1195/1766/3416 +f 229/1775/3417 1195/1766/3417 3008/1693/3417 +f 1634/1776/3418 3019/1677/3418 1635/1771/3418 +f 229/1775/3419 1635/1771/3419 2618/60/3419 +f 1634/1776/3420 3008/1693/3420 1607/1692/3420 +f 230/1777/3421 1607/1692/3421 2600/1691/3421 +f 1605/1778/3422 3006/1680/3422 1636/1678/3422 +f 230/1777/3423 1636/1678/3423 3019/1677/3423 +f 1190/1663/3424 3003/1662/3424 1639/1779/3424 +f 231/1780/3425 1639/1779/3425 3020/1668/3425 +f 1637/1667/3426 3005/1675/3426 1192/1781/3426 +f 231/1780/3427 1192/1781/3427 2599/1664/3427 +f 1602/1782/3428 2475/1520/3428 930/1783/3428 +f 232/1784/3429 930/1783/3429 2743/73/3429 +f 1638/1785/3430 3020/1668/3430 1639/1779/3430 +f 232/1784/3431 1639/1779/3431 3003/1662/3431 +f 1638/1785/3432 2743/73/3432 1342/72/3432 +f 233/1786/3433 1342/72/3433 2393/71/3433 +f 1358/1787/3434 2759/1671/3434 1640/1669/3434 +f 233/1786/3435 1640/1669/3435 3020/1668/3435 +f 970/1510/3436 2783/1509/3436 1643/1788/3436 +f 234/1789/3437 1643/1788/3437 3021/1659/3437 +f 1641/1658/3438 3004/1666/3438 1191/1790/3438 +f 234/1789/3439 1191/1790/3439 2515/1511/3439 +f 1382/1791/3440 2417/386/3440 820/1792/3440 +f 235/1793/3441 820/1792/3441 2633/1522/3441 +f 1642/1794/3442 3021/1659/3442 1643/1788/3442 +f 235/1793/3443 1643/1788/3443 2783/1509/3443 +f 1642/1794/3444 2633/1522/3444 1232/1521/3444 +f 236/1795/3445 1232/1521/3445 2475/1520/3445 +f 1602/1782/3446 3003/1662/3446 1644/1660/3446 +f 236/1795/3447 1644/1660/3447 3021/1659/3447 +f 860/79/3448 2673/78/3448 1647/1796/3448 +f 237/1797/3449 1647/1796/3449 3022/1650/3449 +f 1645/1649/3450 2675/1657/3450 862/1798/3450 +f 237/1797/3451 862/1798/3451 2434/80/3451 +f 1272/1799/3452 2515/1511/3452 1191/1790/3452 +f 238/1800/3453 1191/1790/3453 3004/1666/3453 +f 1646/1801/3454 3022/1650/3454 1647/1796/3454 +f 238/1800/3455 1647/1796/3455 2673/78/3455 +f 1646/1801/3456 3004/1666/3456 1603/1665/3456 +f 239/1802/3457 1603/1665/3457 2599/1664/3457 +f 1601/1803/3458 3002/1653/3458 1648/1651/3458 +f 239/1802/3459 1648/1651/3459 3022/1650/3459 +f 1186/1636/3460 2999/1635/3460 1651/1804/3460 +f 240/1805/3461 1651/1804/3461 3023/1641/3461 +f 1649/1640/3462 3001/1648/3462 1188/1806/3462 +f 240/1805/3463 1188/1806/3463 2598/1637/3463 +f 1598/1807/3464 2451/1466/3464 906/1808/3464 +f 241/1809/3465 906/1808/3465 2719/91/3465 +f 1650/1810/3466 3023/1641/3466 1651/1804/3466 +f 241/1809/3467 1651/1804/3467 2999/1635/3467 +f 1650/1810/3468 2719/91/3468 1318/90/3468 +f 242/1811/3469 1318/90/3469 2405/89/3469 +f 1371/1812/3470 2772/1644/3470 1652/1642/3470 +f 242/1811/3471 1652/1642/3471 3023/1641/3471 +f 962/1618/3472 2775/1617/3472 1655/1813/3472 +f 243/1814/3473 1655/1813/3473 3024/1632/3473 +f 1653/1631/3474 3000/1639/3474 1187/1815/3474 +f 243/1814/3475 1187/1815/3475 2507/1619/3475 +f 1374/1816/3476 2384/359/3476 796/1817/3476 +f 244/1818/3477 796/1817/3477 2609/1468/3477 +f 1654/1819/3478 3024/1632/3478 1655/1813/3478 +f 244/1818/3479 1655/1813/3479 2775/1617/3479 +f 1654/1819/3480 2609/1468/3480 1208/1467/3480 +f 245/1820/3481 1208/1467/3481 2451/1466/3481 +f 1598/1807/3482 2999/1635/3482 1656/1633/3482 +f 245/1820/3483 1656/1633/3483 3024/1632/3483 +f 852/43/3484 2665/42/3484 1659/1821/3484 +f 246/1822/3485 1659/1821/3485 3025/1623/3485 +f 1657/1622/3486 2667/1630/3486 854/1823/3486 +f 246/1822/3487 854/1823/3487 2432/44/3487 +f 1264/1824/3488 2507/1619/3488 1187/1815/3488 +f 247/1825/3489 1187/1815/3489 3000/1639/3489 +f 1658/1826/3490 3025/1623/3490 1659/1821/3490 +f 247/1825/3491 1659/1821/3491 2665/42/3491 +f 1658/1826/3492 3000/1639/3492 1599/1638/3492 +f 248/1827/3493 1599/1638/3493 2598/1637/3493 +f 1597/1828/3494 2998/1626/3494 1660/1624/3494 +f 248/1827/3495 1660/1624/3495 3025/1623/3495 +f 1182/1609/3496 2995/1608/3496 1663/1829/3496 +f 249/1830/3497 1663/1829/3497 3026/1614/3497 +f 1661/1613/3498 2997/1621/3498 1184/1831/3498 +f 249/1830/3499 1184/1831/3499 2597/1610/3499 +f 1594/1832/3500 2463/656/3500 918/1833/3500 +f 250/1834/3501 918/1833/3501 2731/361/3501 +f 1662/1835/3502 3026/1614/3502 1663/1829/3502 +f 250/1834/3503 1663/1829/3503 2995/1608/3503 +f 1662/1835/3504 2731/361/3504 1330/360/3504 +f 251/1836/3505 1330/360/3505 2384/359/3505 +f 1374/1816/3506 2775/1617/3506 1664/1615/3506 +f 251/1836/3507 1664/1615/3507 3026/1614/3507 +f 946/1672/3508 2759/1671/3508 1667/1837/3508 +f 252/1838/3509 1667/1837/3509 3027/1605/3509 +f 1665/1604/3510 2996/1612/3510 1183/1839/3510 +f 252/1838/3511 1183/1839/3511 2491/1673/3511 +f 1358/1787/3512 2393/71/3512 808/1840/3512 +f 253/1841/3513 808/1840/3513 2621/658/3513 +f 1666/1842/3514 3027/1605/3514 1667/1837/3514 +f 253/1841/3515 1667/1837/3515 2759/1671/3515 +f 1666/1842/3516 2621/658/3516 1220/657/3516 +f 254/1843/3517 1220/657/3517 2463/656/3517 +f 1594/1832/3518 2995/1608/3518 1668/1606/3518 +f 254/1843/3519 1668/1606/3519 3027/1605/3519 +f 836/25/3520 2649/24/3520 1671/1844/3520 +f 255/1845/3521 1671/1844/3521 3028/1596/3521 +f 1669/1595/3522 2666/1603/3522 853/1846/3522 +f 255/1845/3523 853/1846/3523 2415/26/3523 +f 1248/1847/3524 2491/1673/3524 1183/1839/3524 +f 256/1848/3525 1183/1839/3525 2996/1612/3525 +f 1670/1849/3526 3028/1596/3526 1671/1844/3526 +f 256/1848/3527 1671/1844/3527 2649/24/3527 +f 1670/1849/3528 2996/1612/3528 1595/1611/3528 +f 257/1850/3529 1595/1611/3529 2597/1610/3529 +f 1593/1851/3530 2994/1599/3530 1672/1597/3530 +f 257/1850/3531 1672/1597/3531 3028/1596/3531 +f 1178/1582/3532 2991/1581/3532 1675/1852/3532 +f 258/1853/3533 1675/1852/3533 3029/1587/3533 +f 1673/1586/3534 2993/1594/3534 1180/1854/3534 +f 258/1853/3535 1180/1854/3535 2596/1583/3535 +f 1590/1855/3536 2508/1601/3536 963/1856/3536 +f 259/1857/3537 963/1856/3537 2776/46/3537 +f 1674/1858/3538 3029/1587/3538 1675/1852/3538 +f 259/1857/3539 1675/1852/3539 2991/1581/3539 +f 1674/1858/3540 2776/46/3540 1375/45/3540 +f 260/1859/3541 1375/45/3541 2432/44/3541 +f 1373/1860/3542 2774/1590/3542 1676/1588/3542 +f 260/1859/3543 1676/1588/3543 3029/1587/3543 +f 927/1267/3544 2740/1266/3544 1679/1861/3544 +f 261/1862/3545 1679/1861/3545 3030/1578/3545 +f 1677/1577/3546 2992/1585/3546 1179/1863/3546 +f 261/1862/3547 1179/1863/3547 2472/1268/3547 +f 1339/1864/3548 2415/26/3548 853/1846/3548 +f 262/1865/3549 853/1846/3549 2666/1603/3549 +f 1678/1866/3550 3030/1578/3550 1679/1861/3550 +f 262/1865/3551 1679/1861/3551 2740/1266/3551 +f 1678/1866/3552 2666/1603/3552 1265/1602/3552 +f 263/1867/3553 1265/1602/3553 2508/1601/3553 +f 1590/1855/3554 2991/1581/3554 1680/1579/3554 +f 263/1867/3555 1680/1579/3555 3030/1578/3555 +f 817/160/3556 2630/159/3556 1683/1868/3556 +f 264/1869/3557 1683/1868/3557 3031/1569/3557 +f 1681/1568/3558 2648/1576/3558 835/1743/3558 +f 264/1869/3559 835/1743/3559 2402/161/3559 +f 1229/1870/3560 2472/1268/3560 1179/1863/3560 +f 265/1871/3561 1179/1863/3561 2992/1585/3561 +f 1682/1872/3562 3031/1569/3562 1683/1868/3562 +f 265/1871/3563 1683/1868/3563 2630/159/3563 +f 1682/1872/3564 2992/1585/3564 1591/1584/3564 +f 266/1873/3565 1591/1584/3565 2596/1583/3565 +f 1589/1874/3566 2990/1572/3566 1684/1570/3566 +f 266/1873/3567 1684/1570/3567 3031/1569/3567 +f 1174/1555/3568 2987/1554/3568 1687/1875/3568 +f 267/1876/3569 1687/1875/3569 3032/1560/3569 +f 1685/1559/3570 2989/1567/3570 1176/1877/3570 +f 267/1876/3571 1176/1877/3571 2595/1556/3571 +f 1586/1878/3572 2553/440/3572 1008/1879/3572 +f 268/1880/3573 1008/1879/3573 2821/433/3573 +f 1686/1881/3574 3032/1560/3574 1687/1875/3574 +f 268/1880/3575 1687/1875/3575 2987/1554/3575 +f 1686/1881/3576 2821/433/3576 1420/432/3576 +f 269/1882/3577 1420/432/3577 2387/431/3577 +f 1327/1767/3578 2728/1563/3578 1688/1561/3578 +f 269/1882/3579 1688/1561/3579 3032/1560/3579 +f 1005/511/3580 2818/510/3580 1691/1883/3580 +f 270/1884/3581 1691/1883/3581 3033/1551/3581 +f 1689/1550/3582 2988/1558/3582 1175/1885/3582 +f 270/1884/3583 1175/1885/3583 2550/512/3583 +f 1417/1886/3584 2443/422/3584 898/1887/3584 +f 271/1888/3585 898/1887/3585 2711/442/3585 +f 1690/1889/3586 3033/1551/3586 1691/1883/3586 +f 271/1888/3587 1691/1883/3587 2818/510/3587 +f 1690/1889/3588 2711/442/3588 1310/441/3588 +f 272/1890/3589 1310/441/3589 2553/440/3589 +f 1586/1878/3590 2987/1554/3590 1692/1552/3590 +f 272/1890/3591 1692/1552/3591 3033/1551/3591 +f 895/412/3592 2708/411/3592 1695/1891/3592 +f 273/1892/3593 1695/1891/3593 3034/1542/3593 +f 1693/1541/3594 2726/1549/3594 1325/1893/3594 +f 273/1892/3595 1325/1893/3595 2388/413/3595 +f 1307/1894/3596 2550/512/3596 1175/1885/3596 +f 274/1895/3597 1175/1885/3597 2988/1558/3597 +f 1694/1896/3598 3034/1542/3598 1695/1891/3598 +f 274/1895/3599 1695/1891/3599 2708/411/3599 +f 1694/1896/3600 2988/1558/3600 1587/1557/3600 +f 275/1897/3601 1587/1557/3601 2595/1556/3601 +f 1585/1898/3602 2986/1545/3602 1696/1543/3602 +f 275/1897/3603 1696/1543/3603 3034/1542/3603 +f 276/1899/3604 1170/1528/3604 2983/1527/3604 +f 1699/1900/3605 3035/1534/3605 1697/1533/3605 +f 276/1899/3606 1697/1533/3606 2985/1540/3606 +f 1172/1901/3607 2594/1529/3607 1170/1528/3607 +f 277/1902/3608 1582/1903/3608 2549/521/3608 +f 1004/1904/3609 2817/406/3609 1698/1905/3609 +f 277/1902/3610 1698/1905/3610 3035/1534/3610 +f 1699/1900/3611 2983/1527/3611 1582/1903/3611 +f 278/1906/3612 1698/1905/3612 2817/406/3612 +f 1416/405/3613 2386/404/3613 1328/1907/3613 +f 278/1906/3614 1328/1907/3614 2729/1536/3614 +f 1700/1535/3615 3035/1534/3615 1698/1905/3615 +f 279/1908/3616 1001/592/3616 2814/591/3616 +f 1703/1909/3617 3036/1525/3617 1701/1524/3617 +f 279/1908/3618 1701/1524/3618 2984/1531/3618 +f 1171/1910/3619 2546/593/3619 1001/592/3619 +f 280/1911/3620 1413/1912/3620 2442/395/3620 +f 894/1913/3621 2707/523/3621 1702/1914/3621 +f 280/1911/3622 1702/1914/3622 3036/1525/3622 +f 1703/1909/3623 2814/591/3623 1413/1912/3623 +f 281/1915/3624 1702/1914/3624 2707/523/3624 +f 1306/522/3625 2549/521/3625 1582/1903/3625 +f 281/1915/3626 1582/1903/3626 2983/1527/3626 +f 1704/1526/3627 3036/1525/3627 1702/1914/3627 +f 891/385/3628 2704/384/3628 1707/1916/3628 +f 1707/1916/3629 3037/1515/3629 1705/1514/3629 +f 1705/1514/3630 2633/1522/3630 820/1792/3630 +f 282/1917/3631 820/1792/3631 2417/386/3631 +f 283/1918/3632 1303/1919/3632 2546/593/3632 +f 1171/1910/3633 2984/1531/3633 1706/1920/3633 +f 283/1918/3634 1706/1920/3634 3037/1515/3634 +f 1707/1916/3635 2704/384/3635 1303/1919/3635 +f 284/1921/3636 1706/1920/3636 2984/1531/3636 +f 1583/1530/3637 2594/1529/3637 1581/1922/3637 +f 284/1921/3638 1581/1922/3638 2982/1518/3638 +f 1708/1516/3639 3037/1515/3639 1706/1920/3639 +f 285/1923/3640 1166/1501/3640 2979/1500/3640 +f 285/1923/3641 1711/1924/3641 3038/1506/3641 +f 1709/1505/3642 2981/1513/3642 1168/1925/3642 +f 1168/1925/3643 2593/1502/3643 1166/1501/3643 +f 286/1926/3644 1578/1927/3644 2474/575/3644 +f 929/1928/3645 2742/388/3645 1710/1929/3645 +f 1710/1929/3646 3038/1506/3646 1711/1924/3646 +f 1711/1924/3647 2979/1500/3647 1578/1927/3647 +f 1710/1929/3648 2742/388/3648 1341/387/3648 +f 287/1930/3649 1341/387/3649 2417/386/3649 +f 1382/1791/3650 2783/1509/3650 1712/1507/3650 +f 287/1930/3651 1712/1507/3651 3038/1506/3651 +f 288/1931/3652 955/1105/3652 2768/1104/3652 +f 1715/1932/3653 3039/1498/3653 1713/1497/3653 +f 288/1931/3654 1713/1497/3654 2980/1504/3654 +f 1167/1933/3655 2500/1106/3655 955/1105/3655 +f 289/1934/3656 1367/1935/3656 2404/116/3656 +f 819/1936/3657 2632/577/3657 1714/1937/3657 +f 289/1934/3658 1714/1937/3658 3039/1498/3658 +f 1715/1932/3659 2768/1104/3659 1367/1935/3659 +f 290/1938/3660 1714/1937/3660 2632/577/3660 +f 1231/576/3661 2474/575/3661 1578/1927/3661 +f 290/1938/3662 1578/1927/3662 2979/1500/3662 +f 1716/1499/3663 3039/1498/3663 1714/1937/3663 +f 291/1939/3664 845/214/3664 2658/213/3664 +f 1719/1940/3665 3040/1489/3665 1717/1488/3665 +f 291/1939/3666 1717/1488/3666 2674/1495/3666 +f 861/1941/3667 2426/215/3667 845/214/3667 +f 292/1942/3668 1257/1943/3668 2500/1106/3668 +f 1167/1933/3669 2980/1504/3669 1718/1944/3669 +f 292/1942/3670 1718/1944/3670 3040/1489/3670 +f 1719/1940/3671 2658/213/3671 1257/1943/3671 +f 293/1945/3672 1718/1944/3672 2980/1504/3672 +f 1579/1503/3673 2593/1502/3673 1577/1946/3673 +f 293/1945/3674 1577/1946/3674 2978/1491/3674 +f 1720/1490/3675 3040/1489/3675 1718/1944/3675 +f 294/1947/3676 1162/1474/3676 2975/1473/3676 +f 1723/1948/3677 3041/1480/3677 1721/1479/3677 +f 294/1947/3678 1721/1479/3678 2977/1486/3678 +f 1164/1949/3679 2592/1475/3679 1162/1474/3679 +f 295/1950/3680 1574/1951/3680 2545/602/3680 +f 1000/1952/3681 2813/379/3681 1722/1953/3681 +f 295/1950/3682 1722/1953/3682 3041/1480/3682 +f 1723/1948/3683 2975/1473/3683 1574/1951/3683 +f 296/1954/3684 1722/1953/3684 2813/379/3684 +f 1412/378/3685 2418/377/3685 1343/1955/3685 +f 296/1954/3686 1343/1955/3686 2744/1482/3686 +f 1724/1481/3687 3041/1480/3687 1722/1953/3687 +f 297/1956/3688 997/673/3688 2810/672/3688 +f 1727/1957/3689 3042/1471/3689 1725/1470/3689 +f 297/1956/3690 1725/1470/3690 2976/1477/3690 +f 1163/1958/3691 2542/674/3691 997/673/3691 +f 298/1959/3692 1409/1960/3692 2441/368/3692 +f 890/1961/3693 2703/604/3693 1726/1962/3693 +f 298/1959/3694 1726/1962/3694 3042/1471/3694 +f 1727/1957/3695 2810/672/3695 1409/1960/3695 +f 299/1963/3696 1726/1962/3696 2703/604/3696 +f 1302/603/3697 2545/602/3697 1574/1951/3697 +f 299/1963/3698 1574/1951/3698 2975/1473/3698 +f 1728/1472/3699 3042/1471/3699 1726/1962/3699 +f 887/358/3700 2700/357/3700 1731/1964/3700 +f 1731/1964/3701 3043/1461/3701 1729/1460/3701 +f 1729/1460/3702 2609/1468/3702 796/1817/3702 +f 300/1965/3703 796/1817/3703 2384/359/3703 +f 301/1966/3704 1299/1967/3704 2542/674/3704 +f 1163/1958/3705 2976/1477/3705 1730/1968/3705 +f 301/1966/3706 1730/1968/3706 3043/1461/3706 +f 1731/1964/3707 2700/357/3707 1299/1967/3707 +f 302/1969/3708 1730/1968/3708 2976/1477/3708 +f 1575/1476/3709 2592/1475/3709 1573/1970/3709 +f 302/1969/3710 1573/1970/3710 2974/1464/3710 +f 1732/1462/3711 3043/1461/3711 1730/1968/3711 +f 303/1971/3712 1158/1447/3712 2971/1446/3712 +f 1735/1972/3713 3044/1453/3713 1733/1452/3713 +f 303/1971/3714 1733/1452/3714 2973/1459/3714 +f 1160/1973/3715 2591/1448/3715 1158/1447/3715 +f 304/1974/3716 1570/1975/3716 2541/683/3716 +f 996/1976/3717 2809/352/3717 1734/1977/3717 +f 304/1974/3718 1734/1977/3718 3044/1453/3718 +f 1735/1972/3719 2971/1446/3719 1570/1975/3719 +f 305/1978/3720 1734/1977/3720 2809/352/3720 +f 1408/351/3721 2419/350/3721 1344/1979/3721 +f 305/1978/3722 1344/1979/3722 2745/1455/3722 +f 1736/1454/3723 3044/1453/3723 1734/1977/3723 +f 306/1980/3724 993/754/3724 2806/753/3724 +f 1739/1981/3725 3045/1444/3725 1737/1443/3725 +f 306/1980/3726 1737/1443/3726 2972/1450/3726 +f 1159/1982/3727 2538/755/3727 993/754/3727 +f 307/1983/3728 1405/1984/3728 2440/341/3728 +f 886/1985/3729 2699/685/3729 1738/1986/3729 +f 307/1983/3730 1738/1986/3730 3045/1444/3730 +f 1739/1981/3731 2806/753/3731 1405/1984/3731 +f 308/1987/3732 1738/1986/3732 2699/685/3732 +f 1298/684/3733 2541/683/3733 1570/1975/3733 +f 308/1987/3734 1570/1975/3734 2971/1446/3734 +f 1740/1445/3735 3045/1444/3735 1738/1986/3735 +f 309/1988/3736 883/331/3736 2696/330/3736 +f 1743/1989/3737 3046/1435/3737 1741/1434/3737 +f 309/1988/3738 1741/1434/3738 2652/1441/3738 +f 839/1990/3739 2420/332/3739 883/331/3739 +f 310/1991/3740 1295/1992/3740 2538/755/3740 +f 1159/1982/3741 2972/1450/3741 1742/1993/3741 +f 310/1991/3742 1742/1993/3742 3046/1435/3742 +f 1743/1989/3743 2696/330/3743 1295/1992/3743 +f 311/1994/3744 1742/1993/3744 2972/1450/3744 +f 1571/1449/3745 2591/1448/3745 1569/1995/3745 +f 311/1994/3746 1569/1995/3746 2970/1437/3746 +f 1744/1436/3747 3046/1435/3747 1742/1993/3747 +f 312/1996/3748 1154/1420/3748 2967/1419/3748 +f 1747/1997/3749 3047/1425/3749 1745/1424/3749 +f 1745/1424/3750 2969/1432/3750 1156/1998/3750 +f 1156/1998/3751 2590/1421/3751 1154/1420/3751 +f 313/1999/3752 1566/2000/3752 2516/1493/3752 +f 971/2001/3753 2784/82/3753 1746/2002/3753 +f 1746/2002/3754 3047/1425/3754 1747/1997/3754 +f 1747/1997/3755 2967/1419/3755 1566/2000/3755 +f 1746/2002/3756 2784/82/3756 1383/81/3756 +f 314/2003/3757 1383/81/3757 2434/80/3757 +f 1381/2004/3758 2782/1428/3758 1748/1426/3758 +f 314/2003/3759 1748/1426/3759 3047/1425/3759 +f 315/2005/3760 940/1294/3760 2753/1293/3760 +f 1751/2006/3761 3048/1417/3761 1749/1416/3761 +f 315/2005/3762 1749/1416/3762 2968/1423/3762 +f 1155/2007/3763 2485/1295/3763 940/1294/3763 +f 316/2008/3764 1352/2009/3764 2426/215/3764 +f 861/1941/3765 2674/1495/3765 1750/2010/3765 +f 316/2008/3766 1750/2010/3766 3048/1417/3766 +f 1751/2006/3767 2753/1293/3767 1352/2009/3767 +f 317/2011/3768 1750/2010/3768 2674/1495/3768 +f 1273/1494/3769 2516/1493/3769 1566/2000/3769 +f 317/2011/3770 1566/2000/3770 2967/1419/3770 +f 1752/1418/3771 3048/1417/3771 1750/2010/3771 +f 318/2012/3772 830/151/3772 2643/150/3772 +f 1755/2013/3773 3049/1408/3773 1753/1407/3773 +f 318/2012/3774 1753/1407/3774 2645/1414/3774 +f 832/2014/3775 2408/152/3775 830/151/3775 +f 319/2015/3776 1242/2016/3776 2485/1295/3776 +f 1155/2007/3777 2968/1423/3777 1754/2017/3777 +f 319/2015/3778 1754/2017/3778 3049/1408/3778 +f 1755/2013/3779 2643/150/3779 1242/2016/3779 +f 320/2018/3780 1754/2017/3780 2968/1423/3780 +f 1567/1422/3781 2590/1421/3781 1565/2019/3781 +f 320/2018/3782 1565/2019/3782 2966/1410/3782 +f 1756/1409/3783 3049/1408/3783 1754/2017/3783 +f 1150/1393/3784 2963/1392/3784 1759/2020/3784 +f 321/2021/3785 1759/2020/3785 3050/1398/3785 +f 1757/1397/3786 2965/1405/3786 1152/2022/3786 +f 321/2021/3787 1152/2022/3787 2589/1394/3787 +f 1562/2023/3788 2537/764/3788 992/2024/3788 +f 322/2025/3789 992/2024/3789 2805/325/3789 +f 1758/2026/3790 3050/1398/3790 1759/2020/3790 +f 322/2025/3791 1759/2020/3791 2963/1392/3791 +f 1758/2026/3792 2805/325/3792 1404/324/3792 +f 323/2027/3793 1404/324/3793 2421/323/3793 +f 1347/2028/3794 2748/1401/3794 1760/1399/3794 +f 323/2027/3795 1760/1399/3795 3050/1398/3795 +f 989/835/3796 2802/834/3796 1763/2029/3796 +f 324/2030/3797 1763/2029/3797 3051/1389/3797 +f 1761/1388/3798 2964/1396/3798 1151/2031/3798 +f 324/2030/3799 1151/2031/3799 2534/836/3799 +f 1401/2032/3800 2439/314/3800 882/2033/3800 +f 325/2034/3801 882/2033/3801 2695/766/3801 +f 1762/2035/3802 3051/1389/3802 1763/2029/3802 +f 325/2034/3803 1763/2029/3803 2802/834/3803 +f 1762/2035/3804 2695/766/3804 1294/765/3804 +f 326/2036/3805 1294/765/3805 2537/764/3805 +f 1562/2023/3806 2963/1392/3806 1764/1390/3806 +f 326/2036/3807 1764/1390/3807 3051/1389/3807 +f 879/304/3808 2692/303/3808 1767/2037/3808 +f 327/2038/3809 1767/2037/3809 3052/1380/3809 +f 327/2038/3810 1765/1379/3810 2610/1387/3810 +f 797/2039/3811 2385/305/3811 879/304/3811 +f 1291/2040/3812 2534/836/3812 1151/2031/3812 +f 328/2041/3813 1151/2031/3813 2964/1396/3813 +f 1766/2042/3814 3052/1380/3814 1767/2037/3814 +f 328/2041/3815 1767/2037/3815 2692/303/3815 +f 1766/2042/3816 2964/1396/3816 1563/1395/3816 +f 329/2043/3817 1563/1395/3817 2589/1394/3817 +f 1561/2044/3818 2962/1383/3818 1768/1381/3818 +f 329/2043/3819 1768/1381/3819 3052/1380/3819 +f 1146/1366/3820 2959/1365/3820 1771/2045/3820 +f 330/2046/3821 1771/2045/3821 3053/1371/3821 +f 1769/1370/3822 2961/1378/3822 1148/2047/3822 +f 330/2046/3823 1148/2047/3823 2588/1367/3823 +f 1558/2048/3824 2533/845/3824 988/2049/3824 +f 331/2050/3825 988/2049/3825 2801/298/3825 +f 1770/2051/3826 3053/1371/3826 1771/2045/3826 +f 331/2050/3827 1771/2045/3827 2959/1365/3827 +f 1770/2051/3828 2801/298/3828 1400/297/3828 +f 332/2052/3829 1400/297/3829 2422/296/3829 +f 1348/2053/3830 2749/1374/3830 1772/1372/3830 +f 332/2052/3831 1772/1372/3831 3053/1371/3831 +f 985/916/3832 2798/915/3832 1775/2054/3832 +f 333/2055/3833 1775/2054/3833 3054/1362/3833 +f 1773/1361/3834 2960/1369/3834 1147/2056/3834 +f 333/2055/3835 1147/2056/3835 2530/917/3835 +f 1397/2057/3836 2438/287/3836 878/2058/3836 +f 334/2059/3837 878/2058/3837 2691/847/3837 +f 1774/2060/3838 3054/1362/3838 1775/2054/3838 +f 334/2059/3839 1775/2054/3839 2798/915/3839 +f 1774/2060/3840 2691/847/3840 1290/846/3840 +f 335/2061/3841 1290/846/3841 2533/845/3841 +f 1558/2048/3842 2959/1365/3842 1776/1363/3842 +f 335/2061/3843 1776/1363/3843 3054/1362/3843 +f 875/277/3844 2688/276/3844 1779/2062/3844 +f 336/2063/3845 1779/2062/3845 3055/1353/3845 +f 1777/1352/3846 2655/1360/3846 842/2064/3846 +f 336/2063/3847 842/2064/3847 2423/278/3847 +f 1287/2065/3848 2530/917/3848 1147/2056/3848 +f 337/2066/3849 1147/2056/3849 2960/1369/3849 +f 1778/2067/3850 3055/1353/3850 1779/2062/3850 +f 337/2066/3851 1779/2062/3851 2688/276/3851 +f 1778/2067/3852 2960/1369/3852 1559/1368/3852 +f 338/2068/3853 1559/1368/3853 2588/1367/3853 +f 1557/2069/3854 2958/1356/3854 1780/1354/3854 +f 338/2068/3855 1780/1354/3855 3055/1353/3855 +f 339/2070/3856 1142/1339/3856 2955/1338/3856 +f 1783/2071/3857 3056/1345/3857 1781/1344/3857 +f 339/2070/3858 1781/1344/3858 2957/1351/3858 +f 1144/2072/3859 2587/1340/3859 1142/1339/3859 +f 340/2073/3860 1554/2074/3860 2529/926/3860 +f 984/2075/3861 2797/271/3861 1782/2076/3861 +f 340/2073/3862 1782/2076/3862 3056/1345/3862 +f 1783/2071/3863 2955/1338/3863 1554/2074/3863 +f 341/2077/3864 1782/2076/3864 2797/271/3864 +f 1396/270/3865 2416/269/3865 1340/2078/3865 +f 341/2077/3866 1340/2078/3866 2741/1347/3866 +f 1784/1346/3867 3056/1345/3867 1782/2076/3867 +f 342/2079/3868 981/997/3868 2794/996/3868 +f 1787/2080/3869 3057/1336/3869 1785/1335/3869 +f 342/2079/3870 1785/1335/3870 2956/1342/3870 +f 1143/2081/3871 2526/998/3871 981/997/3871 +f 343/2082/3872 1393/2083/3872 2437/260/3872 +f 874/2084/3873 2687/928/3873 1786/2085/3873 +f 343/2082/3874 1786/2085/3874 3057/1336/3874 +f 1787/2080/3875 2794/996/3875 1393/2083/3875 +f 344/2086/3876 1786/2085/3876 2687/928/3876 +f 1286/927/3877 2529/926/3877 1554/2074/3877 +f 344/2086/3878 1554/2074/3878 2955/1338/3878 +f 1788/1337/3879 3057/1336/3879 1786/2085/3879 +f 345/2087/3880 871/250/3880 2684/249/3880 +f 1791/2088/3881 3058/1327/3881 1789/1326/3881 +f 345/2087/3882 1789/1326/3882 2656/1333/3882 +f 843/2089/3883 2424/251/3883 871/250/3883 +f 346/2090/3884 1283/2091/3884 2526/998/3884 +f 1143/2081/3885 2956/1342/3885 1790/2092/3885 +f 346/2090/3886 1790/2092/3886 3058/1327/3886 +f 1791/2088/3887 2684/249/3887 1283/2091/3887 +f 347/2093/3888 1790/2092/3888 2956/1342/3888 +f 1555/1341/3889 2587/1340/3889 1553/2094/3889 +f 347/2093/3890 1553/2094/3890 2954/1329/3890 +f 1792/1328/3891 3058/1327/3891 1790/2092/3891 +f 348/2095/3892 1138/1312/3892 2951/1311/3892 +f 1795/2096/3893 3059/1318/3893 1793/1317/3893 +f 348/2095/3894 1793/1317/3894 2953/1324/3894 +f 1140/2097/3895 2586/1313/3895 1138/1312/3895 +f 349/2098/3896 1550/2099/3896 2525/1007/3896 +f 980/2100/3897 2793/244/3897 1794/2101/3897 +f 349/2098/3898 1794/2101/3898 3059/1318/3898 +f 1795/2096/3899 2951/1311/3899 1550/2099/3899 +f 350/2102/3900 1794/2101/3900 2793/244/3900 +f 1392/243/3901 2425/242/3901 1351/2103/3901 +f 350/2102/3902 1351/2103/3902 2752/1320/3902 +f 1796/1319/3903 3059/1318/3903 1794/2101/3903 +f 351/2104/3904 977/1078/3904 2790/1077/3904 +f 1799/2105/3905 3060/1309/3905 1797/1308/3905 +f 351/2104/3906 1797/1308/3906 2952/1315/3906 +f 1139/2106/3907 2522/1079/3907 977/1078/3907 +f 352/2107/3908 1389/2108/3908 2436/233/3908 +f 870/2109/3909 2683/1009/3909 1798/2110/3909 +f 352/2107/3910 1798/2110/3910 3060/1309/3910 +f 1799/2105/3911 2790/1077/3911 1389/2108/3911 +f 353/2111/3912 1798/2110/3912 2683/1009/3912 +f 1282/1008/3913 2525/1007/3913 1550/2099/3913 +f 353/2111/3914 1550/2099/3914 2951/1311/3914 +f 1800/1310/3915 3060/1309/3915 1798/2110/3915 +f 354/2112/3916 867/223/3916 2680/222/3916 +f 1803/2113/3917 3061/1300/3917 1801/1299/3917 +f 354/2112/3918 1801/1299/3918 2738/1306/3918 +f 1337/2114/3919 2414/224/3919 867/223/3919 +f 355/2115/3920 1279/2116/3920 2522/1079/3920 +f 1139/2106/3921 2952/1315/3921 1802/2117/3921 +f 355/2115/3922 1802/2117/3922 3061/1300/3922 +f 1803/2113/3923 2680/222/3923 1279/2116/3923 +f 356/2118/3924 1802/2117/3924 2952/1315/3924 +f 1551/1314/3925 2586/1313/3925 1549/2119/3925 +f 356/2118/3926 1549/2119/3926 2950/1302/3926 +f 1804/1301/3927 3061/1300/3927 1802/2117/3927 +f 357/2120/3928 1134/1285/3928 2947/1284/3928 +f 1807/2121/3929 3062/1291/3929 1805/1290/3929 +f 357/2120/3930 1805/1290/3930 2949/1297/3930 +f 1136/2122/3931 2585/1286/3931 1134/1285/3931 +f 358/2123/3932 1546/2124/3932 2521/1088/3932 +f 976/2125/3933 2789/217/3933 1806/2126/3933 +f 358/2123/3934 1806/2126/3934 3062/1291/3934 +f 1807/2121/3935 2947/1284/3935 1546/2124/3935 +f 359/2127/3936 1806/2126/3936 2789/217/3936 +f 1388/216/3937 2426/215/3937 1352/2009/3937 +f 359/2127/3938 1352/2009/3938 2753/1293/3938 +f 1808/1292/3939 3062/1291/3939 1806/2126/3939 +f 360/2128/3940 973/1159/3940 2786/1158/3940 +f 1811/2129/3941 3063/1282/3941 1809/1281/3941 +f 360/2128/3942 1809/1281/3942 2948/1288/3942 +f 1135/2130/3943 2518/1160/3943 973/1159/3943 +f 361/2131/3944 1385/2132/3944 2435/206/3944 +f 866/2133/3945 2679/1090/3945 1810/2134/3945 +f 361/2131/3946 1810/2134/3946 3063/1282/3946 +f 1811/2129/3947 2786/1158/3947 1385/2132/3947 +f 362/2135/3948 1810/2134/3948 2679/1090/3948 +f 1278/1089/3949 2521/1088/3949 1546/2124/3949 +f 362/2135/3950 1546/2124/3950 2947/1284/3950 +f 1812/1283/3951 3063/1282/3951 1810/2134/3951 +f 363/2136/3952 863/196/3952 2676/195/3952 +f 1815/2137/3953 3064/1273/3953 1813/1272/3953 +f 363/2136/3954 1813/1272/3954 2659/1279/3954 +f 846/2138/3955 2427/197/3955 863/196/3955 +f 364/2139/3956 1275/2140/3956 2518/1160/3956 +f 1135/2130/3957 2948/1288/3957 1814/2141/3957 +f 364/2139/3958 1814/2141/3958 3064/1273/3958 +f 1815/2137/3959 2676/195/3959 1275/2140/3959 +f 365/2142/3960 1814/2141/3960 2948/1288/3960 +f 1547/1287/3961 2585/1286/3961 1545/2143/3961 +f 365/2142/3962 1545/2143/3962 2946/1275/3962 +f 1816/1274/3963 3064/1273/3963 1814/2141/3963 +f 1130/1258/3964 2943/1257/3964 1819/2144/3964 +f 366/2145/3965 1819/2144/3965 3065/1263/3965 +f 1817/1262/3966 2945/1270/3966 1132/2146/3966 +f 366/2145/3967 1132/2146/3967 2584/1259/3967 +f 1542/2147/3968 2517/1655/3968 972/2148/3968 +f 367/2149/3969 972/2148/3969 2785/28/3969 +f 1818/2150/3970 3065/1263/3970 1819/2144/3970 +f 367/2149/3971 1819/2144/3971 2943/1257/3971 +f 1818/2150/3972 2785/28/3972 1384/27/3972 +f 368/2151/3973 1384/27/3973 2415/26/3973 +f 1339/1864/3974 2740/1266/3974 1820/1264/3974 +f 368/2151/3975 1820/1264/3975 3065/1263/3975 +f 969/1429/3976 2782/1428/3976 1823/2152/3976 +f 369/2153/3977 1823/2152/3977 3066/1254/3977 +f 1821/1253/3978 2944/1261/3978 1131/2154/3978 +f 369/2153/3979 1131/2154/3979 2514/1430/3979 +f 1381/2004/3980 2434/80/3980 862/1798/3980 +f 370/2155/3981 862/1798/3981 2675/1657/3981 +f 1822/2156/3982 3066/1254/3982 1823/2152/3982 +f 370/2155/3983 1823/2152/3983 2782/1428/3983 +f 1822/2156/3984 2675/1657/3984 1274/1656/3984 +f 371/2157/3985 1274/1656/3985 2517/1655/3985 +f 1542/2147/3986 2943/1257/3986 1824/1255/3986 +f 371/2157/3987 1824/1255/3987 3066/1254/3987 +f 859/106/3988 2672/105/3988 1827/2158/3988 +f 372/2159/3989 1827/2158/3989 3067/1245/3989 +f 1825/1244/3990 2660/1252/3990 847/2160/3990 +f 372/2159/3991 847/2160/3991 2428/107/3991 +f 1271/2161/3992 2514/1430/3992 1131/2154/3992 +f 373/2162/3993 1131/2154/3993 2944/1261/3993 +f 1826/2163/3994 3067/1245/3994 1827/2158/3994 +f 373/2162/3995 1827/2158/3995 2672/105/3995 +f 1826/2163/3996 2944/1261/3996 1543/1260/3996 +f 374/2164/3997 1543/1260/3997 2584/1259/3997 +f 1541/2165/3998 2942/1248/3998 1828/1246/3998 +f 374/2164/3999 1828/1246/3999 3067/1245/3999 +f 1126/1231/4000 2939/1230/4000 1831/2166/4000 +f 375/2167/4001 1831/2166/4001 3068/1236/4001 +f 1829/1235/4002 2941/1243/4002 1128/2168/4002 +f 375/2167/4003 1128/2168/4003 2583/1232/4003 +f 1538/2169/4004 2513/1169/4004 968/2170/4004 +f 376/2171/4005 968/2170/4005 2781/190/4005 +f 1830/2172/4006 3068/1236/4006 1831/2166/4006 +f 376/2171/4007 1831/2166/4007 2939/1230/4007 +f 1830/2172/4008 2781/190/4008 1380/189/4008 +f 377/2173/4009 1380/189/4009 2429/188/4009 +f 1355/2174/4010 2756/1239/4010 1832/1237/4010 +f 377/2173/4011 1832/1237/4011 3068/1236/4011 +f 965/1699/4012 2778/1698/4012 1835/2175/4012 +f 378/2176/4013 1835/2175/4013 3069/1227/4013 +f 1833/1226/4014 2940/1234/4014 1127/2177/4014 +f 378/2176/4015 1127/2177/4015 2510/1700/4015 +f 1377/1763/4016 2433/8/4016 858/2178/4016 +f 379/2179/4017 858/2178/4017 2671/1171/4017 +f 1834/2180/4018 3069/1227/4018 1835/2175/4018 +f 379/2179/4019 1835/2175/4019 2778/1698/4019 +f 1834/2180/4020 2671/1171/4020 1270/1170/4020 +f 380/2181/4021 1270/1170/4021 2513/1169/4021 +f 1538/2169/4022 2939/1230/4022 1836/1228/4022 +f 380/2181/4023 1836/1228/4023 3069/1227/4023 +f 855/16/4024 2668/15/4024 1839/2182/4024 +f 381/2183/4025 1839/2182/4025 3070/1218/4025 +f 1837/1217/4026 2734/1225/4026 1333/2184/4026 +f 381/2183/4027 1333/2184/4027 2411/17/4027 +f 1267/2185/4028 2510/1700/4028 1127/2177/4028 +f 382/2186/4029 1127/2177/4029 2940/1234/4029 +f 1838/2187/4030 3070/1218/4030 1839/2182/4030 +f 382/2186/4031 1839/2182/4031 2668/15/4031 +f 1838/2187/4032 2940/1234/4032 1539/1233/4032 +f 383/2188/4033 1539/1233/4033 2583/1232/4033 +f 1537/2189/4034 2938/1221/4034 1840/1219/4034 +f 383/2188/4035 1840/1219/4035 3070/1218/4035 +f 1122/1204/4036 2935/1203/4036 1843/2190/4036 +f 384/2191/4037 1843/2190/4037 3071/1209/4037 +f 1841/1208/4038 2937/1216/4038 1124/2192/4038 +f 384/2191/4039 1124/2192/4039 2582/1205/4039 +f 1534/2193/4040 2509/1628/4040 964/2194/4040 +f 385/2195/4041 964/2194/4041 2777/37/4041 +f 1842/2196/4042 3071/1209/4042 1843/2190/4042 +f 385/2195/4043 1843/2190/4043 2935/1203/4043 +f 1842/2196/4044 2777/37/4044 1376/36/4044 +f 386/2197/4045 1376/36/4045 2430/35/4045 +f 1356/2198/4046 2757/1212/4046 1844/1210/4046 +f 386/2197/4047 1844/1210/4047 3071/1209/4047 +f 961/1591/4048 2774/1590/4048 1847/2199/4048 +f 387/2200/4049 1847/2199/4049 3072/1200/4049 +f 1845/1199/4050 2936/1207/4050 1123/2201/4050 +f 387/2200/4051 1123/2201/4051 2506/1592/4051 +f 1373/1860/4052 2432/44/4052 854/1823/4052 +f 388/2202/4053 854/1823/4053 2667/1630/4053 +f 1846/2203/4054 3072/1200/4054 1847/2199/4054 +f 388/2202/4055 1847/2199/4055 2774/1590/4055 +f 1846/2203/4056 2667/1630/4056 1266/1629/4056 +f 389/2204/4057 1266/1629/4057 2509/1628/4057 +f 1534/2193/4058 2935/1203/4058 1848/1201/4058 +f 389/2204/4059 1848/1201/4059 3072/1200/4059 +f 851/52/4060 2664/51/4060 1851/2205/4060 +f 390/2206/4061 1851/2205/4061 3073/1191/4061 +f 1849/1190/4062 2663/1198/4062 850/2207/4062 +f 390/2206/4063 850/2207/4063 2431/53/4063 +f 1263/2208/4064 2506/1592/4064 1123/2201/4064 +f 391/2209/4065 1123/2201/4065 2936/1207/4065 +f 1850/2210/4066 3073/1191/4066 1851/2205/4066 +f 391/2209/4067 1851/2205/4067 2664/51/4067 +f 1850/2210/4068 2936/1207/4068 1535/1206/4068 +f 392/2211/4069 1535/1206/4069 2582/1205/4069 +f 1533/2212/4070 2934/1194/4070 1852/1192/4070 +f 392/2211/4071 1852/1192/4071 3073/1191/4071 +f 1118/1177/4072 2931/1176/4072 1855/2213/4072 +f 393/2214/4073 1855/2213/4073 3074/1182/4073 +f 1853/1181/4074 2933/1189/4074 1120/2215/4074 +f 393/2214/4075 1120/2215/4075 2581/1178/4075 +f 1530/2216/4076 2505/1196/4076 960/2217/4076 +f 394/2218/4077 960/2217/4077 2773/181/4077 +f 1854/2219/4078 3074/1182/4078 1855/2213/4078 +f 394/2218/4079 1855/2213/4079 2931/1176/4079 +f 1854/2219/4080 2773/181/4080 1372/180/4080 +f 395/2220/4081 1372/180/4081 2409/179/4081 +f 1370/2221/4082 2771/1185/4082 1856/1183/4082 +f 395/2220/4083 1856/1183/4083 3074/1182/4083 +f 966/1726/4084 2779/1725/4084 1859/2222/4084 +f 396/2223/4085 1859/2222/4085 3075/1173/4085 +f 1857/1172/4086 2932/1180/4086 1119/2224/4086 +f 396/2223/4087 1119/2224/4087 2511/1727/4087 +f 1378/1738/4088 2431/53/4088 850/2207/4088 +f 397/2225/4089 850/2207/4089 2663/1198/4089 +f 1858/2226/4090 3075/1173/4090 1859/2222/4090 +f 397/2225/4091 1859/2222/4091 2779/1725/4091 +f 1858/2226/4092 2663/1198/4092 1262/1197/4092 +f 398/2227/4093 1262/1197/4093 2505/1196/4093 +f 1530/2216/4094 2931/1176/4094 1860/1174/4094 +f 398/2227/4095 1860/1174/4095 3075/1173/4095 +f 856/7/4096 2669/6/4096 1863/2228/4096 +f 399/2229/4097 1863/2228/4097 3076/1164/4097 +f 1861/1163/4098 2671/1171/4098 858/2178/4098 +f 399/2229/4099 858/2178/4099 2433/8/4099 +f 1268/2230/4100 2511/1727/4100 1119/2224/4100 +f 400/2231/4101 1119/2224/4101 2932/1180/4101 +f 1862/2232/4102 3076/1164/4102 1863/2228/4102 +f 400/2231/4103 1863/2228/4103 2669/6/4103 +f 1862/2232/4104 2932/1180/4104 1531/1179/4104 +f 401/2233/4105 1531/1179/4105 2581/1178/4105 +f 1529/2234/4106 2930/1167/4106 1864/1165/4106 +f 401/2233/4107 1864/1165/4107 3076/1164/4107 +f 402/2235/4108 1114/1150/4108 2927/1149/4108 +f 1867/2236/4109 3077/1156/4109 1865/1155/4109 +f 402/2235/4110 1865/1155/4110 2929/1162/4110 +f 1116/2237/4111 2580/1151/4111 1114/1150/4111 +f 403/2238/4112 1526/2239/4112 2520/1115/4112 +f 975/2240/4113 2788/208/4113 1866/2241/4113 +f 403/2238/4114 1866/2241/4114 3077/1156/4114 +f 1867/2236/4115 2927/1149/4115 1526/2239/4115 +f 404/2242/4116 1866/2241/4116 2788/208/4116 +f 1387/207/4117 2435/206/4117 1385/2132/4117 +f 404/2242/4118 1385/2132/4118 2786/1158/4118 +f 1868/1157/4119 3077/1156/4119 1866/2241/4119 +f 405/2243/4120 919/2244/4120 2732/2245/4120 +f 1871/2246/4121 3078/1147/4121 1869/1146/4121 +f 405/2243/4122 1869/1146/4122 2928/1153/4122 +f 1115/2247/4123 2464/2248/4123 919/2244/4123 +f 406/2249/4124 1331/2250/4124 2383/2251/4124 +f 865/2252/4125 2678/1117/4125 1870/2253/4125 +f 406/2249/4126 1870/2253/4126 3078/1147/4126 +f 1871/2246/4127 2732/2245/4127 1331/2250/4127 +f 407/2254/4128 1870/2253/4128 2678/1117/4128 +f 1277/1116/4129 2520/1115/4129 1526/2239/4129 +f 407/2254/4130 1526/2239/4130 2927/1149/4130 +f 1872/1148/4131 3078/1147/4131 1870/2253/4131 +f 408/2255/4132 809/2256/4132 2622/2257/4132 +f 1875/2258/4133 3079/1138/4133 1873/1137/4133 +f 408/2255/4134 1873/1137/4134 2644/1144/4134 +f 831/2259/4135 2394/2260/4135 809/2256/4135 +f 409/2261/4136 1221/2262/4136 2464/2248/4136 +f 1115/2247/4137 2928/1153/4137 1874/2263/4137 +f 409/2261/4138 1874/2263/4138 3079/1138/4138 +f 1875/2258/4139 2622/2257/4139 1221/2262/4139 +f 410/2264/4140 1874/2263/4140 2928/1153/4140 +f 1527/1152/4141 2580/1151/4141 1525/2265/4141 +f 410/2264/4142 1525/2265/4142 2926/1140/4142 +f 1876/1139/4143 3079/1138/4143 1874/2263/4143 +f 411/2266/4144 1110/1123/4144 2923/1122/4144 +f 1879/2267/4145 3080/1129/4145 1877/1128/4145 +f 411/2266/4146 1877/1128/4146 2925/1135/4146 +f 1112/2268/4147 2579/1124/4147 1110/1123/4147 +f 412/2269/4148 1522/2270/4148 2462/818/4148 +f 917/2271/4149 2730/307/4149 1878/2272/4149 +f 412/2269/4150 1878/2272/4150 3080/1129/4150 +f 1879/2267/4151 2923/1122/4151 1522/2270/4151 +f 413/2273/4152 1878/2272/4152 2730/307/4152 +f 1329/306/4153 2385/305/4153 1386/2274/4153 +f 413/2273/4154 1386/2274/4154 2787/1131/4154 +f 1880/1130/4155 3080/1129/4155 1878/2272/4155 +f 414/2275/4156 905/2276/4156 2718/2277/4156 +f 1883/2278/4157 3081/1120/4157 1881/1119/4157 +f 414/2275/4158 1881/1119/4158 2924/1126/4158 +f 1111/2279/4159 2450/2280/4159 905/2276/4159 +f 415/2281/4160 1317/2282/4160 2389/2283/4160 +f 807/2284/4161 2620/820/4161 1882/2285/4161 +f 415/2281/4162 1882/2285/4162 3081/1120/4162 +f 1883/2278/4163 2718/2277/4163 1317/2282/4163 +f 416/2286/4164 1882/2285/4164 2620/820/4164 +f 1219/819/4165 2462/818/4165 1522/2270/4165 +f 416/2286/4166 1522/2270/4166 2923/1122/4166 +f 1884/1121/4167 3081/1120/4167 1882/2285/4167 +f 417/2287/4168 795/2288/4168 2608/2289/4168 +f 1887/2290/4169 3082/1111/4169 1885/1110/4169 +f 417/2287/4170 1885/1110/4170 2678/1117/4170 +f 865/2252/4171 2383/2251/4171 795/2288/4171 +f 418/2291/4172 1207/2292/4172 2450/2280/4172 +f 1111/2279/4173 2924/1126/4173 1886/2293/4173 +f 418/2291/4174 1886/2293/4174 3082/1111/4174 +f 1887/2290/4175 2608/2289/4175 1207/2292/4175 +f 419/2294/4176 1886/2293/4176 2924/1126/4176 +f 1523/1125/4177 2579/1124/4177 1521/2295/4177 +f 419/2294/4178 1521/2295/4178 2922/1113/4178 +f 1888/1112/4179 3082/1111/4179 1886/2293/4179 +f 420/2296/4180 1106/1096/4180 2919/1095/4180 +f 1891/2297/4181 3083/1102/4181 1889/1101/4181 +f 420/2296/4182 1889/1101/4182 2921/1108/4182 +f 1108/2298/4183 2578/1097/4183 1106/1096/4183 +f 421/2299/4184 1518/2300/4184 2452/1385/4184 +f 907/2301/4185 2720/118/4185 1890/2302/4185 +f 421/2299/4186 1890/2302/4186 3083/1102/4186 +f 1891/2297/4187 2919/1095/4187 1518/2300/4187 +f 422/2303/4188 1890/2302/4188 2720/118/4188 +f 1319/117/4189 2404/116/4189 1367/1935/4189 +f 422/2303/4190 1367/1935/4190 2768/1104/4190 +f 1892/1103/4191 3083/1102/4191 1890/2302/4191 +f 423/2304/4192 974/1132/4192 2787/1131/4192 +f 1895/2305/4193 3084/1093/4193 1893/1092/4193 +f 423/2304/4194 1893/1092/4194 2920/1099/4194 +f 1107/2306/4195 2519/1133/4195 974/1132/4195 +f 424/2307/4196 1386/2274/4196 2385/305/4196 +f 797/2039/4197 2610/1387/4197 1894/2308/4197 +f 424/2307/4198 1894/2308/4198 3084/1093/4198 +f 1895/2305/4199 2787/1131/4199 1386/2274/4199 +f 425/2309/4200 1894/2308/4200 2610/1387/4200 +f 1209/1386/4201 2452/1385/4201 1518/2300/4201 +f 425/2309/4202 1518/2300/4202 2919/1095/4202 +f 1896/1094/4203 3084/1093/4203 1894/2308/4203 +f 426/2310/4204 864/205/4204 2677/204/4204 +f 1899/2311/4205 3085/1084/4205 1897/1083/4205 +f 426/2310/4206 1897/1083/4206 2679/1090/4206 +f 866/2133/4207 2435/206/4207 864/205/4207 +f 427/2312/4208 1276/2313/4208 2519/1133/4208 +f 1107/2306/4209 2920/1099/4209 1898/2314/4209 +f 427/2312/4210 1898/2314/4210 3085/1084/4210 +f 1899/2311/4211 2677/204/4211 1276/2313/4211 +f 428/2315/4212 1898/2314/4212 2920/1099/4212 +f 1519/1098/4213 2578/1097/4213 1517/2316/4213 +f 428/2315/4214 1517/2316/4214 2918/1086/4214 +f 1900/1085/4215 3085/1084/4215 1898/2314/4215 +f 429/2317/4216 1102/1069/4216 2915/1068/4216 +f 1903/2318/4217 3086/1075/4217 1901/1074/4217 +f 429/2317/4218 1901/1074/4218 2917/1081/4218 +f 1104/2319/4219 2577/1070/4219 1102/1069/4219 +f 430/2320/4220 1514/2321/4220 2524/1034/4220 +f 979/2322/4221 2792/235/4221 1902/2323/4221 +f 430/2320/4222 1902/2323/4222 3086/1075/4222 +f 1903/2318/4223 2915/1068/4223 1514/2321/4223 +f 431/2324/4224 1902/2323/4224 2792/235/4224 +f 1391/234/4225 2436/233/4225 1389/2108/4225 +f 431/2324/4226 1389/2108/4226 2790/1077/4226 +f 1904/1076/4227 3086/1075/4227 1902/2323/4227 +f 432/2325/4228 899/2326/4228 2712/2327/4228 +f 1907/2328/4229 3087/1066/4229 1905/1065/4229 +f 432/2325/4230 1905/1065/4230 2916/1072/4230 +f 1103/2329/4231 2444/2330/4231 899/2326/4231 +f 433/2331/4232 1311/2332/4232 2401/2333/4232 +f 869/2334/4233 2682/1036/4233 1906/2335/4233 +f 433/2331/4234 1906/2335/4234 3087/1066/4234 +f 1907/2328/4235 2712/2327/4235 1311/2332/4235 +f 434/2336/4236 1906/2335/4236 2682/1036/4236 +f 1281/1035/4237 2524/1034/4237 1514/2321/4237 +f 434/2336/4238 1514/2321/4238 2915/1068/4238 +f 1908/1067/4239 3087/1066/4239 1906/2335/4239 +f 435/2337/4240 789/2338/4240 2602/2339/4240 +f 1911/2340/4241 3088/1057/4241 1909/1056/4241 +f 435/2337/4242 1909/1056/4242 2713/1063/4242 +f 435/2337/4243 1312/2341/4243 2382/2342/4243 +f 436/2343/4244 1201/2344/4244 2444/2330/4244 +f 1103/2329/4245 2916/1072/4245 1910/2345/4245 +f 436/2343/4246 1910/2345/4246 3088/1057/4246 +f 1911/2340/4247 2602/2339/4247 1201/2344/4247 +f 437/2346/4248 1910/2345/4248 2916/1072/4248 +f 1515/1071/4249 2577/1070/4249 1513/2347/4249 +f 437/2346/4250 1513/2347/4250 2914/1059/4250 +f 1912/1058/4251 3088/1057/4251 1910/2345/4251 +f 438/2348/4252 1098/1042/4252 2911/1041/4252 +f 1915/2349/4253 3089/1048/4253 1913/1047/4253 +f 438/2348/4254 1913/1047/4254 2913/1054/4254 +f 1100/2350/4255 2576/1043/4255 1098/1042/4255 +f 439/2351/4256 1510/2352/4256 2486/1142/4256 +f 941/2353/4257 2754/199/4257 1914/2354/4257 +f 439/2351/4258 1914/2354/4258 3089/1048/4258 +f 1915/2349/4259 2911/1041/4259 1510/2352/4259 +f 440/2355/4260 1914/2354/4260 2754/199/4260 +f 1353/198/4261 2427/197/4261 1390/2356/4261 +f 440/2355/4262 1390/2356/4262 2791/1050/4262 +f 1916/1049/4263 3089/1048/4263 1914/2354/4263 +f 441/2357/4264 926/2358/4264 2739/2359/4264 +f 1919/2360/4265 3090/1039/4265 1917/1038/4265 +f 441/2357/4266 1917/1038/4266 2912/1045/4266 +f 1099/2361/4267 2471/2362/4267 926/2358/4267 +f 442/2363/4268 1338/2364/4268 2394/2260/4268 +f 831/2259/4269 2644/1144/4269 1918/2365/4269 +f 442/2363/4270 1918/2365/4270 3090/1039/4270 +f 1919/2360/4271 2739/2359/4271 1338/2364/4271 +f 443/2366/4272 1918/2365/4272 2644/1144/4272 +f 1243/1143/4273 2486/1142/4273 1510/2352/4273 +f 443/2366/4274 1510/2352/4274 2911/1041/4274 +f 1920/1040/4275 3090/1039/4275 1918/2365/4275 +f 444/2367/4276 816/2368/4276 2629/2369/4276 +f 1923/2370/4277 3091/1030/4277 1921/1029/4277 +f 444/2367/4278 1921/1029/4278 2682/1036/4278 +f 869/2334/4279 2401/2333/4279 816/2368/4279 +f 445/2371/4280 1228/2372/4280 2471/2362/4280 +f 1099/2361/4281 2912/1045/4281 1922/2373/4281 +f 445/2371/4282 1922/2373/4282 3091/1030/4282 +f 1923/2370/4283 2629/2369/4283 1228/2372/4283 +f 446/2374/4284 1922/2373/4284 2912/1045/4284 +f 1511/1044/4285 2576/1043/4285 1509/2375/4285 +f 446/2374/4286 1509/2375/4286 2910/1032/4286 +f 1924/1031/4287 3091/1030/4287 1922/2373/4287 +f 447/2376/4288 1094/1015/4288 2907/1014/4288 +f 1927/2377/4289 3092/1021/4289 1925/1020/4289 +f 447/2376/4290 1925/1020/4290 2909/1027/4290 +f 1096/2378/4291 2575/1016/4291 1094/1015/4291 +f 448/2379/4292 1506/2380/4292 2501/1277/4292 +f 956/2381/4293 2769/154/4293 1926/2382/4293 +f 448/2379/4294 1926/2382/4294 3092/1021/4294 +f 1927/2377/4295 2907/1014/4295 1506/2380/4295 +f 449/2383/4296 1926/2382/4296 2769/154/4296 +f 1368/153/4297 2408/152/4297 1366/2384/4297 +f 449/2383/4298 1366/2384/4298 2767/1023/4298 +f 1928/1022/4299 3092/1021/4299 1926/2382/4299 +f 450/2385/4300 978/1051/4300 2791/1050/4300 +f 1931/2386/4301 3093/1012/4301 1929/1011/4301 +f 450/2385/4302 1929/1011/4302 2908/1018/4302 +f 1095/2387/4303 2523/1052/4303 978/1051/4303 +f 451/2388/4304 1390/2356/4304 2427/197/4304 +f 846/2138/4305 2659/1279/4305 1930/2389/4305 +f 451/2388/4306 1930/2389/4306 3093/1012/4306 +f 1931/2386/4307 2791/1050/4307 1390/2356/4307 +f 452/2390/4308 1930/2389/4308 2659/1279/4308 +f 1258/1278/4309 2501/1277/4309 1506/2380/4309 +f 452/2390/4310 1506/2380/4310 2907/1014/4310 +f 1932/1013/4311 3093/1012/4311 1930/2389/4311 +f 453/2391/4312 868/232/4312 2681/231/4312 +f 1935/2392/4313 3094/1003/4313 1933/1002/4313 +f 453/2391/4314 1933/1002/4314 2683/1009/4314 +f 870/2109/4315 2436/233/4315 868/232/4315 +f 454/2393/4316 1280/2394/4316 2523/1052/4316 +f 1095/2387/4317 2908/1018/4317 1934/2395/4317 +f 454/2393/4318 1934/2395/4318 3094/1003/4318 +f 1935/2392/4319 2681/231/4319 1280/2394/4319 +f 455/2396/4320 1934/2395/4320 2908/1018/4320 +f 1507/1017/4321 2575/1016/4321 1505/2397/4321 +f 455/2396/4322 1505/2397/4322 2906/1005/4322 +f 1936/1004/4323 3094/1003/4323 1934/2395/4323 +f 1090/988/4324 2903/987/4324 1939/2398/4324 +f 456/2399/4325 1939/2398/4325 3095/994/4325 +f 1937/993/4326 2905/1000/4326 1092/2400/4326 +f 456/2399/4327 1092/2400/4327 2574/989/4327 +f 1502/2401/4328 2528/953/4328 983/2402/4328 +f 983/2402/4329 2796/262/4329 1938/2403/4329 +f 1938/2403/4330 3095/994/4330 1939/2398/4330 +f 457/2404/4331 1939/2398/4331 2903/987/4331 +f 458/2405/4332 1938/2403/4332 2796/262/4332 +f 1395/261/4333 2437/260/4333 1393/2083/4333 +f 458/2405/4334 1393/2083/4334 2794/996/4334 +f 1940/995/4335 3095/994/4335 1938/2403/4335 +f 936/1375/4336 2749/1374/4336 1943/2406/4336 +f 459/2407/4337 1943/2406/4337 3096/984/4337 +f 1941/983/4338 2904/991/4338 1091/2408/4338 +f 459/2407/4339 1091/2408/4339 2481/1376/4339 +f 1348/2053/4340 2422/296/4340 873/2409/4340 +f 460/2410/4341 873/2409/4341 2686/955/4341 +f 1942/2411/4342 3096/984/4342 1943/2406/4342 +f 460/2410/4343 1943/2406/4343 2749/1374/4343 +f 1942/2411/4344 2686/955/4344 1285/954/4344 +f 461/2412/4345 1285/954/4345 2528/953/4345 +f 1502/2401/4346 2903/987/4346 1944/985/4346 +f 461/2412/4347 1944/985/4347 3096/984/4347 +f 826/124/4348 2639/123/4348 1947/2413/4348 +f 462/2414/4349 1947/2413/4349 3097/975/4349 +f 1945/974/4350 2641/982/4350 828/2415/4350 +f 462/2414/4351 828/2415/4351 2407/125/4351 +f 1238/2416/4352 2481/1376/4352 1091/2408/4352 +f 463/2417/4353 1091/2408/4353 2904/991/4353 +f 1946/2418/4354 3097/975/4354 1947/2413/4354 +f 463/2417/4355 1947/2413/4355 2639/123/4355 +f 1946/2418/4356 2904/991/4356 1503/990/4356 +f 464/2419/4357 1503/990/4357 2574/989/4357 +f 1501/2420/4358 2902/978/4358 1948/976/4358 +f 464/2419/4359 1948/976/4359 3097/975/4359 +f 1086/961/4360 2899/960/4360 1951/2421/4360 +f 465/2422/4361 1951/2421/4361 3098/967/4361 +f 1949/966/4362 2901/973/4362 1088/2423/4362 +f 465/2422/4363 1088/2423/4363 2573/962/4363 +f 1498/2424/4364 2459/2425/4364 1216/2426/4364 +f 1216/2426/4365 2617/2427/4365 1950/2428/4365 +f 1950/2428/4366 3098/967/4366 1951/2421/4366 +f 466/2429/4367 1951/2421/4367 2899/960/4367 +f 467/2430/4368 1950/2428/4368 2617/2427/4368 +f 804/2431/4369 2392/2432/4369 1394/2433/4369 +f 467/2430/4370 1394/2433/4370 2795/969/4370 +f 1952/968/4371 3098/967/4371 1950/2428/4371 +f 951/862/4372 2764/861/4372 1955/2434/4372 +f 468/2435/4373 1955/2434/4373 3099/957/4373 +f 1953/956/4374 2900/964/4374 1087/2436/4374 +f 468/2435/4375 1087/2436/4375 2496/863/4375 +f 1363/2437/4376 2399/2438/4376 1326/2439/4376 +f 469/2440/4377 1326/2439/4377 2727/2441/4377 +f 1954/2442/4378 3099/957/4378 1955/2434/4378 +f 469/2440/4379 1955/2434/4379 2764/861/4379 +f 1954/2442/4380 2727/2441/4380 914/2443/4380 +f 470/2444/4381 914/2443/4381 2459/2425/4381 +f 1498/2424/4382 2899/960/4382 1956/958/4382 +f 470/2444/4383 1956/958/4383 3099/957/4383 +f 841/295/4384 2654/294/4384 1959/2445/4384 +f 471/2446/4385 1959/2445/4385 3100/948/4385 +f 1957/947/4386 2686/955/4386 873/2409/4386 +f 471/2446/4387 873/2409/4387 2422/296/4387 +f 1253/2447/4388 2496/863/4388 1087/2436/4388 +f 472/2448/4389 1087/2436/4389 2900/964/4389 +f 1958/2449/4390 3100/948/4390 1959/2445/4390 +f 472/2448/4391 1959/2445/4391 2654/294/4391 +f 1958/2449/4392 2900/964/4392 1499/963/4392 +f 473/2450/4393 1499/963/4393 2573/962/4393 +f 1497/2451/4394 2898/951/4394 1960/949/4394 +f 473/2450/4395 1960/949/4395 3100/948/4395 +f 474/2452/4396 1082/934/4396 2895/933/4396 +f 1963/2453/4397 3101/940/4397 1961/939/4397 +f 474/2452/4398 1961/939/4398 2897/946/4398 +f 1084/2454/4399 2572/935/4399 1082/934/4399 +f 475/2455/4400 1494/2456/4400 2457/2457/4400 +f 1214/2458/4401 2615/2459/4401 1962/2460/4401 +f 475/2455/4402 1962/2460/4402 3101/940/4402 +f 1963/2453/4403 2895/933/4403 1494/2456/4403 +f 476/2461/4404 1962/2460/4404 2615/2459/4404 +f 802/2462/4405 2390/2463/4405 1346/2464/4405 +f 476/2461/4406 1346/2464/4406 2747/942/4406 +f 1964/941/4407 3101/940/4407 1962/2460/4407 +f 477/2465/4408 982/970/4408 2795/969/4408 +f 1967/2466/4409 3102/931/4409 1965/930/4409 +f 477/2465/4410 1965/930/4410 2896/937/4410 +f 1083/2467/4411 2527/971/4411 982/970/4411 +f 478/2468/4412 1394/2433/4412 2392/2432/4412 +f 1324/2469/4413 2725/2470/4413 1966/2471/4413 +f 478/2468/4414 1966/2471/4414 3102/931/4414 +f 1967/2466/4415 2795/969/4415 1394/2433/4415 +f 479/2472/4416 1966/2471/4416 2725/2470/4416 +f 912/2473/4417 2457/2457/4417 1494/2456/4417 +f 479/2472/4418 1494/2456/4418 2895/933/4418 +f 1968/932/4419 3102/931/4419 1966/2471/4419 +f 480/2474/4420 872/259/4420 2685/258/4420 +f 1971/2475/4421 3103/922/4421 1969/921/4421 +f 480/2474/4422 1969/921/4422 2687/928/4422 +f 874/2084/4423 2437/260/4423 872/259/4423 +f 481/2476/4424 1284/2477/4424 2527/971/4424 +f 1083/2467/4425 2896/937/4425 1970/2478/4425 +f 481/2476/4426 1970/2478/4426 3103/922/4426 +f 1971/2475/4427 2685/258/4427 1284/2477/4427 +f 482/2479/4428 1970/2478/4428 2896/937/4428 +f 1495/936/4429 2572/935/4429 1493/2480/4429 +f 482/2479/4430 1493/2480/4430 2894/924/4430 +f 1972/923/4431 3103/922/4431 1970/2478/4431 +f 1078/907/4432 2891/906/4432 1975/2481/4432 +f 483/2482/4433 1975/2481/4433 3104/912/4433 +f 1973/911/4434 2893/919/4434 1080/2483/4434 +f 483/2482/4435 1080/2483/4435 2571/908/4435 +f 1490/2484/4436 2532/872/4436 987/2485/4436 +f 484/2486/4437 987/2485/4437 2800/289/4437 +f 1974/2487/4438 3104/912/4438 1975/2481/4438 +f 484/2486/4439 1975/2481/4439 2891/906/4439 +f 1974/2487/4440 2800/289/4440 1399/288/4440 +f 485/2488/4441 1399/288/4441 2438/287/4441 +f 1397/2057/4442 2798/915/4442 1976/913/4442 +f 485/2488/4443 1976/913/4443 3104/912/4443 +f 923/2489/4444 2736/2490/4444 1979/2491/4444 +f 486/2492/4445 1979/2491/4445 3105/903/4445 +f 1977/902/4446 2892/910/4446 1079/2493/4446 +f 486/2492/4447 1079/2493/4447 2468/2494/4447 +f 1335/2495/4448 2412/2496/4448 877/2497/4448 +f 487/2498/4449 877/2497/4449 2690/874/4449 +f 1978/2499/4450 3105/903/4450 1979/2491/4450 +f 487/2498/4451 1979/2491/4451 2736/2490/4451 +f 1978/2499/4452 2690/874/4452 1289/873/4452 +f 488/2500/4453 1289/873/4453 2532/872/4453 +f 1490/2484/4454 2891/906/4454 1980/904/4454 +f 488/2500/4455 1980/904/4455 3105/903/4455 +f 813/2501/4456 2626/2502/4456 1983/2503/4456 +f 489/2504/4457 1983/2503/4457 3106/894/4457 +f 1981/893/4458 2640/901/4458 827/2505/4458 +f 489/2504/4459 827/2505/4459 2398/2506/4459 +f 1225/2507/4460 2468/2494/4460 1079/2493/4460 +f 490/2508/4461 1079/2493/4461 2892/910/4461 +f 1982/2509/4462 3106/894/4462 1983/2503/4462 +f 490/2508/4463 1983/2503/4463 2626/2502/4463 +f 1982/2509/4464 2892/910/4464 1491/909/4464 +f 491/2510/4465 1491/909/4465 2571/908/4465 +f 1489/2511/4466 2890/897/4466 1984/895/4466 +f 491/2510/4467 1984/895/4467 3106/894/4467 +f 1074/880/4468 2887/879/4468 1987/2512/4468 +f 492/2513/4469 1987/2512/4469 3107/885/4469 +f 1985/884/4470 2889/892/4470 1076/2514/4470 +f 492/2513/4471 1076/2514/4471 2570/881/4471 +f 1486/2515/4472 2446/2516/4472 1203/2517/4472 +f 493/2518/4473 1203/2517/4473 2604/2519/4473 +f 1986/2520/4474 3107/885/4474 1987/2512/4474 +f 493/2518/4475 1987/2512/4475 2887/879/4475 +f 1986/2520/4476 2604/2519/4476 791/2521/4476 +f 494/2522/4477 791/2521/4477 2413/2523/4477 +f 1398/2524/4478 2799/888/4478 1988/886/4478 +f 494/2522/4479 1988/886/4479 3107/885/4479 +f 902/2525/4480 2715/2526/4480 1991/2527/4480 +f 495/2528/4481 1991/2527/4481 3108/876/4481 +f 1989/875/4482 2888/883/4482 1075/2529/4482 +f 495/2528/4483 1075/2529/4483 2447/2530/4483 +f 496/2531/4484 1314/2532/4484 2381/2533/4484 +f 496/2531/4485 1313/2534/4485 2714/2535/4485 +f 1990/2536/4486 3108/876/4486 1991/2527/4486 +f 496/2531/4487 1991/2527/4487 2715/2526/4487 +f 1990/2536/4488 2714/2535/4488 901/2537/4488 +f 497/2538/4489 901/2537/4489 2446/2516/4489 +f 1486/2515/4490 2887/879/4490 1992/877/4490 +f 497/2538/4491 1992/877/4491 3108/876/4491 +f 792/2539/4492 2605/2540/4492 1995/2541/4492 +f 498/2542/4493 1995/2541/4493 3109/867/4493 +f 1993/866/4494 2690/874/4494 877/2497/4494 +f 498/2542/4495 877/2497/4495 2412/2496/4495 +f 1204/2543/4496 2447/2530/4496 1075/2529/4496 +f 499/2544/4497 1075/2529/4497 2888/883/4497 +f 1994/2545/4498 3109/867/4498 1995/2541/4498 +f 499/2544/4499 1995/2541/4499 2605/2540/4499 +f 1994/2545/4500 2888/883/4500 1487/882/4500 +f 500/2546/4501 1487/882/4501 2570/881/4501 +f 1485/2547/4502 2886/870/4502 1996/868/4502 +f 500/2546/4503 1996/868/4503 3109/867/4503 +f 1070/853/4504 2883/852/4504 1999/2548/4504 +f 501/2549/4505 1999/2548/4505 3110/858/4505 +f 1997/857/4506 2885/865/4506 1072/2550/4506 +f 501/2549/4507 1072/2550/4507 2569/854/4507 +f 1482/2551/4508 2469/2552/4508 1226/2553/4508 +f 502/2554/4509 1226/2553/4509 2627/2555/4509 +f 1998/2556/4510 3110/858/4510 1999/2548/4510 +f 502/2554/4511 1999/2548/4511 2883/852/4511 +f 1998/2556/4512 2627/2555/4512 814/2557/4512 +f 503/2558/4513 814/2557/4513 2399/2438/4513 +f 1363/2437/4514 2764/861/4514 2000/859/4514 +f 503/2558/4515 2000/859/4515 3110/858/4515 +f 986/889/4516 2799/888/4516 2003/2559/4516 +f 504/2560/4517 2003/2559/4517 3111/849/4517 +f 2001/848/4518 2884/856/4518 1071/2561/4518 +f 504/2560/4519 1071/2561/4519 2531/890/4519 +f 1398/2524/4520 2413/2523/4520 1336/2562/4520 +f 505/2563/4521 1336/2562/4521 2737/2564/4521 +f 2002/2565/4522 3111/849/4522 2003/2559/4522 +f 505/2563/4523 2003/2559/4523 2799/888/4523 +f 2002/2565/4524 2737/2564/4524 924/2566/4524 +f 506/2567/4525 924/2566/4525 2469/2552/4525 +f 1482/2551/4526 2883/852/4526 2004/850/4526 +f 506/2567/4527 2004/850/4527 3111/849/4527 +f 876/286/4528 2689/285/4528 2007/2568/4528 +f 507/2569/4529 2007/2568/4529 3112/840/4529 +f 2005/839/4530 2691/847/4530 878/2058/4530 +f 507/2569/4531 878/2058/4531 2438/287/4531 +f 1288/2570/4532 2531/890/4532 1071/2561/4532 +f 508/2571/4533 1071/2561/4533 2884/856/4533 +f 2006/2572/4534 3112/840/4534 2007/2568/4534 +f 508/2571/4535 2007/2568/4535 2689/285/4535 +f 2006/2572/4536 2884/856/4536 1483/855/4536 +f 509/2573/4537 1483/855/4537 2569/854/4537 +f 1481/2574/4538 2882/843/4538 2008/841/4538 +f 509/2573/4539 2008/841/4539 3112/840/4539 +f 1066/826/4540 2879/825/4540 2011/2575/4540 +f 510/2576/4541 2011/2575/4541 3113/831/4541 +f 2009/830/4542 2881/838/4542 1068/2577/4542 +f 510/2576/4543 1068/2577/4543 2568/827/4543 +f 1478/2578/4544 2536/791/4544 991/2579/4544 +f 511/2580/4545 991/2579/4545 2804/316/4545 +f 2010/2581/4546 3113/831/4546 2011/2575/4546 +f 511/2580/4547 2011/2575/4547 2879/825/4547 +f 2010/2581/4548 2804/316/4548 1403/315/4548 +f 512/2582/4549 1403/315/4549 2439/314/4549 +f 1401/2032/4550 2802/834/4550 2012/832/4550 +f 512/2582/4551 2012/832/4551 3113/831/4551 +f 911/2583/4552 2724/2584/4552 2015/2585/4552 +f 513/2586/4553 2015/2585/4553 3114/822/4553 +f 2013/821/4554 2880/829/4554 1067/2587/4554 +f 513/2586/4555 1067/2587/4555 2456/2588/4555 +f 1323/2589/4556 2397/2590/4556 881/2591/4556 +f 514/2592/4557 881/2591/4557 2694/793/4557 +f 2014/2593/4558 3114/822/4558 2015/2585/4558 +f 514/2592/4559 2015/2585/4559 2724/2584/4559 +f 2014/2593/4560 2694/793/4560 1293/792/4560 +f 515/2594/4561 1293/792/4561 2536/791/4561 +f 1478/2578/4562 2879/825/4562 2016/823/4562 +f 515/2594/4563 2016/823/4563 3114/822/4563 +f 801/2595/4564 2614/2596/4564 2019/2597/4564 +f 516/2598/4565 2019/2597/4565 3115/813/4565 +f 516/2598/4566 2017/812/4566 2620/820/4566 +f 807/2284/4567 2389/2283/4567 801/2595/4567 +f 1213/2599/4568 2456/2588/4568 1067/2587/4568 +f 517/2600/4569 1067/2587/4569 2880/829/4569 +f 2018/2601/4570 3115/813/4570 2019/2597/4570 +f 517/2600/4571 2019/2597/4571 2614/2596/4571 +f 2018/2601/4572 2880/829/4572 1479/828/4572 +f 518/2602/4573 1479/828/4573 2568/827/4573 +f 1477/2603/4574 2878/816/4574 2020/814/4574 +f 518/2602/4575 2020/814/4575 3115/813/4575 +f 1062/799/4576 2875/798/4576 2023/2604/4576 +f 519/2605/4577 2023/2604/4577 3116/804/4577 +f 2021/803/4578 2877/811/4578 1064/2606/4578 +f 519/2605/4579 1064/2606/4579 2567/800/4579 +f 1474/2607/4580 2482/899/4580 937/2608/4580 +f 520/2609/4581 937/2608/4581 2750/280/4581 +f 2022/2610/4582 3116/804/4582 2023/2604/4582 +f 520/2609/4583 2023/2604/4583 2875/798/4583 +f 2022/2610/4584 2750/280/4584 1349/279/4584 +f 521/2611/4585 1349/279/4585 2423/278/4585 +f 1402/2612/4586 2803/807/4586 2024/805/4586 +f 521/2611/4587 2024/805/4587 3116/804/4587 +f 922/2613/4588 2735/2614/4588 2027/2615/4588 +f 522/2616/4589 2027/2615/4589 3117/795/4589 +f 2025/794/4590 2876/802/4590 1063/2617/4590 +f 522/2616/4591 1063/2617/4591 2467/2618/4591 +f 1334/2619/4592 2398/2506/4592 827/2505/4592 +f 523/2620/4593 827/2505/4593 2640/901/4593 +f 2026/2621/4594 3117/795/4594 2027/2615/4594 +f 523/2620/4595 2027/2615/4595 2735/2614/4595 +f 2026/2621/4596 2640/901/4596 1239/900/4596 +f 524/2622/4597 1239/900/4597 2482/899/4597 +f 1474/2607/4598 2875/798/4598 2028/796/4598 +f 524/2622/4599 2028/796/4599 3117/795/4599 +f 812/2623/4600 2625/2624/4600 2031/2625/4600 +f 525/2626/4601 2031/2625/4601 3118/786/4601 +f 2029/785/4602 2694/793/4602 881/2591/4602 +f 525/2626/4603 881/2591/4603 2397/2590/4603 +f 1224/2627/4604 2467/2618/4604 1063/2617/4604 +f 526/2628/4605 1063/2617/4605 2876/802/4605 +f 2030/2629/4606 3118/786/4606 2031/2625/4606 +f 526/2628/4607 2031/2625/4607 2625/2624/4607 +f 2030/2629/4608 2876/802/4608 1475/801/4608 +f 527/2630/4609 1475/801/4609 2567/800/4609 +f 1473/2631/4610 2874/789/4610 2032/787/4610 +f 527/2630/4611 2032/787/4611 3118/786/4611 +f 1058/772/4612 2871/771/4612 2035/2632/4612 +f 528/2633/4613 2035/2632/4613 3119/777/4613 +f 2033/776/4614 2873/784/4614 1060/2634/4614 +f 528/2633/4615 1060/2634/4615 2566/773/4615 +f 1470/2635/4616 2497/1358/4616 952/2636/4616 +f 529/2637/4617 952/2636/4617 2765/127/4617 +f 2034/2638/4618 3119/777/4618 2035/2632/4618 +f 529/2637/4619 2035/2632/4619 2871/771/4619 +f 2034/2638/4620 2765/127/4620 1364/126/4620 +f 530/2639/4621 1364/126/4621 2407/125/4621 +f 1362/2640/4622 2763/780/4622 2036/778/4622 +f 530/2639/4623 2036/778/4623 3119/777/4623 +f 990/808/4624 2803/807/4624 2039/2641/4624 +f 531/2642/4625 2039/2641/4625 3120/768/4625 +f 2037/767/4626 2872/775/4626 1059/2643/4626 +f 531/2642/4627 1059/2643/4627 2535/809/4627 +f 1402/2612/4628 2423/278/4628 842/2064/4628 +f 532/2644/4629 842/2064/4629 2655/1360/4629 +f 2038/2645/4630 3120/768/4630 2039/2641/4630 +f 532/2644/4631 2039/2641/4631 2803/807/4631 +f 2038/2645/4632 2655/1360/4632 1254/1359/4632 +f 533/2646/4633 1254/1359/4633 2497/1358/4633 +f 1470/2635/4634 2871/771/4634 2040/769/4634 +f 533/2646/4635 2040/769/4635 3120/768/4635 +f 880/313/4636 2693/312/4636 2043/2647/4636 +f 534/2648/4637 2043/2647/4637 3121/759/4637 +f 2041/758/4638 2695/766/4638 882/2033/4638 +f 534/2648/4639 882/2033/4639 2439/314/4639 +f 1292/2649/4640 2535/809/4640 1059/2643/4640 +f 535/2650/4641 1059/2643/4641 2872/775/4641 +f 2042/2651/4642 3121/759/4642 2043/2647/4642 +f 535/2650/4643 2043/2647/4643 2693/312/4643 +f 2042/2651/4644 2872/775/4644 1471/774/4644 +f 536/2652/4645 1471/774/4645 2566/773/4645 +f 1469/2653/4646 2870/762/4646 2044/760/4646 +f 536/2652/4647 2044/760/4647 3121/759/4647 +f 537/2654/4648 1054/745/4648 2867/744/4648 +f 2047/2655/4649 3122/751/4649 2045/750/4649 +f 537/2654/4650 2045/750/4650 2869/757/4650 +f 1056/2656/4651 2565/746/4651 1054/745/4651 +f 538/2657/4652 1466/2658/4652 2540/710/4652 +f 995/2659/4653 2808/343/4653 2046/2660/4653 +f 538/2657/4654 2046/2660/4654 3122/751/4654 +f 2047/2655/4655 2867/744/4655 1466/2658/4655 +f 539/2661/4656 2046/2660/4656 2808/343/4656 +f 1407/342/4657 2440/341/4657 1405/1984/4657 +f 539/2661/4658 1405/1984/4658 2806/753/4658 +f 2048/752/4659 3122/751/4659 2046/2660/4659 +f 540/2662/4660 928/1348/4660 2741/1347/4660 +f 2051/2663/4661 3123/742/4661 2049/741/4661 +f 540/2662/4662 2049/741/4662 2868/748/4662 +f 1055/2664/4663 2473/1349/4663 928/1348/4663 +f 541/2665/4664 1340/2078/4664 2416/269/4664 +f 885/2666/4665 2698/712/4665 2050/2667/4665 +f 541/2665/4666 2050/2667/4666 3123/742/4666 +f 2051/2663/4667 2741/1347/4667 1340/2078/4667 +f 542/2668/4668 2050/2667/4668 2698/712/4668 +f 1297/711/4669 2540/710/4669 1466/2658/4669 +f 542/2668/4670 1466/2658/4670 2867/744/4670 +f 2052/743/4671 3123/742/4671 2050/2667/4671 +f 543/2669/4672 818/133/4672 2631/132/4672 +f 2055/2670/4673 3124/733/4673 2053/732/4673 +f 543/2669/4674 2053/732/4674 2636/739/4674 +f 823/2671/4675 2403/134/4675 818/133/4675 +f 544/2672/4676 1230/2673/4676 2473/1349/4676 +f 1055/2664/4677 2868/748/4677 2054/2674/4677 +f 544/2672/4678 2054/2674/4678 3124/733/4678 +f 2055/2670/4679 2631/132/4679 1230/2673/4679 +f 545/2675/4680 2054/2674/4680 2868/748/4680 +f 1467/747/4681 2565/746/4681 1465/2676/4681 +f 545/2675/4682 1465/2676/4682 2866/735/4682 +f 2056/734/4683 3124/733/4683 2054/2674/4683 +f 546/2677/4684 1050/718/4684 2863/717/4684 +f 2059/2678/4685 3125/724/4685 2057/723/4685 +f 546/2677/4686 2057/723/4686 2865/730/4686 +f 1052/2679/4687 2564/719/4687 1050/718/4687 +f 547/2680/4688 1462/2681/4688 2449/2682/4688 +f 1206/2683/4689 2607/2684/4689 2058/2685/4689 +f 547/2680/4690 2058/2685/4690 3125/724/4690 +f 2059/2678/4691 2863/717/4691 1462/2681/4691 +f 548/2686/4692 2058/2685/4692 2607/2684/4692 +f 794/2687/4693 2410/2688/4693 1406/2689/4693 +f 548/2686/4694 1406/2689/4694 2807/726/4694 +f 2060/725/4695 3125/724/4695 2058/2685/4695 +f 549/2690/4696 934/943/4696 2747/942/4696 +f 2063/2691/4697 3126/715/4697 2061/714/4697 +f 549/2690/4698 2061/714/4698 2864/721/4698 +f 1051/2692/4699 2479/944/4699 934/943/4699 +f 550/2693/4700 1346/2464/4700 2390/2463/4700 +f 1316/2694/4701 2717/2695/4701 2062/2696/4701 +f 550/2693/4702 2062/2696/4702 3126/715/4702 +f 2063/2691/4703 2747/942/4703 1346/2464/4703 +f 551/2697/4704 2062/2696/4704 2717/2695/4704 +f 904/2698/4705 2449/2682/4705 1462/2681/4705 +f 551/2697/4706 1462/2681/4706 2863/717/4706 +f 2064/716/4707 3126/715/4707 2062/2696/4707 +f 552/2699/4708 824/268/4708 2637/267/4708 +f 2067/2700/4709 3127/706/4709 2065/705/4709 +f 552/2699/4710 2065/705/4710 2698/712/4710 +f 885/2666/4711 2416/269/4711 824/268/4711 +f 553/2701/4712 1236/2702/4712 2479/944/4712 +f 1051/2692/4713 2864/721/4713 2066/2703/4713 +f 553/2701/4714 2066/2703/4714 3127/706/4714 +f 2067/2700/4715 2637/267/4715 1236/2702/4715 +f 554/2704/4716 2066/2703/4716 2864/721/4716 +f 1463/720/4717 2564/719/4717 1461/2705/4717 +f 554/2704/4718 1461/2705/4718 2862/708/4718 +f 2068/707/4719 3127/706/4719 2066/2703/4719 +f 555/2706/4720 1046/691/4720 2859/690/4720 +f 2071/2707/4721 3128/697/4721 2069/696/4721 +f 555/2706/4722 2069/696/4722 2861/703/4722 +f 1048/2708/4723 2563/692/4723 1046/691/4723 +f 556/2709/4724 1458/2710/4724 2465/2711/4724 +f 1222/2712/4725 2623/2713/4725 2070/2714/4725 +f 556/2709/4726 2070/2714/4726 3128/697/4726 +f 2071/2707/4727 2859/690/4727 1458/2710/4727 +f 557/2715/4728 2070/2714/4728 2623/2713/4728 +f 557/2715/4729 810/2716/4729 2395/2717/4729 +f 557/2715/4730 1360/2718/4730 2761/699/4730 +f 2072/698/4731 3128/697/4731 2070/2714/4731 +f 558/2719/4732 994/727/4732 2807/726/4732 +f 2075/2720/4733 3129/688/4733 2073/687/4733 +f 558/2719/4734 2073/687/4734 2860/694/4734 +f 1047/2721/4735 2539/728/4735 994/727/4735 +f 559/2722/4736 1406/2689/4736 2410/2688/4736 +f 1332/2723/4737 2733/2724/4737 2074/2725/4737 +f 559/2722/4738 2074/2725/4738 3129/688/4738 +f 2075/2720/4739 2807/726/4739 1406/2689/4739 +f 560/2726/4740 2074/2725/4740 2733/2724/4740 +f 920/2727/4741 2465/2711/4741 1458/2710/4741 +f 560/2726/4742 1458/2710/4742 2859/690/4742 +f 2076/689/4743 3129/688/4743 2074/2725/4743 +f 561/2728/4744 884/340/4744 2697/339/4744 +f 2079/2729/4745 3130/679/4745 2077/678/4745 +f 561/2728/4746 2077/678/4746 2699/685/4746 +f 886/1985/4747 2440/341/4747 884/340/4747 +f 562/2730/4748 1296/2731/4748 2539/728/4748 +f 1047/2721/4749 2860/694/4749 2078/2732/4749 +f 562/2730/4750 2078/2732/4750 3130/679/4750 +f 2079/2729/4751 2697/339/4751 1296/2731/4751 +f 563/2733/4752 2078/2732/4752 2860/694/4752 +f 1459/693/4753 2563/692/4753 1457/2734/4753 +f 563/2733/4754 1457/2734/4754 2858/681/4754 +f 2080/680/4755 3130/679/4755 2078/2732/4755 +f 564/2735/4756 1042/664/4756 2855/663/4756 +f 2083/2736/4757 3131/670/4757 2081/669/4757 +f 564/2735/4758 2081/669/4758 2857/676/4758 +f 1044/2737/4759 2562/665/4759 1042/664/4759 +f 565/2738/4760 1454/2739/4760 2544/629/4760 +f 999/2740/4761 2812/370/4761 2082/2741/4761 +f 565/2738/4762 2082/2741/4762 3131/670/4762 +f 2083/2736/4763 2855/663/4763 1454/2739/4763 +f 566/2742/4764 2082/2741/4764 2812/370/4764 +f 1411/369/4765 2441/368/4765 1409/1960/4765 +f 566/2742/4766 1409/1960/4766 2810/672/4766 +f 2084/671/4767 3131/670/4767 2082/2741/4767 +f 567/2743/4768 916/1537/4768 2729/1536/4768 +f 2087/2744/4769 3132/661/4769 2085/660/4769 +f 567/2743/4770 2085/660/4770 2856/667/4770 +f 1043/2745/4771 2461/1538/4771 916/1537/4771 +f 568/2746/4772 1328/1907/4772 2386/404/4772 +f 889/2747/4773 2702/631/4773 2086/2748/4773 +f 568/2746/4774 2086/2748/4774 3132/661/4774 +f 2087/2744/4775 2729/1536/4775 1328/1907/4775 +f 569/2749/4776 2086/2748/4776 2702/631/4776 +f 1301/630/4777 2544/629/4777 1454/2739/4777 +f 569/2749/4778 1454/2739/4778 2855/663/4778 +f 2088/662/4779 3132/661/4779 2086/2748/4779 +f 806/70/4780 2619/69/4780 2091/2750/4780 +f 570/2751/4781 2091/2750/4781 3133/651/4781 +f 2089/650/4782 2621/658/4782 808/1840/4782 +f 570/2751/4783 808/1840/4783 2393/71/4783 +f 571/2752/4784 1218/2753/4784 2461/1538/4784 +f 1043/2745/4785 2856/667/4785 2090/2754/4785 +f 571/2752/4786 2090/2754/4786 3133/651/4786 +f 2091/2750/4787 2619/69/4787 1218/2753/4787 +f 572/2755/4788 2090/2754/4788 2856/667/4788 +f 1455/666/4789 2562/665/4789 1453/2756/4789 +f 572/2755/4790 1453/2756/4790 2854/654/4790 +f 2092/652/4791 3133/651/4791 2090/2754/4791 +f 573/2757/4792 1038/637/4792 2851/636/4792 +f 2095/2758/4793 3134/643/4793 2093/642/4793 +f 573/2757/4794 2093/642/4794 2853/649/4794 +f 1040/2759/4795 2561/638/4795 1038/637/4795 +f 574/2760/4796 1450/2761/4796 2478/737/4796 +f 933/2762/4797 2746/334/4797 2094/2763/4797 +f 574/2760/4798 2094/2763/4798 3134/643/4798 +f 2095/2758/4799 2851/636/4799 1450/2761/4799 +f 575/2764/4800 2094/2763/4800 2746/334/4800 +f 1345/333/4801 2420/332/4801 1410/2765/4801 +f 575/2764/4802 1410/2765/4802 2811/645/4802 +f 2096/644/4803 3134/643/4803 2094/2763/4803 +f 576/2766/4804 908/538/4804 2721/537/4804 +f 2099/2767/4805 3135/634/4805 2097/633/4805 +f 576/2766/4806 2097/633/4806 2852/640/4806 +f 1039/2768/4807 2453/539/4807 908/538/4807 +f 577/2769/4808 1320/2770/4808 2403/134/4808 +f 823/2671/4809 2636/739/4809 2098/2771/4809 +f 577/2769/4810 2098/2771/4810 3135/634/4810 +f 2099/2767/4811 2721/537/4811 1320/2770/4811 +f 578/2772/4812 2098/2771/4812 2636/739/4812 +f 1235/738/4813 2478/737/4813 1450/2761/4813 +f 578/2772/4814 1450/2761/4814 2851/636/4814 +f 2100/635/4815 3135/634/4815 2098/2771/4815 +f 579/2773/4816 798/403/4816 2611/402/4816 +f 2103/2774/4817 3136/625/4817 2101/624/4817 +f 579/2773/4818 2101/624/4818 2702/631/4818 +f 889/2747/4819 2386/404/4819 798/403/4819 +f 580/2775/4820 1210/2776/4820 2453/539/4820 +f 1039/2768/4821 2852/640/4821 2102/2777/4821 +f 580/2775/4822 2102/2777/4822 3136/625/4822 +f 2103/2774/4823 2611/402/4823 1210/2776/4823 +f 581/2778/4824 2102/2777/4824 2852/640/4824 +f 1451/639/4825 2561/638/4825 1449/2779/4825 +f 581/2778/4826 1449/2779/4826 2850/627/4826 +f 2104/626/4827 3136/625/4827 2102/2777/4827 +f 582/2780/4828 1034/610/4828 2847/609/4828 +f 2107/2781/4829 3137/616/4829 2105/615/4829 +f 582/2780/4830 2105/615/4830 2849/622/4830 +f 1036/2782/4831 2560/611/4831 1034/610/4831 +f 583/2783/4832 1446/2784/4832 2494/1439/4832 +f 949/2785/4833 2762/100/4833 2106/2786/4833 +f 583/2783/4834 2106/2786/4834 3137/616/4834 +f 2107/2781/4835 2847/609/4835 1446/2784/4835 +f 584/2787/4836 2106/2786/4836 2762/100/4836 +f 1361/99/4837 2406/98/4837 1359/2788/4837 +f 584/2787/4838 1359/2788/4838 2760/618/4838 +f 2108/617/4839 3137/616/4839 2106/2786/4839 +f 585/2789/4840 998/646/4840 2811/645/4840 +f 2111/2790/4841 3138/607/4841 2109/606/4841 +f 585/2789/4842 2109/606/4842 2848/613/4842 +f 1035/2791/4843 2543/647/4843 998/646/4843 +f 586/2792/4844 1410/2765/4844 2420/332/4844 +f 839/1990/4845 2652/1441/4845 2110/2793/4845 +f 586/2792/4846 2110/2793/4846 3138/607/4846 +f 2111/2790/4847 2811/645/4847 1410/2765/4847 +f 587/2794/4848 2110/2793/4848 2652/1441/4848 +f 1251/1440/4849 2494/1439/4849 1446/2784/4849 +f 587/2794/4850 1446/2784/4850 2847/609/4850 +f 2112/608/4851 3138/607/4851 2110/2793/4851 +f 588/2795/4852 888/367/4852 2701/366/4852 +f 2115/2796/4853 3139/598/4853 2113/597/4853 +f 588/2795/4854 2113/597/4854 2703/604/4854 +f 890/1961/4855 2441/368/4855 888/367/4855 +f 589/2797/4856 1300/2798/4856 2543/647/4856 +f 1035/2791/4857 2848/613/4857 2114/2799/4857 +f 589/2797/4858 2114/2799/4858 3139/598/4858 +f 2115/2796/4859 2701/366/4859 1300/2798/4859 +f 590/2800/4860 2114/2799/4860 2848/613/4860 +f 1447/612/4861 2560/611/4861 1445/2801/4861 +f 590/2800/4862 1445/2801/4862 2846/600/4862 +f 2116/599/4863 3139/598/4863 2114/2799/4863 +f 1030/583/4864 2843/582/4864 2119/2802/4864 +f 591/2803/4865 2119/2802/4865 3140/589/4865 +f 2117/588/4866 2845/595/4866 1032/2804/4866 +f 591/2803/4867 1032/2804/4867 2559/584/4867 +f 1442/2805/4868 2548/548/4868 1003/2806/4868 +f 1003/2806/4869 2816/397/4869 2118/2807/4869 +f 2118/2807/4870 3140/589/4870 2119/2802/4870 +f 592/2808/4871 2119/2802/4871 2843/582/4871 +f 593/2809/4872 2118/2807/4872 2816/397/4872 +f 1415/396/4873 2442/395/4873 1413/1912/4873 +f 593/2809/4874 1413/1912/4874 2814/591/4874 +f 2120/590/4875 3140/589/4875 2118/2807/4875 +f 935/1402/4876 2748/1401/4876 2123/2810/4876 +f 594/2811/4877 2123/2810/4877 3141/579/4877 +f 2121/578/4878 2844/586/4878 1031/2812/4878 +f 594/2811/4879 1031/2812/4879 2480/1403/4879 +f 1347/2028/4880 2421/323/4880 893/2813/4880 +f 595/2814/4881 893/2813/4881 2706/550/4881 +f 2122/2815/4882 3141/579/4882 2123/2810/4882 +f 595/2814/4883 2123/2810/4883 2748/1401/4883 +f 2122/2815/4884 2706/550/4884 1305/549/4884 +f 596/2816/4885 1305/549/4885 2548/548/4885 +f 1442/2805/4886 2843/582/4886 2124/580/4886 +f 596/2816/4887 2124/580/4887 3141/579/4887 +f 825/115/4888 2638/114/4888 2127/2817/4888 +f 2127/2817/4889 3142/571/4889 2125/570/4889 +f 597/2818/4890 2125/570/4890 2632/577/4890 +f 819/1936/4891 2404/116/4891 825/115/4891 +f 1237/2819/4892 2480/1403/4892 1031/2812/4892 +f 598/2820/4893 1031/2812/4893 2844/586/4893 +f 2126/2821/4894 3142/571/4894 2127/2817/4894 +f 598/2820/4895 2127/2817/4895 2638/114/4895 +f 2126/2821/4896 2844/586/4896 1443/585/4896 +f 599/2822/4897 1443/585/4897 2559/584/4897 +f 1441/2823/4898 2842/573/4898 2128/572/4898 +f 599/2822/4899 2128/572/4899 3142/571/4899 +f 1026/556/4900 2839/555/4900 2131/2824/4900 +f 600/2825/4901 2131/2824/4901 3143/562/4901 +f 2129/561/4902 2841/568/4902 1028/2826/4902 +f 600/2825/4903 1028/2826/4903 2558/557/4903 +f 1438/2827/4904 2483/980/4904 938/2828/4904 +f 601/2829/4905 938/2828/4905 2751/253/4905 +f 2130/2830/4906 3143/562/4906 2131/2824/4906 +f 601/2829/4907 2131/2824/4907 2839/555/4907 +f 602/2831/4908 2130/2830/4908 2751/253/4908 +f 1350/252/4909 2424/251/4909 1414/2832/4909 +f 602/2831/4910 1414/2832/4910 2815/564/4910 +f 2132/563/4911 3143/562/4911 2130/2830/4911 +f 950/781/4912 2763/780/4912 2135/2833/4912 +f 603/2834/4913 2135/2833/4913 3144/552/4913 +f 2133/551/4914 2840/559/4914 1027/2835/4914 +f 603/2834/4915 1027/2835/4915 2495/782/4915 +f 1362/2640/4916 2407/125/4916 828/2415/4916 +f 604/2836/4917 828/2415/4917 2641/982/4917 +f 2134/2837/4918 3144/552/4918 2135/2833/4918 +f 604/2836/4919 2135/2833/4919 2763/780/4919 +f 2134/2837/4920 2641/982/4920 1240/981/4920 +f 605/2838/4921 1240/981/4921 2483/980/4921 +f 1438/2827/4922 2839/555/4922 2136/553/4922 +f 605/2838/4923 2136/553/4923 3144/552/4923 +f 840/322/4924 2653/321/4924 2139/2839/4924 +f 606/2840/4925 2139/2839/4925 3145/543/4925 +f 2137/542/4926 2706/550/4926 893/2813/4926 +f 606/2840/4927 893/2813/4927 2421/323/4927 +f 1252/2841/4928 2495/782/4928 1027/2835/4928 +f 607/2842/4929 1027/2835/4929 2840/559/4929 +f 2138/2843/4930 3145/543/4930 2139/2839/4930 +f 607/2842/4931 2139/2839/4931 2653/321/4931 +f 2138/2843/4932 2840/559/4932 1439/558/4932 +f 608/2844/4933 1439/558/4933 2558/557/4933 +f 1437/2845/4934 2838/546/4934 2140/544/4934 +f 608/2844/4935 2140/544/4935 3145/543/4935 +f 609/2846/4936 1022/529/4936 2835/528/4936 +f 2143/2847/4937 3146/535/4937 2141/534/4937 +f 609/2846/4938 2141/534/4938 2837/541/4938 +f 1024/2848/4939 2557/530/4939 1022/529/4939 +f 610/2849/4940 1434/2850/4940 2498/1331/4940 +f 953/2851/4941 2766/136/4941 2142/2852/4941 +f 610/2849/4942 2142/2852/4942 3146/535/4942 +f 2143/2847/4943 2835/528/4943 1434/2850/4943 +f 611/2853/4944 2142/2852/4944 2766/136/4944 +f 1365/135/4945 2403/134/4945 1320/2770/4945 +f 611/2853/4946 1320/2770/4946 2721/537/4946 +f 2144/536/4947 3146/535/4947 2142/2852/4947 +f 612/2854/4948 1002/565/4948 2815/564/4948 +f 2147/2855/4949 3147/526/4949 2145/525/4949 +f 612/2854/4950 2145/525/4950 2836/532/4950 +f 1023/2856/4951 2547/566/4951 1002/565/4951 +f 613/2857/4952 1414/2832/4952 2424/251/4952 +f 843/2089/4953 2656/1333/4953 2146/2858/4953 +f 613/2857/4954 2146/2858/4954 3147/526/4954 +f 2147/2855/4955 2815/564/4955 1414/2832/4955 +f 614/2859/4956 2146/2858/4956 2656/1333/4956 +f 1255/1332/4957 2498/1331/4957 1434/2850/4957 +f 614/2859/4958 1434/2850/4958 2835/528/4958 +f 2148/527/4959 3147/526/4959 2146/2858/4959 +f 615/2860/4960 892/394/4960 2705/393/4960 +f 2151/2861/4961 3148/517/4961 2149/516/4961 +f 615/2860/4962 2149/516/4962 2707/523/4962 +f 894/1913/4963 2442/395/4963 892/394/4963 +f 616/2862/4964 1304/2863/4964 2547/566/4964 +f 1023/2856/4965 2836/532/4965 2150/2864/4965 +f 616/2862/4966 2150/2864/4966 3148/517/4966 +f 2151/2861/4967 2705/393/4967 1304/2863/4967 +f 617/2865/4968 2150/2864/4968 2836/532/4968 +f 1435/531/4969 2557/530/4969 1433/2866/4969 +f 617/2865/4970 1433/2866/4970 2834/519/4970 +f 2152/518/4971 3148/517/4971 2150/2864/4971 +f 618/2867/4972 1018/502/4972 2831/501/4972 +f 2155/2868/4973 3149/507/4973 2153/506/4973 +f 2153/506/4974 2833/514/4974 1020/2869/4974 +f 1020/2869/4975 2556/503/4975 1018/502/4975 +f 619/2870/4976 1430/2871/4976 2552/467/4976 +f 1007/2872/4977 2820/424/4977 2154/2873/4977 +f 2154/2873/4978 3149/507/4978 2155/2868/4978 +f 2155/2868/4979 2831/501/4979 1430/2871/4979 +f 2154/2873/4980 2820/424/4980 1419/423/4980 +f 620/2874/4981 1419/423/4981 2443/422/4981 +f 1417/1886/4982 2818/510/4982 2156/508/4982 +f 620/2874/4983 2156/508/4983 3149/507/4983 +f 621/2875/4984 939/1321/4984 2752/1320/4984 +f 2159/2876/4985 3150/499/4985 2157/498/4985 +f 621/2875/4986 2157/498/4986 2832/505/4986 +f 1019/2877/4987 2484/1322/4987 939/1321/4987 +f 622/2878/4988 1351/2103/4988 2425/242/4988 +f 897/2879/4989 2710/469/4989 2158/2880/4989 +f 622/2878/4990 2158/2880/4990 3150/499/4990 +f 2159/2876/4991 2752/1320/4991 1351/2103/4991 +f 623/2881/4992 2158/2880/4992 2710/469/4992 +f 1309/468/4993 2552/467/4993 1430/2871/4993 +f 623/2881/4994 1430/2871/4994 2831/501/4994 +f 2160/500/4995 3150/499/4995 2158/2880/4995 +f 624/2882/4996 829/142/4996 2642/141/4996 +f 2163/2883/4997 3151/490/4997 2161/489/4997 +f 624/2882/4998 2161/489/4998 2723/496/4998 +f 1322/2884/4999 2400/143/4999 829/142/4999 +f 625/2885/5000 1241/2886/5000 2484/1322/5000 +f 1019/2877/5001 2832/505/5001 2162/2887/5001 +f 625/2885/5002 2162/2887/5002 3151/490/5002 +f 2163/2883/5003 2642/141/5003 1241/2886/5003 +f 626/2888/5004 2162/2887/5004 2832/505/5004 +f 1431/504/5005 2556/503/5005 1429/2889/5005 +f 626/2888/5006 1429/2889/5006 2830/492/5006 +f 2164/491/5007 3151/490/5007 2162/2887/5007 +f 627/2890/5008 1014/475/5008 2827/474/5008 +f 2167/2891/5009 3152/480/5009 2165/479/5009 +f 2165/479/5010 2829/487/5010 1016/2892/5010 +f 1016/2892/5011 2555/476/5011 1014/475/5011 +f 628/2893/5012 1426/2894/5012 2487/1412/5012 +f 942/2895/5013 2755/109/5013 2166/2896/5013 +f 2166/2896/5014 3152/480/5014 2167/2891/5014 +f 2167/2891/5015 2827/474/5015 1426/2894/5015 +f 2166/2896/5016 2755/109/5016 1354/108/5016 +f 629/2897/5017 1354/108/5017 2428/107/5017 +f 1418/2898/5018 2819/483/5018 2168/481/5018 +f 629/2897/5019 2168/481/5019 3152/480/5019 +f 630/2899/5020 954/1024/5020 2767/1023/5020 +f 2171/2900/5021 3153/472/5021 2169/471/5021 +f 630/2899/5022 2169/471/5022 2828/478/5022 +f 1015/2901/5023 2499/1025/5023 954/1024/5023 +f 631/2902/5024 1366/2384/5024 2408/152/5024 +f 832/2014/5025 2645/1414/5025 2170/2903/5025 +f 631/2902/5026 2170/2903/5026 3153/472/5026 +f 2171/2900/5027 2767/1023/5027 1366/2384/5027 +f 632/2904/5028 2170/2903/5028 2645/1414/5028 +f 1244/1413/5029 2487/1412/5029 1426/2894/5029 +f 632/2904/5030 1426/2894/5030 2827/474/5030 +f 2172/473/5031 3153/472/5031 2170/2903/5031 +f 633/2905/5032 844/241/5032 2657/240/5032 +f 2175/2906/5033 3154/463/5033 2173/462/5033 +f 633/2905/5034 2173/462/5034 2710/469/5034 +f 897/2879/5035 2425/242/5035 844/241/5035 +f 634/2907/5036 1256/2908/5036 2499/1025/5036 +f 1015/2901/5037 2828/478/5037 2174/2909/5037 +f 634/2907/5038 2174/2909/5038 3154/463/5038 +f 2175/2906/5039 2657/240/5039 1256/2908/5039 +f 635/2910/5040 2174/2909/5040 2828/478/5040 +f 1427/477/5041 2555/476/5041 1425/2911/5041 +f 635/2910/5042 1425/2911/5042 2826/465/5042 +f 2176/464/5043 3154/463/5043 2174/2909/5043 +f 1010/448/5044 2823/447/5044 2179/2912/5044 +f 636/2913/5045 2179/2912/5045 3155/453/5045 +f 2177/452/5046 2825/460/5046 1012/2914/5046 +f 636/2913/5047 1012/2914/5047 2554/449/5047 +f 1422/2915/5048 2502/1250/5048 957/2916/5048 +f 637/2917/5049 957/2916/5049 2770/163/5049 +f 2178/2918/5050 3155/453/5050 2179/2912/5050 +f 637/2917/5051 2179/2912/5051 2823/447/5051 +f 2178/2918/5052 2770/163/5052 1369/162/5052 +f 638/2919/5053 1369/162/5053 2402/161/5053 +f 1321/1742/5054 2722/456/5054 2180/454/5054 +f 638/2919/5055 2180/454/5055 3155/453/5055 +f 1006/484/5056 2819/483/5056 2183/2920/5056 +f 639/2921/5057 2183/2920/5057 3156/444/5057 +f 2181/443/5058 2824/451/5058 1011/2922/5058 +f 639/2921/5059 1011/2922/5059 2551/485/5059 +f 1418/2898/5060 2428/107/5060 847/2160/5060 +f 640/2923/5061 847/2160/5061 2660/1252/5061 +f 2182/2924/5062 3156/444/5062 2183/2920/5062 +f 640/2923/5063 2183/2920/5063 2819/483/5063 +f 2182/2924/5064 2660/1252/5064 1259/1251/5064 +f 641/2925/5065 1259/1251/5065 2502/1250/5065 +f 1422/2915/5066 2823/447/5066 2184/445/5066 +f 641/2925/5067 2184/445/5067 3156/444/5067 +f 896/421/5068 2709/420/5068 2187/2926/5068 +f 642/2927/5069 2187/2926/5069 3157/435/5069 +f 2185/434/5070 2711/442/5070 898/1887/5070 +f 642/2927/5071 898/1887/5071 2443/422/5071 +f 1308/2928/5072 2551/485/5072 1011/2922/5072 +f 643/2929/5073 1011/2922/5073 2824/451/5073 +f 2186/2930/5074 3157/435/5074 2187/2926/5074 +f 643/2929/5075 2187/2926/5075 2709/420/5075 +f 2186/2930/5076 2824/451/5076 1423/450/5076 +f 644/2931/5077 1423/450/5077 2554/449/5077 +f 1421/2932/5078 2822/438/5078 2188/436/5078 +f 644/2931/5079 2188/436/5079 3157/435/5079 +f 1009/439/5080 2822/438/5080 2191/2933/5080 +f 645/2934/5081 2191/2933/5081 3158/426/5081 +f 2189/425/5082 2821/433/5082 1008/1879/5082 +f 645/2934/5083 1008/1879/5083 2553/440/5083 +f 1421/2932/5084 2554/449/5084 1012/2914/5084 +f 646/2935/5085 1012/2914/5085 2825/460/5085 +f 2190/2936/5086 3158/426/5086 2191/2933/5086 +f 646/2935/5087 2191/2933/5087 2822/438/5087 +f 2190/2936/5088 2825/460/5088 1424/459/5088 +f 647/2937/5089 1424/459/5089 2454/458/5089 +f 1211/1750/5090 2612/429/5090 2192/427/5090 +f 647/2937/5091 2192/427/5091 3158/426/5091 +f 648/2938/5092 1013/466/5092 2826/465/5092 +f 648/2938/5093 2195/2939/5093 3159/417/5093 +f 2193/416/5094 2820/424/5094 1007/2872/5094 +f 1007/2872/5095 2552/467/5095 1013/466/5095 +f 649/2940/5096 1425/2911/5096 2555/476/5096 +f 649/2940/5097 1016/2892/5097 2829/487/5097 +f 2194/2941/5098 3159/417/5098 2195/2939/5098 +f 2195/2939/5099 2826/465/5099 1425/2911/5099 +f 2194/2941/5100 2829/487/5100 1428/486/5100 +f 650/2942/5101 1428/486/5101 2551/485/5101 +f 1308/2928/5102 2709/420/5102 2196/418/5102 +f 650/2942/5103 2196/418/5103 3159/417/5103 +f 651/2943/5104 1017/493/5104 2830/492/5104 +f 2199/2944/5105 3160/408/5105 2197/407/5105 +f 2197/407/5106 2613/415/5106 1212/2945/5106 +f 1212/2945/5107 2455/494/5107 1017/493/5107 +f 652/2946/5108 1429/2889/5108 2556/503/5108 +f 1020/2869/5109 2833/514/5109 2198/2947/5109 +f 652/2946/5110 2198/2947/5110 3160/408/5110 +f 2199/2944/5111 2830/492/5111 1429/2889/5111 +f 2198/2947/5112 2833/514/5112 1432/513/5112 +f 653/2948/5113 1432/513/5113 2550/512/5113 +f 1307/1894/5114 2708/411/5114 2200/409/5114 +f 653/2948/5115 2200/409/5115 3160/408/5115 +f 654/2949/5116 1021/520/5116 2834/519/5116 +f 2203/2950/5117 3161/400/5117 2201/399/5117 +f 654/2949/5118 2201/399/5118 2817/406/5118 +f 1004/1904/5119 2549/521/5119 1021/520/5119 +f 655/2951/5120 1433/2866/5120 2557/530/5120 +f 1024/2848/5121 2837/541/5121 2202/2952/5121 +f 655/2951/5122 2202/2952/5122 3161/400/5122 +f 2203/2950/5123 2834/519/5123 1433/2866/5123 +f 656/2953/5124 2202/2952/5124 2837/541/5124 +f 1436/540/5125 2453/539/5125 1210/2776/5125 +f 656/2953/5126 1210/2776/5126 2611/402/5126 +f 2204/401/5127 3161/400/5127 2202/2952/5127 +f 1025/547/5128 2838/546/5128 2207/2954/5128 +f 2207/2954/5129 3162/391/5129 2205/390/5129 +f 2205/390/5130 2816/397/5130 1003/2806/5130 +f 657/2955/5131 1003/2806/5131 2548/548/5131 +f 1437/2845/5132 2558/557/5132 1028/2826/5132 +f 658/2956/5133 1028/2826/5133 2841/568/5133 +f 2206/2957/5134 3162/391/5134 2207/2954/5134 +f 658/2956/5135 2207/2954/5135 2838/546/5135 +f 659/2958/5136 2206/2957/5136 2841/568/5136 +f 1440/567/5137 2547/566/5137 1304/2863/5137 +f 659/2958/5138 1304/2863/5138 2705/393/5138 +f 2208/392/5139 3162/391/5139 2206/2957/5139 +f 1029/574/5140 2842/573/5140 2211/2959/5140 +f 660/2960/5141 2211/2959/5141 3163/381/5141 +f 2209/380/5142 2742/388/5142 929/1928/5142 +f 929/1928/5143 2474/575/5143 1029/574/5143 +f 1441/2823/5144 2559/584/5144 1032/2804/5144 +f 1032/2804/5145 2845/595/5145 2210/2961/5145 +f 2210/2961/5146 3163/381/5146 2211/2959/5146 +f 661/2962/5147 2211/2959/5147 2842/573/5147 +f 662/2963/5148 2210/2961/5148 2845/595/5148 +f 1444/594/5149 2546/593/5149 1303/1919/5149 +f 662/2963/5150 1303/1919/5150 2704/384/5150 +f 2212/382/5151 3163/381/5151 2210/2961/5151 +f 663/2964/5152 1033/601/5152 2846/600/5152 +f 2215/2965/5153 3164/373/5153 2213/372/5153 +f 663/2964/5154 2213/372/5154 2813/379/5154 +f 1000/1952/5155 2545/602/5155 1033/601/5155 +f 664/2966/5156 1445/2801/5156 2560/611/5156 +f 1036/2782/5157 2849/622/5157 2214/2967/5157 +f 664/2966/5158 2214/2967/5158 3164/373/5158 +f 2215/2965/5159 2846/600/5159 1445/2801/5159 +f 665/2968/5160 2214/2967/5160 2849/622/5160 +f 1448/621/5161 2492/620/5161 1249/2969/5161 +f 665/2968/5162 1249/2969/5162 2650/375/5162 +f 2216/374/5163 3164/373/5163 2214/2967/5163 +f 666/2970/5164 1037/628/5164 2850/627/5164 +f 2219/2971/5165 3165/364/5165 2217/363/5165 +f 666/2970/5166 2217/363/5166 2812/370/5166 +f 999/2740/5167 2544/629/5167 1037/628/5167 +f 667/2972/5168 1449/2779/5168 2561/638/5168 +f 1040/2759/5169 2853/649/5169 2218/2973/5169 +f 667/2972/5170 2218/2973/5170 3165/364/5170 +f 2219/2971/5171 2850/627/5171 1449/2779/5171 +f 668/2974/5172 2218/2973/5172 2853/649/5172 +f 1452/648/5173 2543/647/5173 1300/2798/5173 +f 668/2974/5174 1300/2798/5174 2701/366/5174 +f 2220/365/5175 3165/364/5175 2218/2973/5175 +f 1041/655/5176 2854/654/5176 2223/2975/5176 +f 669/2976/5177 2223/2975/5177 3166/354/5177 +f 2221/353/5178 2731/361/5178 918/1833/5178 +f 669/2976/5179 918/1833/5179 2463/656/5179 +f 670/2977/5180 1453/2756/5180 2562/665/5180 +f 1044/2737/5181 2857/676/5181 2222/2978/5181 +f 670/2977/5182 2222/2978/5182 3166/354/5182 +f 2223/2975/5183 2854/654/5183 1453/2756/5183 +f 671/2979/5184 2222/2978/5184 2857/676/5184 +f 1456/675/5185 2542/674/5185 1299/1967/5185 +f 671/2979/5186 1299/1967/5186 2700/357/5186 +f 2224/355/5187 3166/354/5187 2222/2978/5187 +f 672/2980/5188 1045/682/5188 2858/681/5188 +f 2227/2981/5189 3167/346/5189 2225/345/5189 +f 672/2980/5190 2225/345/5190 2809/352/5190 +f 996/1976/5191 2541/683/5191 1045/682/5191 +f 673/2982/5192 1457/2734/5192 2563/692/5192 +f 1048/2708/5193 2861/703/5193 2226/2983/5193 +f 673/2982/5194 2226/2983/5194 3167/346/5194 +f 2227/2981/5195 2858/681/5195 1457/2734/5195 +f 674/2984/5196 2226/2983/5196 2861/703/5196 +f 1460/702/5197 2493/701/5197 1250/2985/5197 +f 674/2984/5198 1250/2985/5198 2651/348/5198 +f 2228/347/5199 3167/346/5199 2226/2983/5199 +f 675/2986/5200 1049/709/5200 2862/708/5200 +f 2231/2987/5201 3168/337/5201 2229/336/5201 +f 675/2986/5202 2229/336/5202 2808/343/5202 +f 995/2659/5203 2540/710/5203 1049/709/5203 +f 676/2988/5204 1461/2705/5204 2564/719/5204 +f 1052/2679/5205 2865/730/5205 2230/2989/5205 +f 676/2988/5206 2230/2989/5206 3168/337/5206 +f 2231/2987/5207 2862/708/5207 1461/2705/5207 +f 677/2990/5208 2230/2989/5208 2865/730/5208 +f 1464/729/5209 2539/728/5209 1296/2731/5209 +f 677/2990/5210 1296/2731/5210 2697/339/5210 +f 2232/338/5211 3168/337/5211 2230/2989/5211 +f 678/2991/5212 1053/736/5212 2866/735/5212 +f 2235/2992/5213 3169/328/5213 2233/327/5213 +f 678/2991/5214 2233/327/5214 2746/334/5214 +f 933/2762/5215 2478/737/5215 1053/736/5215 +f 679/2993/5216 1465/2676/5216 2565/746/5216 +f 1056/2656/5217 2869/757/5217 2234/2994/5217 +f 679/2993/5218 2234/2994/5218 3169/328/5218 +f 2235/2992/5219 2866/735/5219 1465/2676/5219 +f 680/2995/5220 2234/2994/5220 2869/757/5220 +f 1468/756/5221 2538/755/5221 1295/1992/5221 +f 680/2995/5222 1295/1992/5222 2696/330/5222 +f 2236/329/5223 3169/328/5223 2234/2994/5223 +f 1057/763/5224 2870/762/5224 2239/2996/5224 +f 681/2997/5225 2239/2996/5225 3170/318/5225 +f 2237/317/5226 2805/325/5226 992/2024/5226 +f 681/2997/5227 992/2024/5227 2537/764/5227 +f 1469/2653/5228 2566/773/5228 1060/2634/5228 +f 682/2998/5229 1060/2634/5229 2873/784/5229 +f 2238/2999/5230 3170/318/5230 2239/2996/5230 +f 682/2998/5231 2239/2996/5231 2870/762/5231 +f 2238/2999/5232 2873/784/5232 1472/783/5232 +f 683/3000/5233 1472/783/5233 2495/782/5233 +f 1252/2841/5234 2653/321/5234 2240/319/5234 +f 683/3000/5235 2240/319/5235 3170/318/5235 +f 1061/790/5236 2874/789/5236 2243/3001/5236 +f 684/3002/5237 2243/3001/5237 3171/309/5237 +f 2241/308/5238 2804/316/5238 991/2579/5238 +f 684/3002/5239 991/2579/5239 2536/791/5239 +f 1473/2631/5240 2567/800/5240 1064/2606/5240 +f 685/3003/5241 1064/2606/5241 2877/811/5241 +f 2242/3004/5242 3171/309/5242 2243/3001/5242 +f 685/3003/5243 2243/3001/5243 2874/789/5243 +f 2242/3004/5244 2877/811/5244 1476/810/5244 +f 686/3005/5245 1476/810/5245 2535/809/5245 +f 1292/2649/5246 2693/312/5246 2244/310/5246 +f 686/3005/5247 2244/310/5247 3171/309/5247 +f 1065/817/5248 2878/816/5248 2247/3006/5248 +f 687/3007/5249 2247/3006/5249 3172/300/5249 +f 687/3007/5250 2245/299/5250 2730/307/5250 +f 917/2271/5251 2462/818/5251 1065/817/5251 +f 1477/2603/5252 2568/827/5252 1068/2577/5252 +f 688/3008/5253 1068/2577/5253 2881/838/5253 +f 2246/3009/5254 3172/300/5254 2247/3006/5254 +f 688/3008/5255 2247/3006/5255 2878/816/5255 +f 2246/3009/5256 2881/838/5256 1480/837/5256 +f 689/3010/5257 1480/837/5257 2534/836/5257 +f 1291/2040/5258 2692/303/5258 2248/301/5258 +f 689/3010/5259 2248/301/5259 3172/300/5259 +f 1069/844/5260 2882/843/5260 2251/3011/5260 +f 690/3012/5261 2251/3011/5261 3173/291/5261 +f 2249/290/5262 2801/298/5262 988/2049/5262 +f 690/3012/5263 988/2049/5263 2533/845/5263 +f 1481/2574/5264 2569/854/5264 1072/2550/5264 +f 691/3013/5265 1072/2550/5265 2885/865/5265 +f 2250/3014/5266 3173/291/5266 2251/3011/5266 +f 691/3013/5267 2251/3011/5267 2882/843/5267 +f 2250/3014/5268 2885/865/5268 1484/864/5268 +f 692/3015/5269 1484/864/5269 2496/863/5269 +f 1253/2447/5270 2654/294/5270 2252/292/5270 +f 692/3015/5271 2252/292/5271 3173/291/5271 +f 1073/871/5272 2886/870/5272 2255/3016/5272 +f 693/3017/5273 2255/3016/5273 3174/282/5273 +f 2253/281/5274 2800/289/5274 987/2485/5274 +f 693/3017/5275 987/2485/5275 2532/872/5275 +f 1485/2547/5276 2570/881/5276 1076/2514/5276 +f 694/3018/5277 1076/2514/5277 2889/892/5277 +f 2254/3019/5278 3174/282/5278 2255/3016/5278 +f 694/3018/5279 2255/3016/5279 2886/870/5279 +f 2254/3019/5280 2889/892/5280 1488/891/5280 +f 695/3020/5281 1488/891/5281 2531/890/5281 +f 1288/2570/5282 2689/285/5282 2256/283/5282 +f 695/3020/5283 2256/283/5283 3174/282/5283 +f 1077/898/5284 2890/897/5284 2259/3021/5284 +f 696/3022/5285 2259/3021/5285 3175/273/5285 +f 2257/272/5286 2750/280/5286 937/2608/5286 +f 696/3022/5287 937/2608/5287 2482/899/5287 +f 1489/2511/5288 2571/908/5288 1080/2483/5288 +f 697/3023/5289 1080/2483/5289 2893/919/5289 +f 2258/3024/5290 3175/273/5290 2259/3021/5290 +f 697/3023/5291 2259/3021/5291 2890/897/5291 +f 2258/3024/5292 2893/919/5292 1492/918/5292 +f 698/3025/5293 1492/918/5293 2530/917/5293 +f 1287/2065/5294 2688/276/5294 2260/274/5294 +f 698/3025/5295 2260/274/5295 3175/273/5295 +f 699/3026/5296 1081/925/5296 2894/924/5296 +f 2263/3027/5297 3176/265/5297 2261/264/5297 +f 699/3026/5298 2261/264/5298 2797/271/5298 +f 984/2075/5299 2529/926/5299 1081/925/5299 +f 700/3028/5300 1493/2480/5300 2572/935/5300 +f 1084/2454/5301 2897/946/5301 2262/3029/5301 +f 700/3028/5302 2262/3029/5302 3176/265/5302 +f 2263/3027/5303 2894/924/5303 1493/2480/5303 +f 701/3030/5304 2262/3029/5304 2897/946/5304 +f 1496/945/5305 2479/944/5305 1236/2702/5305 +f 701/3030/5306 1236/2702/5306 2637/267/5306 +f 2264/266/5307 3176/265/5307 2262/3029/5307 +f 1085/952/5308 2898/951/5308 2267/3031/5308 +f 702/3032/5309 2267/3031/5309 3177/256/5309 +f 702/3032/5310 2265/255/5310 2796/262/5310 +f 702/3032/5311 983/2402/5311 2528/953/5311 +f 1497/2451/5312 2573/962/5312 1088/2423/5312 +f 1088/2423/5313 2901/973/5313 2266/3033/5313 +f 2266/3033/5314 3177/256/5314 2267/3031/5314 +f 703/3034/5315 2267/3031/5315 2898/951/5315 +f 704/3035/5316 2266/3033/5316 2901/973/5316 +f 1500/972/5317 2527/971/5317 1284/2477/5317 +f 704/3035/5318 1284/2477/5318 2685/258/5318 +f 2268/257/5319 3177/256/5319 2266/3033/5319 +f 1089/979/5320 2902/978/5320 2271/3036/5320 +f 705/3037/5321 2271/3036/5321 3178/247/5321 +f 705/3037/5322 2269/246/5322 2751/253/5322 +f 705/3037/5323 938/2828/5323 2483/980/5323 +f 1501/2420/5324 2574/989/5324 1092/2400/5324 +f 1092/2400/5325 2905/1000/5325 2270/3038/5325 +f 706/3039/5326 2270/3038/5326 3178/247/5326 +f 706/3039/5327 2271/3036/5327 2902/978/5327 +f 707/3040/5328 2270/3038/5328 2905/1000/5328 +f 1504/999/5329 2526/998/5329 1283/2091/5329 +f 707/3040/5330 1283/2091/5330 2684/249/5330 +f 2272/248/5331 3178/247/5331 2270/3038/5331 +f 708/3041/5332 1093/1006/5332 2906/1005/5332 +f 2275/3042/5333 3179/238/5333 2273/237/5333 +f 708/3041/5334 2273/237/5334 2793/244/5334 +f 980/2100/5335 2525/1007/5335 1093/1006/5335 +f 709/3043/5336 1505/2397/5336 2575/1016/5336 +f 1096/2378/5337 2909/1027/5337 2274/3044/5337 +f 709/3043/5338 2274/3044/5338 3179/238/5338 +f 2275/3042/5339 2906/1005/5339 1505/2397/5339 +f 710/3045/5340 2274/3044/5340 2909/1027/5340 +f 1508/1026/5341 2499/1025/5341 1256/2908/5341 +f 710/3045/5342 1256/2908/5342 2657/240/5342 +f 2276/239/5343 3179/238/5343 2274/3044/5343 +f 711/3046/5344 1097/1033/5344 2910/1032/5344 +f 2279/3047/5345 3180/229/5345 2277/228/5345 +f 711/3046/5346 2277/228/5346 2792/235/5346 +f 979/2322/5347 2524/1034/5347 1097/1033/5347 +f 712/3048/5348 1509/2375/5348 2576/1043/5348 +f 1100/2350/5349 2913/1054/5349 2278/3049/5349 +f 712/3048/5350 2278/3049/5350 3180/229/5350 +f 2279/3047/5351 2910/1032/5351 1509/2375/5351 +f 713/3050/5352 2278/3049/5352 2913/1054/5352 +f 1512/1053/5353 2523/1052/5353 1280/2394/5353 +f 713/3050/5354 1280/2394/5354 2681/231/5354 +f 2280/230/5355 3180/229/5355 2278/3049/5355 +f 714/3051/5356 1101/1060/5356 2914/1059/5356 +f 2283/3052/5357 3181/220/5357 2281/219/5357 +f 714/3051/5358 2281/219/5358 2603/226/5358 +f 1202/3053/5359 2445/1061/5359 1101/1060/5359 +f 715/3054/5360 1513/2347/5360 2577/1070/5360 +f 1104/2319/5361 2917/1081/5361 2282/3055/5361 +f 715/3054/5362 2282/3055/5362 3181/220/5362 +f 2283/3052/5363 2914/1059/5363 1513/2347/5363 +f 716/3056/5364 2282/3055/5364 2917/1081/5364 +f 1516/1080/5365 2522/1079/5365 1279/2116/5365 +f 716/3056/5366 1279/2116/5366 2680/222/5366 +f 2284/221/5367 3181/220/5367 2282/3055/5367 +f 717/3057/5368 1105/1087/5368 2918/1086/5368 +f 2287/3058/5369 3182/211/5369 2285/210/5369 +f 717/3057/5370 2285/210/5370 2789/217/5370 +f 976/2125/5371 2521/1088/5371 1105/1087/5371 +f 718/3059/5372 1517/2316/5372 2578/1097/5372 +f 1108/2298/5373 2921/1108/5373 2286/3060/5373 +f 718/3059/5374 2286/3060/5374 3182/211/5374 +f 2287/3058/5375 2918/1086/5375 1517/2316/5375 +f 719/3061/5376 2286/3060/5376 2921/1108/5376 +f 1520/1107/5377 2500/1106/5377 1257/1943/5377 +f 719/3061/5378 1257/1943/5378 2658/213/5378 +f 2288/212/5379 3182/211/5379 2286/3060/5379 +f 720/3062/5380 1109/1114/5380 2922/1113/5380 +f 2291/3063/5381 3183/202/5381 2289/201/5381 +f 720/3062/5382 2289/201/5382 2788/208/5382 +f 975/2240/5383 2520/1115/5383 1109/1114/5383 +f 721/3064/5384 1521/2295/5384 2579/1124/5384 +f 1112/2268/5385 2925/1135/5385 2290/3065/5385 +f 721/3064/5386 2290/3065/5386 3183/202/5386 +f 2291/3063/5387 2922/1113/5387 1521/2295/5387 +f 722/3066/5388 2290/3065/5388 2925/1135/5388 +f 1524/1134/5389 2519/1133/5389 1276/2313/5389 +f 722/3066/5390 1276/2313/5390 2677/204/5390 +f 2292/203/5391 3183/202/5391 2290/3065/5391 +f 723/3067/5392 1113/1141/5392 2926/1140/5392 +f 2295/3068/5393 3184/193/5393 2293/192/5393 +f 723/3067/5394 2293/192/5394 2754/199/5394 +f 941/2353/5395 2486/1142/5395 1113/1141/5395 +f 724/3069/5396 1525/2265/5396 2580/1151/5396 +f 1116/2237/5397 2929/1162/5397 2294/3070/5397 +f 724/3069/5398 2294/3070/5398 3184/193/5398 +f 2295/3068/5399 2926/1140/5399 1525/2265/5399 +f 725/3071/5400 2294/3070/5400 2929/1162/5400 +f 1528/1161/5401 2518/1160/5401 1275/2140/5401 +f 725/3071/5402 1275/2140/5402 2676/195/5402 +f 2296/194/5403 3184/193/5403 2294/3070/5403 +f 1117/1168/5404 2930/1167/5404 2299/3072/5404 +f 726/3073/5405 2299/3072/5405 3185/183/5405 +f 2297/182/5406 2781/190/5406 968/2170/5406 +f 726/3073/5407 968/2170/5407 2513/1169/5407 +f 1529/2234/5408 2581/1178/5408 1120/2215/5408 +f 727/3074/5409 1120/2215/5409 2933/1189/5409 +f 2298/3075/5410 3185/183/5410 2299/3072/5410 +f 727/3074/5411 2299/3072/5411 2930/1167/5411 +f 2298/3075/5412 2933/1189/5412 1532/1188/5412 +f 728/3076/5413 1532/1188/5413 2503/1187/5413 +f 1260/3077/5414 2661/186/5414 2300/184/5414 +f 728/3076/5415 2300/184/5415 3185/183/5415 +f 1121/1195/5416 2934/1194/5416 2303/3078/5416 +f 729/3079/5417 2303/3078/5417 3186/174/5417 +f 2301/173/5418 2773/181/5418 960/2217/5418 +f 729/3079/5419 960/2217/5419 2505/1196/5419 +f 1533/2212/5420 2582/1205/5420 1124/2192/5420 +f 730/3080/5421 1124/2192/5421 2937/1216/5421 +f 2302/3081/5422 3186/174/5422 2303/3078/5422 +f 730/3080/5423 2303/3078/5423 2934/1194/5423 +f 2302/3081/5424 2937/1216/5424 1536/1215/5424 +f 731/3082/5425 1536/1215/5425 2489/1214/5425 +f 1246/3083/5426 2647/177/5426 2304/175/5426 +f 731/3082/5427 2304/175/5427 3186/174/5427 +f 1125/1222/5428 2938/1221/5428 2307/3084/5428 +f 732/3085/5429 2307/3084/5429 3187/165/5429 +f 2305/164/5430 2624/172/5430 1223/3086/5430 +f 732/3085/5431 1223/3086/5431 2466/1223/5431 +f 1537/2189/5432 2583/1232/5432 1128/2168/5432 +f 733/3087/5433 1128/2168/5433 2941/1243/5433 +f 2306/3088/5434 3187/165/5434 2307/3084/5434 +f 733/3087/5435 2307/3084/5435 2938/1221/5435 +f 2306/3088/5436 2941/1243/5436 1540/1242/5436 +f 734/3089/5437 1540/1242/5437 2488/1241/5437 +f 1245/3090/5438 2646/168/5438 2308/166/5438 +f 734/3089/5439 2308/166/5439 3187/165/5439 +f 1129/1249/5440 2942/1248/5440 2311/3091/5440 +f 735/3092/5441 2311/3091/5441 3188/156/5441 +f 2309/155/5442 2770/163/5442 957/2916/5442 +f 735/3092/5443 957/2916/5443 2502/1250/5443 +f 1541/2165/5444 2584/1259/5444 1132/2146/5444 +f 736/3093/5445 1132/2146/5445 2945/1270/5445 +f 2310/3094/5446 3188/156/5446 2311/3091/5446 +f 736/3093/5447 2311/3091/5447 2942/1248/5447 +f 2310/3094/5448 2945/1270/5448 1544/1269/5448 +f 737/3095/5449 1544/1269/5449 2472/1268/5449 +f 1229/1870/5450 2630/159/5450 2312/157/5450 +f 737/3095/5451 2312/157/5451 3188/156/5451 +f 738/3096/5452 1133/1276/5452 2946/1275/5452 +f 2315/3097/5453 3189/148/5453 2313/147/5453 +f 738/3096/5454 2313/147/5454 2769/154/5454 +f 956/2381/5455 2501/1277/5455 1133/1276/5455 +f 739/3098/5456 1545/2143/5456 2585/1286/5456 +f 1136/2122/5457 2949/1297/5457 2314/3099/5457 +f 739/3098/5458 2314/3099/5458 3189/148/5458 +f 2315/3097/5459 2946/1275/5459 1545/2143/5459 +f 740/3100/5460 2314/3099/5460 2949/1297/5460 +f 1548/1296/5461 2485/1295/5461 1242/2016/5461 +f 740/3100/5462 1242/2016/5462 2643/150/5462 +f 2316/149/5463 3189/148/5463 2314/3099/5463 +f 741/3101/5464 1137/1303/5464 2950/1302/5464 +f 2319/3102/5465 3190/139/5465 2317/138/5465 +f 741/3101/5466 2317/138/5466 2628/145/5466 +f 1227/3103/5467 2470/1304/5467 1137/1303/5467 +f 742/3104/5468 1549/2119/5468 2586/1313/5468 +f 1140/2097/5469 2953/1324/5469 2318/3105/5469 +f 742/3104/5470 2318/3105/5470 3190/139/5470 +f 2319/3102/5471 2950/1302/5471 1549/2119/5471 +f 743/3106/5472 2318/3105/5472 2953/1324/5472 +f 1552/1323/5473 2484/1322/5473 1241/2886/5473 +f 743/3106/5474 1241/2886/5474 2642/141/5474 +f 2320/140/5475 3190/139/5475 2318/3105/5475 +f 744/3107/5476 1141/1330/5476 2954/1329/5476 +f 2323/3108/5477 3191/130/5477 2321/129/5477 +f 744/3107/5478 2321/129/5478 2766/136/5478 +f 953/2851/5479 2498/1331/5479 1141/1330/5479 +f 745/3109/5480 1553/2094/5480 2587/1340/5480 +f 1144/2072/5481 2957/1351/5481 2322/3110/5481 +f 745/3109/5482 2322/3110/5482 3191/130/5482 +f 2323/3108/5483 2954/1329/5483 1553/2094/5483 +f 746/3111/5484 2322/3110/5484 2957/1351/5484 +f 1556/1350/5485 2473/1349/5485 1230/2673/5485 +f 746/3111/5486 1230/2673/5486 2631/132/5486 +f 2324/131/5487 3191/130/5487 2322/3110/5487 +f 1145/1357/5488 2958/1356/5488 2327/3112/5488 +f 747/3113/5489 2327/3112/5489 3192/120/5489 +f 2325/119/5490 2765/127/5490 952/2636/5490 +f 747/3113/5491 952/2636/5491 2497/1358/5491 +f 1557/2069/5492 2588/1367/5492 1148/2047/5492 +f 748/3114/5493 1148/2047/5493 2961/1378/5493 +f 2326/3115/5494 3192/120/5494 2327/3112/5494 +f 748/3114/5495 2327/3112/5495 2958/1356/5495 +f 2326/3115/5496 2961/1378/5496 1560/1377/5496 +f 749/3116/5497 1560/1377/5497 2481/1376/5497 +f 1238/2416/5498 2639/123/5498 2328/121/5498 +f 749/3116/5499 2328/121/5499 3192/120/5499 +f 1149/1384/5500 2962/1383/5500 2331/3117/5500 +f 750/3118/5501 2331/3117/5501 3193/111/5501 +f 750/3118/5502 2329/110/5502 2720/118/5502 +f 907/2301/5503 2452/1385/5503 1149/1384/5503 +f 1561/2044/5504 2589/1394/5504 1152/2022/5504 +f 751/3119/5505 1152/2022/5505 2965/1405/5505 +f 2330/3120/5506 3193/111/5506 2331/3117/5506 +f 751/3119/5507 2331/3117/5507 2962/1383/5507 +f 2330/3120/5508 2965/1405/5508 1564/1404/5508 +f 752/3121/5509 1564/1404/5509 2480/1403/5509 +f 1237/2819/5510 2638/114/5510 2332/112/5510 +f 752/3121/5511 2332/112/5511 3193/111/5511 +f 753/3122/5512 1153/1411/5512 2966/1410/5512 +f 2335/3123/5513 3194/102/5513 2333/101/5513 +f 2333/101/5514 2755/109/5514 942/2895/5514 +f 942/2895/5515 2487/1412/5515 1153/1411/5515 +f 754/3124/5516 1565/2019/5516 2590/1421/5516 +f 754/3124/5517 1156/1998/5517 2969/1432/5517 +f 754/3124/5518 2334/3125/5518 3194/102/5518 +f 2335/3123/5519 2966/1410/5519 1565/2019/5519 +f 2334/3125/5520 2969/1432/5520 1568/1431/5520 +f 755/3126/5521 1568/1431/5521 2514/1430/5521 +f 1271/2161/5522 2672/105/5522 2336/103/5522 +f 755/3126/5523 2336/103/5523 3194/102/5523 +f 756/3127/5524 1157/1438/5524 2970/1437/5524 +f 2339/3128/5525 3195/94/5525 2337/93/5525 +f 756/3127/5526 2337/93/5526 2762/100/5526 +f 949/2785/5527 2494/1439/5527 1157/1438/5527 +f 757/3129/5528 1569/1995/5528 2591/1448/5528 +f 1160/1973/5529 2973/1459/5529 2338/3130/5529 +f 757/3129/5530 2338/3130/5530 3195/94/5530 +f 2339/3128/5531 2970/1437/5531 1569/1995/5531 +f 758/3131/5532 2338/3130/5532 2973/1459/5532 +f 1572/1458/5533 2477/1457/5533 1234/3132/5533 +f 758/3131/5534 1234/3132/5534 2635/96/5534 +f 2340/95/5535 3195/94/5535 2338/3130/5535 +f 1161/1465/5536 2974/1464/5536 2343/3133/5536 +f 759/3134/5537 2343/3133/5537 3196/84/5537 +f 2341/83/5538 2719/91/5538 906/1808/5538 +f 759/3134/5539 906/1808/5539 2451/1466/5539 +f 760/3135/5540 1573/1970/5540 2592/1475/5540 +f 1164/1949/5541 2977/1486/5541 2342/3136/5541 +f 760/3135/5542 2342/3136/5542 3196/84/5542 +f 2343/3133/5543 2974/1464/5543 1573/1970/5543 +f 761/3137/5544 2342/3136/5544 2977/1486/5544 +f 1576/1485/5545 2476/1484/5545 1233/3138/5545 +f 761/3137/5546 1233/3138/5546 2634/87/5546 +f 2344/85/5547 3196/84/5547 2342/3136/5547 +f 762/3139/5548 1165/1492/5548 2978/1491/5548 +f 762/3139/5549 2347/3140/5549 3197/75/5549 +f 2345/74/5550 2784/82/5550 971/2001/5550 +f 971/2001/5551 2516/1493/5551 1165/1492/5551 +f 763/3141/5552 1577/1946/5552 2593/1502/5552 +f 763/3141/5553 1168/1925/5553 2981/1513/5553 +f 2346/3142/5554 3197/75/5554 2347/3140/5554 +f 2347/3140/5555 2978/1491/5555 1577/1946/5555 +f 2346/3142/5556 2981/1513/5556 1580/1512/5556 +f 764/3143/5557 1580/1512/5557 2515/1511/5557 +f 1272/1799/5558 2673/78/5558 2348/76/5558 +f 764/3143/5559 2348/76/5559 3197/75/5559 +f 1169/1519/5560 2982/1518/5560 2351/3144/5560 +f 2351/3144/5561 3198/66/5561 2349/65/5561 +f 2349/65/5562 2743/73/5562 930/1783/5562 +f 765/3145/5563 930/1783/5563 2475/1520/5563 +f 766/3146/5564 1581/1922/5564 2594/1529/5564 +f 1172/1901/5565 2985/1540/5565 2350/3147/5565 +f 766/3146/5566 2350/3147/5566 3198/66/5566 +f 2351/3144/5567 2982/1518/5567 1581/1922/5567 +f 767/3148/5568 2350/3147/5568 2985/1540/5568 +f 1584/1539/5569 2461/1538/5569 1218/2753/5569 +f 767/3148/5570 1218/2753/5570 2619/69/5570 +f 2352/67/5571 3198/66/5571 2350/3147/5571 +f 1173/1546/5572 2986/1545/5572 2355/3149/5572 +f 768/3150/5573 2355/3149/5573 3199/57/5573 +f 2353/56/5574 2616/64/5574 1215/3151/5574 +f 768/3150/5575 1215/3151/5575 2458/1547/5575 +f 1585/1898/5576 2595/1556/5576 1176/1877/5576 +f 769/3152/5577 1176/1877/5577 2989/1567/5577 +f 2354/3153/5578 3199/57/5578 2355/3149/5578 +f 769/3152/5579 2355/3149/5579 2986/1545/5579 +f 2354/3153/5580 2989/1567/5580 1588/1566/5580 +f 770/3154/5581 1588/1566/5581 2460/1565/5581 +f 1217/1774/5582 2618/60/5582 2356/58/5582 +f 770/3154/5583 2356/58/5583 3199/57/5583 +f 1177/1573/5584 2990/1572/5584 2359/3155/5584 +f 771/3156/5585 2359/3155/5585 3200/48/5585 +f 2357/47/5586 2758/55/5586 945/1734/5586 +f 771/3156/5587 945/1734/5587 2490/1574/5587 +f 1589/1874/5588 2596/1583/5588 1180/1854/5588 +f 772/3157/5589 1180/1854/5589 2993/1594/5589 +f 2358/3158/5590 3200/48/5590 2359/3155/5590 +f 772/3157/5591 2359/3155/5591 2990/1572/5591 +f 2358/3158/5592 2993/1594/5592 1592/1593/5592 +f 773/3159/5593 1592/1593/5593 2506/1592/5593 +f 1263/2208/5594 2664/51/5594 2360/49/5594 +f 773/3159/5595 2360/49/5595 3200/48/5595 +f 1181/1600/5596 2994/1599/5596 2363/3160/5596 +f 774/3161/5597 2363/3160/5597 3201/39/5597 +f 2361/38/5598 2776/46/5598 963/1856/5598 +f 774/3161/5599 963/1856/5599 2508/1601/5599 +f 1593/1851/5600 2597/1610/5600 1184/1831/5600 +f 775/3162/5601 1184/1831/5601 2997/1621/5601 +f 2362/3163/5602 3201/39/5602 2363/3160/5602 +f 775/3162/5603 2363/3160/5603 2994/1599/5603 +f 2362/3163/5604 2997/1621/5604 1596/1620/5604 +f 776/3164/5605 1596/1620/5605 2507/1619/5605 +f 1264/1824/5606 2665/42/5606 2364/40/5606 +f 776/3164/5607 2364/40/5607 3201/39/5607 +f 1185/1627/5608 2998/1626/5608 2367/3165/5608 +f 777/3166/5609 2367/3165/5609 3202/30/5609 +f 2365/29/5610 2777/37/5610 964/2194/5610 +f 777/3166/5611 964/2194/5611 2509/1628/5611 +f 1597/1828/5612 2598/1637/5612 1188/1806/5612 +f 778/3167/5613 1188/1806/5613 3001/1648/5613 +f 2366/3168/5614 3202/30/5614 2367/3165/5614 +f 778/3167/5615 2367/3165/5615 2998/1626/5615 +f 2366/3168/5616 3001/1648/5616 1600/1647/5616 +f 779/3169/5617 1600/1647/5617 2504/1646/5617 +f 1261/3170/5618 2662/33/5618 2368/31/5618 +f 779/3169/5619 2368/31/5619 3202/30/5619 +f 1189/1654/5620 3002/1653/5620 2371/3171/5620 +f 780/3172/5621 2371/3171/5621 3203/21/5621 +f 2369/20/5622 2785/28/5622 972/2148/5622 +f 780/3172/5623 972/2148/5623 2517/1655/5623 +f 1601/1803/5624 2599/1664/5624 1192/1781/5624 +f 781/3173/5625 1192/1781/5625 3005/1675/5625 +f 2370/3174/5626 3203/21/5626 2371/3171/5626 +f 781/3173/5627 2371/3171/5627 3002/1653/5627 +f 2370/3174/5628 3005/1675/5628 1604/1674/5628 +f 782/3175/5629 1604/1674/5629 2491/1673/5629 +f 1248/1847/5630 2649/24/5630 2372/22/5630 +f 782/3175/5631 2372/22/5631 3203/21/5631 +f 1193/1681/5632 3006/1680/5632 2375/3176/5632 +f 783/3177/5633 2375/3176/5633 3204/12/5633 +f 2373/11/5634 2606/19/5634 1205/3178/5634 +f 783/3177/5635 1205/3178/5635 2448/1682/5635 +f 1605/1778/5636 2600/1691/5636 1196/1757/5636 +f 784/3179/5637 1196/1757/5637 3009/1702/5637 +f 2374/3180/5638 3204/12/5638 2375/3176/5638 +f 784/3179/5639 2375/3176/5639 3006/1680/5639 +f 2374/3180/5640 3009/1702/5640 1608/1701/5640 +f 785/3181/5641 1608/1701/5641 2510/1700/5641 +f 1267/2185/5642 2668/15/5642 2376/13/5642 +f 785/3181/5643 2376/13/5643 3204/12/5643 +f 1197/1708/5644 3010/1707/5644 2379/3182/5644 +f 786/3183/5645 2379/3182/5645 3205/3/5645 +f 2377/2/5646 2780/10/5646 967/1759/5646 +f 786/3183/5647 967/1759/5647 2512/1709/5647 +f 1609/1754/5648 2601/1718/5648 1200/1732/5648 +f 787/3184/5649 1200/1732/5649 3013/1729/5649 +f 2378/3185/5650 3205/3/5650 2379/3182/5650 +f 787/3184/5651 2379/3182/5651 3010/1707/5651 +f 2378/3185/5652 3013/1729/5652 1612/1728/5652 +f 788/3186/5653 1612/1728/5653 2511/1727/5653 +f 1268/2230/5654 2669/6/5654 2380/4/5654 +f 788/3186/5655 2380/4/5655 3205/3/5655 +f 21/5/5656 2377/2/5656 2380/4/5656 +f 856/7/5657 21/5/5657 2669/6/5657 +f 21/5/5658 856/7/5658 1379/9/5658 +f 2377/2/5659 21/5/5659 2780/10/5659 +f 22/14/5660 2373/11/5660 2376/13/5660 +f 855/16/5661 22/14/5661 2668/15/5661 +f 22/14/5662 855/16/5662 793/18/5662 +f 2373/11/5663 22/14/5663 2606/19/5663 +f 23/23/5664 2369/20/5664 2372/22/5664 +f 836/25/5665 23/23/5665 2649/24/5665 +f 23/23/5666 836/25/5666 1384/27/5666 +f 2369/20/5667 23/23/5667 2785/28/5667 +f 24/32/5668 2365/29/5668 2368/31/5668 +f 849/34/5669 24/32/5669 2662/33/5669 +f 24/32/5670 849/34/5670 1376/36/5670 +f 2365/29/5671 24/32/5671 2777/37/5671 +f 25/41/5672 2361/38/5672 2364/40/5672 +f 852/43/5673 25/41/5673 2665/42/5673 +f 25/41/5674 852/43/5674 1375/45/5674 +f 2361/38/5675 25/41/5675 2776/46/5675 +f 26/50/5676 2357/47/5676 2360/49/5676 +f 851/52/5677 26/50/5677 2664/51/5677 +f 26/50/5678 851/52/5678 1357/54/5678 +f 2357/47/5679 26/50/5679 2758/55/5679 +f 27/59/5680 2353/56/5680 2356/58/5680 +f 805/61/5681 27/59/5681 2618/60/5681 +f 27/59/5682 805/61/5682 803/63/5682 +f 2353/56/5683 27/59/5683 2616/64/5683 +f 28/68/2612 2349/65/2612 2352/67/2612 +f 806/70/2613 28/68/2613 2619/69/2613 +f 28/68/2614 806/70/2614 1342/72/2614 +f 2349/65/5684 28/68/5684 2743/73/5684 +f 29/77/2616 2345/74/2616 2348/76/2616 +f 860/79/5685 29/77/5685 2673/78/5685 +f 29/77/5686 860/79/5686 1383/81/5686 +f 2345/74/5687 29/77/5687 2784/82/5687 +f 30/86/2620 2341/83/2620 2344/85/2620 +f 821/88/2621 30/86/2621 2634/87/2621 +f 30/86/5688 821/88/5688 1318/90/5688 +f 2341/83/5689 30/86/5689 2719/91/5689 +f 2340/95/5690 31/92/5690 3195/94/5690 +f 31/92/5691 2340/95/5691 822/97/5691 +f 1361/99/5692 31/92/5692 2406/98/5692 +f 31/92/5693 1361/99/5693 2337/93/5693 +f 32/104/2628 2333/101/2628 2336/103/2628 +f 859/106/5694 32/104/5694 2672/105/5694 +f 32/104/5695 859/106/5695 1354/108/5695 +f 2333/101/2631 32/104/2631 2755/109/2631 +f 33/113/2632 2329/110/2632 2332/112/2632 +f 825/115/2633 33/113/2633 2638/114/2633 +f 1319/117/2634 33/113/2634 2404/116/2634 +f 33/113/5696 1319/117/5696 2329/110/5696 +f 34/122/5697 2325/119/5697 2328/121/5697 +f 826/124/5698 34/122/5698 2639/123/5698 +f 34/122/5699 826/124/5699 1364/126/5699 +f 2325/119/5700 34/122/5700 2765/127/5700 +f 2324/131/5701 35/128/5701 3191/130/5701 +f 35/128/5702 2324/131/5702 818/133/5702 +f 1365/135/5703 35/128/5703 2403/134/5703 +f 35/128/5704 1365/135/5704 2321/129/5704 +f 2320/140/5705 36/137/5705 3190/139/5705 +f 36/137/5706 2320/140/5706 829/142/5706 +f 815/144/5707 36/137/5707 2400/143/5707 +f 36/137/5708 815/144/5708 2317/138/5708 +f 2316/149/5709 37/146/5709 3189/148/5709 +f 37/146/5710 2316/149/5710 830/151/5710 +f 1368/153/5711 37/146/5711 2408/152/5711 +f 37/146/5712 1368/153/5712 2313/147/5712 +f 38/158/5713 2309/155/5713 2312/157/5713 +f 817/160/5714 38/158/5714 2630/159/5714 +f 38/158/5715 817/160/5715 1369/162/5715 +f 2309/155/5716 38/158/5716 2770/163/5716 +f 39/167/5717 2305/164/5717 2308/166/5717 +f 833/169/5718 39/167/5718 2646/168/5718 +f 811/171/5719 39/167/5719 2396/170/5719 +f 2305/164/5720 39/167/5720 2624/172/5720 +f 40/176/5721 2301/173/5721 2304/175/5721 +f 834/178/5722 40/176/5722 2647/177/5722 +f 40/176/5723 834/178/5723 1372/180/5723 +f 2301/173/5724 40/176/5724 2773/181/5724 +f 41/185/5725 2297/182/5725 2300/184/5725 +f 848/187/5726 41/185/5726 2661/186/5726 +f 41/185/5727 848/187/5727 1380/189/5727 +f 2297/182/5728 41/185/5728 2781/190/5728 +f 2296/194/5729 42/191/5729 3184/193/5729 +f 42/191/5730 2296/194/5730 863/196/5730 +f 1353/198/5731 42/191/5731 2427/197/5731 +f 42/191/5732 1353/198/5732 2293/192/5732 +f 2292/203/5733 43/200/5733 3183/202/5733 +f 43/200/5734 2292/203/5734 864/205/5734 +f 1387/207/5735 43/200/5735 2435/206/5735 +f 43/200/5736 1387/207/5736 2289/201/5736 +f 2288/212/5737 44/209/5737 3182/211/5737 +f 44/209/5738 2288/212/5738 845/214/5738 +f 1388/216/5739 44/209/5739 2426/215/5739 +f 44/209/5740 1388/216/5740 2285/210/5740 +f 2284/221/5741 45/218/5741 3181/220/5741 +f 45/218/5742 2284/221/5742 867/223/5742 +f 790/225/5743 45/218/5743 2414/224/5743 +f 45/218/5744 790/225/5744 2281/219/5744 +f 2280/230/5745 46/227/5745 3180/229/5745 +f 46/227/5746 2280/230/5746 868/232/5746 +f 1391/234/5747 46/227/5747 2436/233/5747 +f 46/227/5748 1391/234/5748 2277/228/5748 +f 2276/239/5749 47/236/5749 3179/238/5749 +f 47/236/5750 2276/239/5750 844/241/5750 +f 1392/243/5751 47/236/5751 2425/242/5751 +f 47/236/5752 1392/243/5752 2273/237/5752 +f 2272/248/2692 48/245/2692 3178/247/2692 +f 48/245/5753 2272/248/5753 871/250/5753 +f 1350/252/5754 48/245/5754 2424/251/5754 +f 48/245/5755 1350/252/5755 2269/246/5755 +f 2268/257/5756 49/254/5756 3177/256/5756 +f 49/254/5757 2268/257/5757 872/259/5757 +f 1395/261/5758 49/254/5758 2437/260/5758 +f 49/254/5759 1395/261/5759 2265/255/5759 +f 2264/266/5760 50/263/5760 3176/265/5760 +f 50/263/5761 2264/266/5761 824/268/5761 +f 1396/270/5762 50/263/5762 2416/269/5762 +f 50/263/5763 1396/270/5763 2261/264/5763 +f 51/275/5764 2257/272/5764 2260/274/5764 +f 875/277/5765 51/275/5765 2688/276/5765 +f 51/275/5766 875/277/5766 1349/279/5766 +f 2257/272/5767 51/275/5767 2750/280/5767 +f 52/284/5768 2253/281/5768 2256/283/5768 +f 876/286/5769 52/284/5769 2689/285/5769 +f 52/284/5770 876/286/5770 1399/288/5770 +f 2253/281/5771 52/284/5771 2800/289/5771 +f 53/293/5772 2249/290/5772 2252/292/5772 +f 841/295/5773 53/293/5773 2654/294/5773 +f 53/293/5774 841/295/5774 1400/297/5774 +f 2249/290/5775 53/293/5775 2801/298/5775 +f 54/302/2716 2245/299/2716 2248/301/2716 +f 879/304/2717 54/302/2717 2692/303/2717 +f 1329/306/5776 54/302/5776 2385/305/5776 +f 54/302/5777 1329/306/5777 2245/299/5777 +f 55/311/5778 2241/308/5778 2244/310/5778 +f 880/313/5779 55/311/5779 2693/312/5779 +f 55/311/5780 880/313/5780 1403/315/5780 +f 2241/308/5781 55/311/5781 2804/316/5781 +f 56/320/5782 2237/317/5782 2240/319/5782 +f 840/322/5783 56/320/5783 2653/321/5783 +f 56/320/5784 840/322/5784 1404/324/5784 +f 2237/317/5785 56/320/5785 2805/325/5785 +f 2236/329/5786 57/326/5786 3169/328/5786 +f 57/326/5787 2236/329/5787 883/331/5787 +f 1345/333/5788 57/326/5788 2420/332/5788 +f 57/326/5789 1345/333/5789 2233/327/5789 +f 2232/338/5790 58/335/5790 3168/337/5790 +f 58/335/5791 2232/338/5791 884/340/5791 +f 1407/342/5792 58/335/5792 2440/341/5792 +f 58/335/5793 1407/342/5793 2229/336/5793 +f 2228/347/5794 59/344/5794 3167/346/5794 +f 59/344/5795 2228/347/5795 838/349/5795 +f 1408/351/5796 59/344/5796 2419/350/5796 +f 59/344/5797 1408/351/5797 2225/345/5797 +f 60/356/2740 2221/353/2740 2224/355/2740 +f 887/358/2741 60/356/2741 2700/357/2741 +f 60/356/5798 887/358/5798 1330/360/5798 +f 2221/353/2743 60/356/2743 2731/361/2743 +f 2220/365/5799 61/362/5799 3165/364/5799 +f 61/362/5800 2220/365/5800 888/367/5800 +f 1411/369/5801 61/362/5801 2441/368/5801 +f 61/362/5802 1411/369/5802 2217/363/5802 +f 2216/374/5803 62/371/5803 3164/373/5803 +f 62/371/5804 2216/374/5804 837/376/5804 +f 1412/378/5805 62/371/5805 2418/377/5805 +f 62/371/5806 1412/378/5806 2213/372/5806 +f 63/383/2752 2209/380/2752 2212/382/2752 +f 891/385/2753 63/383/2753 2704/384/2753 +f 63/383/2754 891/385/2754 1341/387/2754 +f 2209/380/2755 63/383/2755 2742/388/2755 +f 2208/392/2756 64/389/2756 3162/391/2756 +f 64/389/5807 2208/392/5807 892/394/5807 +f 1415/396/5808 64/389/5808 2442/395/5808 +f 64/389/5809 1415/396/5809 2205/390/5809 +f 2204/401/5810 65/398/5810 3161/400/5810 +f 65/398/5811 2204/401/5811 798/403/5811 +f 1416/405/5812 65/398/5812 2386/404/5812 +f 65/398/5813 1416/405/5813 2201/399/5813 +f 66/410/2764 2197/407/2764 2200/409/2764 +f 895/412/5814 66/410/5814 2708/411/5814 +f 66/410/5815 895/412/5815 800/414/5815 +f 2197/407/5816 66/410/5816 2613/415/5816 +f 67/419/5817 2193/416/5817 2196/418/5817 +f 896/421/5818 67/419/5818 2709/420/5818 +f 67/419/5819 896/421/5819 1419/423/5819 +f 2193/416/5820 67/419/5820 2820/424/5820 +f 68/428/5821 2189/425/5821 2192/427/5821 +f 799/430/5822 68/428/5822 2612/429/5822 +f 68/428/5823 799/430/5823 1420/432/5823 +f 2189/425/5824 68/428/5824 2821/433/5824 +f 69/437/5825 2185/434/5825 2188/436/5825 +f 1009/439/5826 69/437/5826 2822/438/5826 +f 69/437/5827 1009/439/5827 1310/441/5827 +f 2185/434/5828 69/437/5828 2711/442/5828 +f 70/446/5829 2181/443/5829 2184/445/5829 +f 1010/448/5830 70/446/5830 2823/447/5830 +f 70/446/5831 1010/448/5831 1423/450/5831 +f 2181/443/5832 70/446/5832 2824/451/5832 +f 71/455/5833 2177/452/5833 2180/454/5833 +f 909/457/5834 71/455/5834 2722/456/5834 +f 71/455/5835 909/457/5835 1424/459/5835 +f 2177/452/5836 71/455/5836 2825/460/5836 +f 2176/464/5837 72/461/5837 3154/463/5837 +f 72/461/5838 2176/464/5838 1013/466/5838 +f 1309/468/5839 72/461/5839 2552/467/5839 +f 72/461/5840 1309/468/5840 2173/462/5840 +f 2172/473/5841 73/470/5841 3153/472/5841 +f 73/470/5842 2172/473/5842 1014/475/5842 +f 1427/477/5843 73/470/5843 2555/476/5843 +f 73/470/5844 1427/477/5844 2169/471/5844 +f 74/482/5845 2165/479/5845 2168/481/5845 +f 1006/484/5846 74/482/5846 2819/483/5846 +f 74/482/5847 1006/484/5847 1428/486/5847 +f 2165/479/2799 74/482/2799 2829/487/2799 +f 2164/491/5848 75/488/5848 3151/490/5848 +f 75/488/5849 2164/491/5849 1017/493/5849 +f 910/495/5850 75/488/5850 2455/494/5850 +f 75/488/5851 910/495/5851 2161/489/5851 +f 2160/500/5852 76/497/5852 3150/499/5852 +f 76/497/5853 2160/500/5853 1018/502/5853 +f 1431/504/5854 76/497/5854 2556/503/5854 +f 76/497/5855 1431/504/5855 2157/498/5855 +f 77/509/5856 2153/506/5856 2156/508/5856 +f 1005/511/5857 77/509/5857 2818/510/5857 +f 77/509/5858 1005/511/5858 1432/513/5858 +f 2153/506/2811 77/509/2811 2833/514/2811 +f 2152/518/5859 78/515/5859 3148/517/5859 +f 78/515/5860 2152/518/5860 1021/520/5860 +f 1306/522/5861 78/515/5861 2549/521/5861 +f 78/515/5862 1306/522/5862 2149/516/5862 +f 2148/527/5863 79/524/5863 3147/526/5863 +f 79/524/5864 2148/527/5864 1022/529/5864 +f 1435/531/5865 79/524/5865 2557/530/5865 +f 79/524/5866 1435/531/5866 2145/525/5866 +f 2144/536/5867 80/533/5867 3146/535/5867 +f 80/533/5868 2144/536/5868 908/538/5868 +f 1436/540/5869 80/533/5869 2453/539/5869 +f 80/533/5870 1436/540/5870 2141/534/5870 +f 81/545/5871 2137/542/5871 2140/544/5871 +f 1025/547/5872 81/545/5872 2838/546/5872 +f 81/545/5873 1025/547/5873 1305/549/5873 +f 2137/542/5874 81/545/5874 2706/550/5874 +f 82/554/5875 2133/551/5875 2136/553/5875 +f 1026/556/5876 82/554/5876 2839/555/5876 +f 82/554/5877 1026/556/5877 1439/558/5877 +f 2133/551/5878 82/554/5878 2840/559/5878 +f 2132/563/5879 83/560/5879 3143/562/5879 +f 83/560/5880 2132/563/5880 1002/565/5880 +f 1440/567/5881 83/560/5881 2547/566/5881 +f 83/560/5882 1440/567/5882 2129/561/5882 +f 2128/572/2836 84/569/2836 3142/571/2836 +f 84/569/2837 2128/572/2837 1029/574/2837 +f 1231/576/2838 84/569/2838 2474/575/2838 +f 84/569/5883 1231/576/5883 2125/570/5883 +f 85/581/5884 2121/578/5884 2124/580/5884 +f 1030/583/5885 85/581/5885 2843/582/5885 +f 85/581/5886 1030/583/5886 1443/585/5886 +f 2121/578/5887 85/581/5887 2844/586/5887 +f 2120/590/2844 86/587/2844 3140/589/2844 +f 86/587/5888 2120/590/5888 1001/592/5888 +f 1444/594/5889 86/587/5889 2546/593/5889 +f 86/587/5890 1444/594/5890 2117/588/5890 +f 2116/599/5891 87/596/5891 3139/598/5891 +f 87/596/5892 2116/599/5892 1033/601/5892 +f 1302/603/5893 87/596/5893 2545/602/5893 +f 87/596/5894 1302/603/5894 2113/597/5894 +f 2112/608/5895 88/605/5895 3138/607/5895 +f 88/605/5896 2112/608/5896 1034/610/5896 +f 1447/612/5897 88/605/5897 2560/611/5897 +f 88/605/5898 1447/612/5898 2109/606/5898 +f 2108/617/5899 89/614/5899 3137/616/5899 +f 89/614/5900 2108/617/5900 947/619/5900 +f 1448/621/5901 89/614/5901 2492/620/5901 +f 89/614/5902 1448/621/5902 2105/615/5902 +f 2104/626/5903 90/623/5903 3136/625/5903 +f 90/623/5904 2104/626/5904 1037/628/5904 +f 1301/630/5905 90/623/5905 2544/629/5905 +f 90/623/5906 1301/630/5906 2101/624/5906 +f 2100/635/5907 91/632/5907 3135/634/5907 +f 91/632/5908 2100/635/5908 1038/637/5908 +f 1451/639/5909 91/632/5909 2561/638/5909 +f 91/632/5910 1451/639/5910 2097/633/5910 +f 2096/644/5911 92/641/5911 3134/643/5911 +f 92/641/5912 2096/644/5912 998/646/5912 +f 1452/648/5913 92/641/5913 2543/647/5913 +f 92/641/5914 1452/648/5914 2093/642/5914 +f 93/653/2872 2089/650/2872 2092/652/2872 +f 1041/655/2873 93/653/2873 2854/654/2873 +f 93/653/5915 1041/655/5915 1220/657/5915 +f 2089/650/5916 93/653/5916 2621/658/5916 +f 2088/662/5917 94/659/5917 3132/661/5917 +f 94/659/5918 2088/662/5918 1042/664/5918 +f 1455/666/5919 94/659/5919 2562/665/5919 +f 94/659/5920 1455/666/5920 2085/660/5920 +f 2084/671/5921 95/668/5921 3131/670/5921 +f 95/668/5922 2084/671/5922 997/673/5922 +f 1456/675/5923 95/668/5923 2542/674/5923 +f 95/668/5924 1456/675/5924 2081/669/5924 +f 2080/680/5925 96/677/5925 3130/679/5925 +f 96/677/5926 2080/680/5926 1045/682/5926 +f 1298/684/5927 96/677/5927 2541/683/5927 +f 96/677/5928 1298/684/5928 2077/678/5928 +f 2076/689/5929 97/686/5929 3129/688/5929 +f 97/686/5930 2076/689/5930 1046/691/5930 +f 1459/693/5931 97/686/5931 2563/692/5931 +f 97/686/5932 1459/693/5932 2073/687/5932 +f 2072/698/5933 98/695/5933 3128/697/5933 +f 98/695/5934 2072/698/5934 948/700/5934 +f 1460/702/5935 98/695/5935 2493/701/5935 +f 98/695/5936 1460/702/5936 2069/696/5936 +f 2068/707/5937 99/704/5937 3127/706/5937 +f 99/704/5938 2068/707/5938 1049/709/5938 +f 1297/711/5939 99/704/5939 2540/710/5939 +f 99/704/5940 1297/711/5940 2065/705/5940 +f 2064/716/5941 100/713/5941 3126/715/5941 +f 100/713/5942 2064/716/5942 1050/718/5942 +f 1463/720/5943 100/713/5943 2564/719/5943 +f 100/713/5944 1463/720/5944 2061/714/5944 +f 2060/725/5945 101/722/5945 3125/724/5945 +f 101/722/5946 2060/725/5946 994/727/5946 +f 1464/729/5947 101/722/5947 2539/728/5947 +f 101/722/5948 1464/729/5948 2057/723/5948 +f 2056/734/5949 102/731/5949 3124/733/5949 +f 102/731/5950 2056/734/5950 1053/736/5950 +f 1235/738/5951 102/731/5951 2478/737/5951 +f 102/731/5952 1235/738/5952 2053/732/5952 +f 2052/743/5953 103/740/5953 3123/742/5953 +f 103/740/5954 2052/743/5954 1054/745/5954 +f 1467/747/5955 103/740/5955 2565/746/5955 +f 103/740/5956 1467/747/5956 2049/741/5956 +f 2048/752/5957 104/749/5957 3122/751/5957 +f 104/749/5958 2048/752/5958 993/754/5958 +f 1468/756/5959 104/749/5959 2538/755/5959 +f 104/749/5960 1468/756/5960 2045/750/5960 +f 105/761/5961 2041/758/5961 2044/760/5961 +f 1057/763/5962 105/761/5962 2870/762/5962 +f 105/761/5963 1057/763/5963 1294/765/5963 +f 2041/758/5964 105/761/5964 2695/766/5964 +f 106/770/5965 2037/767/5965 2040/769/5965 +f 1058/772/5966 106/770/5966 2871/771/5966 +f 106/770/5967 1058/772/5967 1471/774/5967 +f 2037/767/5968 106/770/5968 2872/775/5968 +f 107/779/5969 2033/776/5969 2036/778/5969 +f 950/781/5970 107/779/5970 2763/780/5970 +f 107/779/5971 950/781/5971 1472/783/5971 +f 2033/776/5972 107/779/5972 2873/784/5972 +f 108/788/5973 2029/785/5973 2032/787/5973 +f 1061/790/5974 108/788/5974 2874/789/5974 +f 108/788/5975 1061/790/5975 1293/792/5975 +f 2029/785/5976 108/788/5976 2694/793/5976 +f 109/797/5977 2025/794/5977 2028/796/5977 +f 1062/799/5978 109/797/5978 2875/798/5978 +f 109/797/5979 1062/799/5979 1475/801/5979 +f 2025/794/5980 109/797/5980 2876/802/5980 +f 110/806/5981 2021/803/5981 2024/805/5981 +f 990/808/5982 110/806/5982 2803/807/5982 +f 110/806/5983 990/808/5983 1476/810/5983 +f 2021/803/5984 110/806/5984 2877/811/5984 +f 111/815/2944 2017/812/2944 2020/814/2944 +f 1065/817/2945 111/815/2945 2878/816/2945 +f 1219/819/5985 111/815/5985 2462/818/5985 +f 111/815/5986 1219/819/5986 2017/812/5986 +f 112/824/5987 2013/821/5987 2016/823/5987 +f 1066/826/5988 112/824/5988 2879/825/5988 +f 112/824/5989 1066/826/5989 1479/828/5989 +f 2013/821/5990 112/824/5990 2880/829/5990 +f 113/833/5991 2009/830/5991 2012/832/5991 +f 989/835/5992 113/833/5992 2802/834/5992 +f 113/833/5993 989/835/5993 1480/837/5993 +f 2009/830/5994 113/833/5994 2881/838/5994 +f 114/842/5995 2005/839/5995 2008/841/5995 +f 1069/844/5996 114/842/5996 2882/843/5996 +f 114/842/5997 1069/844/5997 1290/846/5997 +f 2005/839/5998 114/842/5998 2691/847/5998 +f 115/851/5999 2001/848/5999 2004/850/5999 +f 1070/853/6000 115/851/6000 2883/852/6000 +f 115/851/6001 1070/853/6001 1483/855/6001 +f 2001/848/6002 115/851/6002 2884/856/6002 +f 116/860/6003 1997/857/6003 2000/859/6003 +f 951/862/6004 116/860/6004 2764/861/6004 +f 116/860/6005 951/862/6005 1484/864/6005 +f 1997/857/6006 116/860/6006 2885/865/6006 +f 117/869/6007 1993/866/6007 1996/868/6007 +f 1073/871/6008 117/869/6008 2886/870/6008 +f 117/869/6009 1073/871/6009 1289/873/6009 +f 1993/866/6010 117/869/6010 2690/874/6010 +f 118/878/6011 1989/875/6011 1992/877/6011 +f 1074/880/6012 118/878/6012 2887/879/6012 +f 118/878/6013 1074/880/6013 1487/882/6013 +f 1989/875/6014 118/878/6014 2888/883/6014 +f 119/887/6015 1985/884/6015 1988/886/6015 +f 986/889/6016 119/887/6016 2799/888/6016 +f 119/887/6017 986/889/6017 1488/891/6017 +f 1985/884/6018 119/887/6018 2889/892/6018 +f 120/896/6019 1981/893/6019 1984/895/6019 +f 1077/898/6020 120/896/6020 2890/897/6020 +f 120/896/6021 1077/898/6021 1239/900/6021 +f 1981/893/6022 120/896/6022 2640/901/6022 +f 121/905/6023 1977/902/6023 1980/904/6023 +f 1078/907/6024 121/905/6024 2891/906/6024 +f 121/905/6025 1078/907/6025 1491/909/6025 +f 1977/902/6026 121/905/6026 2892/910/6026 +f 122/914/6027 1973/911/6027 1976/913/6027 +f 985/916/6028 122/914/6028 2798/915/6028 +f 122/914/6029 985/916/6029 1492/918/6029 +f 1973/911/6030 122/914/6030 2893/919/6030 +f 1972/923/6031 123/920/6031 3103/922/6031 +f 123/920/6032 1972/923/6032 1081/925/6032 +f 1286/927/6033 123/920/6033 2529/926/6033 +f 123/920/6034 1286/927/6034 1969/921/6034 +f 1968/932/6035 124/929/6035 3102/931/6035 +f 124/929/6036 1968/932/6036 1082/934/6036 +f 1495/936/6037 124/929/6037 2572/935/6037 +f 124/929/6038 1495/936/6038 1965/930/6038 +f 1964/941/6039 125/938/6039 3101/940/6039 +f 125/938/6040 1964/941/6040 934/943/6040 +f 1496/945/6041 125/938/6041 2479/944/6041 +f 125/938/6042 1496/945/6042 1961/939/6042 +f 126/950/6043 1957/947/6043 1960/949/6043 +f 1085/952/6044 126/950/6044 2898/951/6044 +f 126/950/6045 1085/952/6045 1285/954/6045 +f 1957/947/6046 126/950/6046 2686/955/6046 +f 127/959/6047 1953/956/6047 1956/958/6047 +f 1086/961/6048 127/959/6048 2899/960/6048 +f 127/959/6049 1086/961/6049 1499/963/6049 +f 1953/956/6050 127/959/6050 2900/964/6050 +f 1952/968/6051 128/965/6051 3098/967/6051 +f 128/965/6052 1952/968/6052 982/970/6052 +f 1500/972/6053 128/965/6053 2527/971/6053 +f 128/965/6054 1500/972/6054 1949/966/6054 +f 129/977/6055 1945/974/6055 1948/976/6055 +f 1089/979/6056 129/977/6056 2902/978/6056 +f 129/977/6057 1089/979/6057 1240/981/6057 +f 1945/974/6058 129/977/6058 2641/982/6058 +f 130/986/6059 1941/983/6059 1944/985/6059 +f 1090/988/6060 130/986/6060 2903/987/6060 +f 130/986/6061 1090/988/6061 1503/990/6061 +f 1941/983/6062 130/986/6062 2904/991/6062 +f 1940/995/6063 131/992/6063 3095/994/6063 +f 131/992/6064 1940/995/6064 981/997/6064 +f 1504/999/6065 131/992/6065 2526/998/6065 +f 131/992/6066 1504/999/6066 1937/993/6066 +f 1936/1004/6067 132/1001/6067 3094/1003/6067 +f 132/1001/6068 1936/1004/6068 1093/1006/6068 +f 1282/1008/6069 132/1001/6069 2525/1007/6069 +f 132/1001/6070 1282/1008/6070 1933/1002/6070 +f 1932/1013/6071 133/1010/6071 3093/1012/6071 +f 133/1010/6072 1932/1013/6072 1094/1015/6072 +f 1507/1017/6073 133/1010/6073 2575/1016/6073 +f 133/1010/6074 1507/1017/6074 1929/1011/6074 +f 1928/1022/6075 134/1019/6075 3092/1021/6075 +f 134/1019/6076 1928/1022/6076 954/1024/6076 +f 1508/1026/6077 134/1019/6077 2499/1025/6077 +f 134/1019/6078 1508/1026/6078 1925/1020/6078 +f 1924/1031/6079 135/1028/6079 3091/1030/6079 +f 135/1028/6080 1924/1031/6080 1097/1033/6080 +f 1281/1035/6081 135/1028/6081 2524/1034/6081 +f 135/1028/6082 1281/1035/6082 1921/1029/6082 +f 1920/1040/6083 136/1037/6083 3090/1039/6083 +f 136/1037/6084 1920/1040/6084 1098/1042/6084 +f 1511/1044/6085 136/1037/6085 2576/1043/6085 +f 136/1037/6086 1511/1044/6086 1917/1038/6086 +f 1916/1049/6087 137/1046/6087 3089/1048/6087 +f 137/1046/6088 1916/1049/6088 978/1051/6088 +f 1512/1053/6089 137/1046/6089 2523/1052/6089 +f 137/1046/6090 1512/1053/6090 1913/1047/6090 +f 1912/1058/6091 138/1055/6091 3088/1057/6091 +f 138/1055/6092 1912/1058/6092 1101/1060/6092 +f 900/1062/6093 138/1055/6093 2445/1061/6093 +f 138/1055/6094 900/1062/6094 1909/1056/6094 +f 1908/1067/6095 139/1064/6095 3087/1066/6095 +f 139/1064/6096 1908/1067/6096 1102/1069/6096 +f 1515/1071/6097 139/1064/6097 2577/1070/6097 +f 139/1064/6098 1515/1071/6098 1905/1065/6098 +f 1904/1076/6099 140/1073/6099 3086/1075/6099 +f 140/1073/6100 1904/1076/6100 977/1078/6100 +f 1516/1080/6101 140/1073/6101 2522/1079/6101 +f 140/1073/6102 1516/1080/6102 1901/1074/6102 +f 1900/1085/6103 141/1082/6103 3085/1084/6103 +f 141/1082/6104 1900/1085/6104 1105/1087/6104 +f 1278/1089/6105 141/1082/6105 2521/1088/6105 +f 141/1082/6106 1278/1089/6106 1897/1083/6106 +f 1896/1094/6107 142/1091/6107 3084/1093/6107 +f 142/1091/6108 1896/1094/6108 1106/1096/6108 +f 1519/1098/6109 142/1091/6109 2578/1097/6109 +f 142/1091/6110 1519/1098/6110 1893/1092/6110 +f 1892/1103/6111 143/1100/6111 3083/1102/6111 +f 143/1100/6112 1892/1103/6112 955/1105/6112 +f 1520/1107/6113 143/1100/6113 2500/1106/6113 +f 143/1100/6114 1520/1107/6114 1889/1101/6114 +f 1888/1112/6115 144/1109/6115 3082/1111/6115 +f 144/1109/6116 1888/1112/6116 1109/1114/6116 +f 1277/1116/6117 144/1109/6117 2520/1115/6117 +f 144/1109/6118 1277/1116/6118 1885/1110/6118 +f 1884/1121/6119 145/1118/6119 3081/1120/6119 +f 145/1118/6120 1884/1121/6120 1110/1123/6120 +f 1523/1125/6121 145/1118/6121 2579/1124/6121 +f 145/1118/6122 1523/1125/6122 1881/1119/6122 +f 1880/1130/6123 146/1127/6123 3080/1129/6123 +f 146/1127/6124 1880/1130/6124 974/1132/6124 +f 1524/1134/6125 146/1127/6125 2519/1133/6125 +f 146/1127/6126 1524/1134/6126 1877/1128/6126 +f 1876/1139/6127 147/1136/6127 3079/1138/6127 +f 147/1136/6128 1876/1139/6128 1113/1141/6128 +f 1243/1143/6129 147/1136/6129 2486/1142/6129 +f 147/1136/6130 1243/1143/6130 1873/1137/6130 +f 1872/1148/6131 148/1145/6131 3078/1147/6131 +f 148/1145/6132 1872/1148/6132 1114/1150/6132 +f 1527/1152/6133 148/1145/6133 2580/1151/6133 +f 148/1145/6134 1527/1152/6134 1869/1146/6134 +f 1868/1157/6135 149/1154/6135 3077/1156/6135 +f 149/1154/6136 1868/1157/6136 973/1159/6136 +f 1528/1161/6137 149/1154/6137 2518/1160/6137 +f 149/1154/6138 1528/1161/6138 1865/1155/6138 +f 150/1166/6139 1861/1163/6139 1864/1165/6139 +f 1117/1168/6140 150/1166/6140 2930/1167/6140 +f 150/1166/6141 1117/1168/6141 1270/1170/6141 +f 1861/1163/6142 150/1166/6142 2671/1171/6142 +f 151/1175/6143 1857/1172/6143 1860/1174/6143 +f 1118/1177/6144 151/1175/6144 2931/1176/6144 +f 151/1175/6145 1118/1177/6145 1531/1179/6145 +f 1857/1172/6146 151/1175/6146 2932/1180/6146 +f 152/1184/6147 1853/1181/6147 1856/1183/6147 +f 958/1186/6148 152/1184/6148 2771/1185/6148 +f 152/1184/6149 958/1186/6149 1532/1188/6149 +f 1853/1181/6150 152/1184/6150 2933/1189/6150 +f 153/1193/6151 1849/1190/6151 1852/1192/6151 +f 1121/1195/6152 153/1193/6152 2934/1194/6152 +f 153/1193/6153 1121/1195/6153 1262/1197/6153 +f 1849/1190/6154 153/1193/6154 2663/1198/6154 +f 154/1202/6155 1845/1199/6155 1848/1201/6155 +f 1122/1204/6156 154/1202/6156 2935/1203/6156 +f 154/1202/6157 1122/1204/6157 1535/1206/6157 +f 1845/1199/6158 154/1202/6158 2936/1207/6158 +f 155/1211/6159 1841/1208/6159 1844/1210/6159 +f 944/1213/6160 155/1211/6160 2757/1212/6160 +f 155/1211/6161 944/1213/6161 1536/1215/6161 +f 1841/1208/6162 155/1211/6162 2937/1216/6162 +f 156/1220/6163 1837/1217/6163 1840/1219/6163 +f 1125/1222/6164 156/1220/6164 2938/1221/6164 +f 156/1220/6165 1125/1222/6165 921/1224/6165 +f 1837/1217/6166 156/1220/6166 2734/1225/6166 +f 157/1229/6167 1833/1226/6167 1836/1228/6167 +f 1126/1231/6168 157/1229/6168 2939/1230/6168 +f 157/1229/6169 1126/1231/6169 1539/1233/6169 +f 1833/1226/6170 157/1229/6170 2940/1234/6170 +f 158/1238/6171 1829/1235/6171 1832/1237/6171 +f 943/1240/6172 158/1238/6172 2756/1239/6172 +f 158/1238/6173 943/1240/6173 1540/1242/6173 +f 1829/1235/6174 158/1238/6174 2941/1243/6174 +f 159/1247/6175 1825/1244/6175 1828/1246/6175 +f 1129/1249/6176 159/1247/6176 2942/1248/6176 +f 159/1247/6177 1129/1249/6177 1259/1251/6177 +f 1825/1244/6178 159/1247/6178 2660/1252/6178 +f 160/1256/6179 1821/1253/6179 1824/1255/6179 +f 1130/1258/6180 160/1256/6180 2943/1257/6180 +f 160/1256/6181 1130/1258/6181 1543/1260/6181 +f 1821/1253/6182 160/1256/6182 2944/1261/6182 +f 161/1265/6183 1817/1262/6183 1820/1264/6183 +f 927/1267/6184 161/1265/6184 2740/1266/6184 +f 161/1265/6185 927/1267/6185 1544/1269/6185 +f 1817/1262/6186 161/1265/6186 2945/1270/6186 +f 1816/1274/6187 162/1271/6187 3064/1273/6187 +f 162/1271/6188 1816/1274/6188 1133/1276/6188 +f 1258/1278/6189 162/1271/6189 2501/1277/6189 +f 162/1271/6190 1258/1278/6190 1813/1272/6190 +f 1812/1283/6191 163/1280/6191 3063/1282/6191 +f 163/1280/6192 1812/1283/6192 1134/1285/6192 +f 1547/1287/6193 163/1280/6193 2585/1286/6193 +f 163/1280/6194 1547/1287/6194 1809/1281/6194 +f 1808/1292/6195 164/1289/6195 3062/1291/6195 +f 164/1289/6196 1808/1292/6196 940/1294/6196 +f 1548/1296/6197 164/1289/6197 2485/1295/6197 +f 164/1289/6198 1548/1296/6198 1805/1290/6198 +f 1804/1301/6199 165/1298/6199 3061/1300/6199 +f 165/1298/6200 1804/1301/6200 1137/1303/6200 +f 925/1305/6201 165/1298/6201 2470/1304/6201 +f 165/1298/6202 925/1305/6202 1801/1299/6202 +f 1800/1310/6203 166/1307/6203 3060/1309/6203 +f 166/1307/6204 1800/1310/6204 1138/1312/6204 +f 1551/1314/6205 166/1307/6205 2586/1313/6205 +f 166/1307/6206 1551/1314/6206 1797/1308/6206 +f 1796/1319/6207 167/1316/6207 3059/1318/6207 +f 167/1316/6208 1796/1319/6208 939/1321/6208 +f 1552/1323/6209 167/1316/6209 2484/1322/6209 +f 167/1316/6210 1552/1323/6210 1793/1317/6210 +f 1792/1328/6211 168/1325/6211 3058/1327/6211 +f 168/1325/6212 1792/1328/6212 1141/1330/6212 +f 1255/1332/6213 168/1325/6213 2498/1331/6213 +f 168/1325/6214 1255/1332/6214 1789/1326/6214 +f 1788/1337/6215 169/1334/6215 3057/1336/6215 +f 169/1334/6216 1788/1337/6216 1142/1339/6216 +f 1555/1341/6217 169/1334/6217 2587/1340/6217 +f 169/1334/6218 1555/1341/6218 1785/1335/6218 +f 1784/1346/6219 170/1343/6219 3056/1345/6219 +f 170/1343/6220 1784/1346/6220 928/1348/6220 +f 1556/1350/6221 170/1343/6221 2473/1349/6221 +f 170/1343/6222 1556/1350/6222 1781/1344/6222 +f 171/1355/6223 1777/1352/6223 1780/1354/6223 +f 1145/1357/6224 171/1355/6224 2958/1356/6224 +f 171/1355/6225 1145/1357/6225 1254/1359/6225 +f 1777/1352/6226 171/1355/6226 2655/1360/6226 +f 172/1364/6227 1773/1361/6227 1776/1363/6227 +f 1146/1366/6228 172/1364/6228 2959/1365/6228 +f 172/1364/6229 1146/1366/6229 1559/1368/6229 +f 1773/1361/6230 172/1364/6230 2960/1369/6230 +f 173/1373/6231 1769/1370/6231 1772/1372/6231 +f 936/1375/6232 173/1373/6232 2749/1374/6232 +f 173/1373/6233 936/1375/6233 1560/1377/6233 +f 1769/1370/6234 173/1373/6234 2961/1378/6234 +f 174/1382/3196 1765/1379/3196 1768/1381/3196 +f 1149/1384/3197 174/1382/3197 2962/1383/3197 +f 1209/1386/3198 174/1382/3198 2452/1385/3198 +f 174/1382/6235 1209/1386/6235 1765/1379/6235 +f 175/1391/6236 1761/1388/6236 1764/1390/6236 +f 1150/1393/6237 175/1391/6237 2963/1392/6237 +f 175/1391/6238 1150/1393/6238 1563/1395/6238 +f 1761/1388/6239 175/1391/6239 2964/1396/6239 +f 176/1400/6240 1757/1397/6240 1760/1399/6240 +f 935/1402/6241 176/1400/6241 2748/1401/6241 +f 176/1400/6242 935/1402/6242 1564/1404/6242 +f 1757/1397/6243 176/1400/6243 2965/1405/6243 +f 1756/1409/6244 177/1406/6244 3049/1408/6244 +f 177/1406/6245 1756/1409/6245 1153/1411/6245 +f 1244/1413/6246 177/1406/6246 2487/1412/6246 +f 177/1406/6247 1244/1413/6247 1753/1407/6247 +f 1752/1418/6248 178/1415/6248 3048/1417/6248 +f 178/1415/6249 1752/1418/6249 1154/1420/6249 +f 1567/1422/6250 178/1415/6250 2590/1421/6250 +f 178/1415/6251 1567/1422/6251 1749/1416/6251 +f 179/1427/6252 1745/1424/6252 1748/1426/6252 +f 969/1429/6253 179/1427/6253 2782/1428/6253 +f 179/1427/6254 969/1429/6254 1568/1431/6254 +f 1745/1424/6255 179/1427/6255 2969/1432/6255 +f 1744/1436/6256 180/1433/6256 3046/1435/6256 +f 180/1433/6257 1744/1436/6257 1157/1438/6257 +f 1251/1440/6258 180/1433/6258 2494/1439/6258 +f 180/1433/6259 1251/1440/6259 1741/1434/6259 +f 1740/1445/6260 181/1442/6260 3045/1444/6260 +f 181/1442/6261 1740/1445/6261 1158/1447/6261 +f 1571/1449/6262 181/1442/6262 2591/1448/6262 +f 181/1442/6263 1571/1449/6263 1737/1443/6263 +f 1736/1454/6264 182/1451/6264 3044/1453/6264 +f 182/1451/6265 1736/1454/6265 932/1456/6265 +f 1572/1458/6266 182/1451/6266 2477/1457/6266 +f 182/1451/6267 1572/1458/6267 1733/1452/6267 +f 183/1463/3232 1729/1460/3232 1732/1462/3232 +f 1161/1465/3233 183/1463/3233 2974/1464/3233 +f 183/1463/6268 1161/1465/6268 1208/1467/6268 +f 1729/1460/3235 183/1463/3235 2609/1468/3235 +f 1728/1472/6269 184/1469/6269 3042/1471/6269 +f 184/1469/6270 1728/1472/6270 1162/1474/6270 +f 1575/1476/6271 184/1469/6271 2592/1475/6271 +f 184/1469/6272 1575/1476/6272 1725/1470/6272 +f 1724/1481/6273 185/1478/6273 3041/1480/6273 +f 185/1478/6274 1724/1481/6274 931/1483/6274 +f 1576/1485/6275 185/1478/6275 2476/1484/6275 +f 185/1478/6276 1576/1485/6276 1721/1479/6276 +f 1720/1490/6277 186/1487/6277 3040/1489/6277 +f 186/1487/6278 1720/1490/6278 1165/1492/6278 +f 1273/1494/6279 186/1487/6279 2516/1493/6279 +f 186/1487/6280 1273/1494/6280 1717/1488/6280 +f 1716/1499/6281 187/1496/6281 3039/1498/6281 +f 187/1496/6282 1716/1499/6282 1166/1501/6282 +f 1579/1503/6283 187/1496/6283 2593/1502/6283 +f 187/1496/6284 1579/1503/6284 1713/1497/6284 +f 188/1508/3252 1709/1505/3252 1712/1507/3252 +f 970/1510/6285 188/1508/6285 2783/1509/6285 +f 188/1508/6286 970/1510/6286 1580/1512/6286 +f 1709/1505/6287 188/1508/6287 2981/1513/6287 +f 189/1517/3256 1705/1514/3256 1708/1516/3256 +f 1169/1519/3257 189/1517/3257 2982/1518/3257 +f 189/1517/3258 1169/1519/3258 1232/1521/3258 +f 1705/1514/6288 189/1517/6288 2633/1522/6288 +f 1704/1526/6289 190/1523/6289 3036/1525/6289 +f 190/1523/6290 1704/1526/6290 1170/1528/6290 +f 1583/1530/6291 190/1523/6291 2594/1529/6291 +f 190/1523/6292 1583/1530/6292 1701/1524/6292 +f 1700/1535/6293 191/1532/6293 3035/1534/6293 +f 191/1532/6294 1700/1535/6294 916/1537/6294 +f 1584/1539/6295 191/1532/6295 2461/1538/6295 +f 191/1532/6296 1584/1539/6296 1697/1533/6296 +f 192/1544/6297 1693/1541/6297 1696/1543/6297 +f 1173/1546/6298 192/1544/6298 2986/1545/6298 +f 192/1544/6299 1173/1546/6299 913/1548/6299 +f 1693/1541/6300 192/1544/6300 2726/1549/6300 +f 193/1553/6301 1689/1550/6301 1692/1552/6301 +f 1174/1555/6302 193/1553/6302 2987/1554/6302 +f 193/1553/6303 1174/1555/6303 1587/1557/6303 +f 1689/1550/6304 193/1553/6304 2988/1558/6304 +f 194/1562/6305 1685/1559/6305 1688/1561/6305 +f 915/1564/6306 194/1562/6306 2728/1563/6306 +f 194/1562/6307 915/1564/6307 1588/1566/6307 +f 1685/1559/6308 194/1562/6308 2989/1567/6308 +f 195/1571/6309 1681/1568/6309 1684/1570/6309 +f 1177/1573/6310 195/1571/6310 2990/1572/6310 +f 195/1571/6311 1177/1573/6311 1247/1575/6311 +f 1681/1568/6312 195/1571/6312 2648/1576/6312 +f 196/1580/6313 1677/1577/6313 1680/1579/6313 +f 1178/1582/6314 196/1580/6314 2991/1581/6314 +f 196/1580/6315 1178/1582/6315 1591/1584/6315 +f 1677/1577/6316 196/1580/6316 2992/1585/6316 +f 197/1589/6317 1673/1586/6317 1676/1588/6317 +f 961/1591/6318 197/1589/6318 2774/1590/6318 +f 197/1589/6319 961/1591/6319 1592/1593/6319 +f 1673/1586/6320 197/1589/6320 2993/1594/6320 +f 198/1598/6321 1669/1595/6321 1672/1597/6321 +f 1181/1600/6322 198/1598/6322 2994/1599/6322 +f 198/1598/6323 1181/1600/6323 1265/1602/6323 +f 1669/1595/6324 198/1598/6324 2666/1603/6324 +f 199/1607/6325 1665/1604/6325 1668/1606/6325 +f 1182/1609/6326 199/1607/6326 2995/1608/6326 +f 199/1607/6327 1182/1609/6327 1595/1611/6327 +f 1665/1604/6328 199/1607/6328 2996/1612/6328 +f 200/1616/6329 1661/1613/6329 1664/1615/6329 +f 962/1618/6330 200/1616/6330 2775/1617/6330 +f 200/1616/6331 962/1618/6331 1596/1620/6331 +f 1661/1613/6332 200/1616/6332 2997/1621/6332 +f 201/1625/6333 1657/1622/6333 1660/1624/6333 +f 1185/1627/6334 201/1625/6334 2998/1626/6334 +f 201/1625/6335 1185/1627/6335 1266/1629/6335 +f 1657/1622/6336 201/1625/6336 2667/1630/6336 +f 202/1634/6337 1653/1631/6337 1656/1633/6337 +f 1186/1636/6338 202/1634/6338 2999/1635/6338 +f 202/1634/6339 1186/1636/6339 1599/1638/6339 +f 1653/1631/6340 202/1634/6340 3000/1639/6340 +f 203/1643/6341 1649/1640/6341 1652/1642/6341 +f 959/1645/6342 203/1643/6342 2772/1644/6342 +f 203/1643/6343 959/1645/6343 1600/1647/6343 +f 1649/1640/6344 203/1643/6344 3001/1648/6344 +f 204/1652/6345 1645/1649/6345 1648/1651/6345 +f 1189/1654/6346 204/1652/6346 3002/1653/6346 +f 204/1652/6347 1189/1654/6347 1274/1656/6347 +f 1645/1649/6348 204/1652/6348 2675/1657/6348 +f 205/1661/6349 1641/1658/6349 1644/1660/6349 +f 1190/1663/6350 205/1661/6350 3003/1662/6350 +f 205/1661/6351 1190/1663/6351 1603/1665/6351 +f 1641/1658/6352 205/1661/6352 3004/1666/6352 +f 206/1670/6353 1637/1667/6353 1640/1669/6353 +f 946/1672/6354 206/1670/6354 2759/1671/6354 +f 206/1670/6355 946/1672/6355 1604/1674/6355 +f 1637/1667/6356 206/1670/6356 3005/1675/6356 +f 207/1679/6357 1633/1676/6357 1636/1678/6357 +f 1193/1681/6358 207/1679/6358 3006/1680/6358 +f 207/1679/6359 1193/1681/6359 903/1683/6359 +f 1633/1676/6360 207/1679/6360 2716/1684/6360 +f 208/1688/6361 1629/1685/6361 1632/1687/6361 +f 1194/1690/6362 208/1688/6362 3007/1689/6362 +f 208/1688/6363 1194/1690/6363 1607/1692/6363 +f 1629/1685/6364 208/1688/6364 3008/1693/6364 +f 209/1697/6365 1625/1694/6365 1628/1696/6365 +f 965/1699/6366 209/1697/6366 2778/1698/6366 +f 209/1697/6367 965/1699/6367 1608/1701/6367 +f 1625/1694/6368 209/1697/6368 3009/1702/6368 +f 210/1706/6369 1621/1703/6369 1624/1705/6369 +f 1197/1708/6370 210/1706/6370 3010/1707/6370 +f 210/1706/6371 1197/1708/6371 1269/1710/6371 +f 1621/1703/6372 210/1706/6372 2670/1711/6372 +f 211/1715/6373 1617/1712/6373 1620/1714/6373 +f 1198/1717/6374 211/1715/6374 3011/1716/6374 +f 211/1715/6375 1198/1717/6375 1611/1719/6375 +f 1617/1712/6376 211/1715/6376 3012/1720/6376 +f 212/1724/6377 1613/1721/6377 1616/1723/6377 +f 966/1726/6378 212/1724/6378 2779/1725/6378 +f 212/1724/6379 966/1726/6379 1612/1728/6379 +f 1613/1721/6380 212/1724/6380 3013/1729/6380 +f 213/1731/6381 1198/1717/6381 1615/1730/6381 +f 1613/1721/6382 213/1731/6382 3014/1722/6382 +f 213/1731/6383 1613/1721/6383 1200/1732/6383 +f 1198/1717/6384 213/1731/6384 2601/1718/6384 +f 214/1735/6385 1610/1733/6385 945/1734/6385 +f 1614/1736/6386 214/1735/6386 2758/55/6386 +f 214/1735/6387 1614/1736/6387 1615/1730/6387 +f 1610/1733/6388 214/1735/6388 3011/1716/6388 +f 215/1737/6389 1614/1736/6389 1357/54/6389 +f 1378/1738/6390 215/1737/6390 2431/53/6390 +f 215/1737/6391 1378/1738/6391 1616/1723/6391 +f 1614/1736/6392 215/1737/6392 3014/1722/6392 +f 216/1740/6393 909/457/6393 1619/1739/6393 +f 1617/1712/6394 216/1740/6394 3015/1713/6394 +f 216/1740/6395 1617/1712/6395 1199/1741/6395 +f 909/457/6396 216/1740/6396 2454/458/6396 +f 217/1744/6397 1321/1742/6397 835/1743/6397 +f 1618/1745/6398 217/1744/6398 2648/1576/6398 +f 217/1744/6399 1618/1745/6399 1619/1739/6399 +f 1321/1742/6400 217/1744/6400 2722/456/6400 +f 218/1746/6401 1618/1745/6401 1247/1575/6401 +f 1610/1733/6402 218/1746/6402 2490/1574/6402 +f 218/1746/6403 1610/1733/6403 1620/1714/6403 +f 1618/1745/6404 218/1746/6404 3015/1713/6404 +f 219/1748/6405 799/430/6405 1623/1747/6405 +f 1621/1703/6406 219/1748/6406 3016/1704/6406 +f 219/1748/6407 1621/1703/6407 857/1749/6407 +f 799/430/6408 219/1748/6408 2387/431/6408 +f 220/1751/6409 1211/1750/6409 1199/1741/6409 +f 1622/1752/6410 220/1751/6410 3012/1720/6410 +f 220/1751/6411 1622/1752/6411 1623/1747/6411 +f 1211/1750/6412 220/1751/6412 2612/429/6412 +f 221/1753/6413 1622/1752/6413 1611/1719/6413 +f 1609/1754/6414 221/1753/6414 2601/1718/6414 +f 221/1753/6415 1609/1754/6415 1624/1705/6415 +f 1622/1752/6416 221/1753/6416 3016/1704/6416 +f 222/1756/6417 1194/1690/6417 1627/1755/6417 +f 1625/1694/6418 222/1756/6418 3017/1695/6418 +f 222/1756/6419 1625/1694/6419 1196/1757/6419 +f 1194/1690/6420 222/1756/6420 2600/1691/6420 +f 223/1760/6421 1606/1758/6421 967/1759/6421 +f 1626/1761/6422 223/1760/6422 2780/10/6422 +f 223/1760/6423 1626/1761/6423 1627/1755/6423 +f 1606/1758/6424 223/1760/6424 3007/1689/6424 +f 224/1762/6425 1626/1761/6425 1379/9/6425 +f 1377/1763/6426 224/1762/6426 2433/8/6426 +f 224/1762/6427 1377/1763/6427 1628/1696/6427 +f 1626/1761/6428 224/1762/6428 3017/1695/6428 +f 225/1765/6429 915/1564/6429 1631/1764/6429 +f 1629/1685/6430 225/1765/6430 3018/1686/6430 +f 225/1765/6431 1629/1685/6431 1195/1766/6431 +f 915/1564/6432 225/1765/6432 2460/1565/6432 +f 226/1768/6433 1327/1767/6433 857/1749/6433 +f 1630/1769/6434 226/1768/6434 2670/1711/6434 +f 226/1768/6435 1630/1769/6435 1631/1764/6435 +f 1327/1767/6436 226/1768/6436 2728/1563/6436 +f 227/1770/6437 1630/1769/6437 1269/1710/6437 +f 1606/1758/6438 227/1770/6438 2512/1709/6438 +f 227/1770/6439 1606/1758/6439 1632/1687/6439 +f 1630/1769/6440 227/1770/6440 3018/1686/6440 +f 228/1772/6441 805/61/6441 1635/1771/6441 +f 1633/1676/6442 228/1772/6442 3019/1677/6442 +f 228/1772/6443 1633/1676/6443 1315/1773/6443 +f 805/61/6444 228/1772/6444 2391/62/6444 +f 229/1775/6445 1217/1774/6445 1195/1766/6445 +f 1634/1776/6446 229/1775/6446 3008/1693/6446 +f 229/1775/6447 1634/1776/6447 1635/1771/6447 +f 1217/1774/6448 229/1775/6448 2618/60/6448 +f 230/1777/6449 1634/1776/6449 1607/1692/6449 +f 1605/1778/6450 230/1777/6450 2600/1691/6450 +f 230/1777/6451 1605/1778/6451 1636/1678/6451 +f 1634/1776/6452 230/1777/6452 3019/1677/6452 +f 231/1780/6453 1190/1663/6453 1639/1779/6453 +f 1637/1667/6454 231/1780/6454 3020/1668/6454 +f 231/1780/6455 1637/1667/6455 1192/1781/6455 +f 1190/1663/6456 231/1780/6456 2599/1664/6456 +f 232/1784/6457 1602/1782/6457 930/1783/6457 +f 1638/1785/6458 232/1784/6458 2743/73/6458 +f 232/1784/6459 1638/1785/6459 1639/1779/6459 +f 1602/1782/6460 232/1784/6460 3003/1662/6460 +f 233/1786/6461 1638/1785/6461 1342/72/6461 +f 1358/1787/6462 233/1786/6462 2393/71/6462 +f 233/1786/6463 1358/1787/6463 1640/1669/6463 +f 1638/1785/6464 233/1786/6464 3020/1668/6464 +f 234/1789/6465 970/1510/6465 1643/1788/6465 +f 1641/1658/6466 234/1789/6466 3021/1659/6466 +f 234/1789/6467 1641/1658/6467 1191/1790/6467 +f 970/1510/6468 234/1789/6468 2515/1511/6468 +f 235/1793/6469 1382/1791/6469 820/1792/6469 +f 1642/1794/6470 235/1793/6470 2633/1522/6470 +f 235/1793/6471 1642/1794/6471 1643/1788/6471 +f 1382/1791/6472 235/1793/6472 2783/1509/6472 +f 236/1795/6473 1642/1794/6473 1232/1521/6473 +f 1602/1782/6474 236/1795/6474 2475/1520/6474 +f 236/1795/6475 1602/1782/6475 1644/1660/6475 +f 1642/1794/6476 236/1795/6476 3021/1659/6476 +f 237/1797/6477 860/79/6477 1647/1796/6477 +f 1645/1649/6478 237/1797/6478 3022/1650/6478 +f 237/1797/6479 1645/1649/6479 862/1798/6479 +f 860/79/6480 237/1797/6480 2434/80/6480 +f 238/1800/6481 1272/1799/6481 1191/1790/6481 +f 1646/1801/6482 238/1800/6482 3004/1666/6482 +f 238/1800/6483 1646/1801/6483 1647/1796/6483 +f 1272/1799/6484 238/1800/6484 2673/78/6484 +f 239/1802/6485 1646/1801/6485 1603/1665/6485 +f 1601/1803/6486 239/1802/6486 2599/1664/6486 +f 239/1802/6487 1601/1803/6487 1648/1651/6487 +f 1646/1801/6488 239/1802/6488 3022/1650/6488 +f 240/1805/6489 1186/1636/6489 1651/1804/6489 +f 1649/1640/6490 240/1805/6490 3023/1641/6490 +f 240/1805/6491 1649/1640/6491 1188/1806/6491 +f 1186/1636/6492 240/1805/6492 2598/1637/6492 +f 241/1809/6493 1598/1807/6493 906/1808/6493 +f 1650/1810/6494 241/1809/6494 2719/91/6494 +f 241/1809/6495 1650/1810/6495 1651/1804/6495 +f 1598/1807/6496 241/1809/6496 2999/1635/6496 +f 242/1811/6497 1650/1810/6497 1318/90/6497 +f 1371/1812/6498 242/1811/6498 2405/89/6498 +f 242/1811/6499 1371/1812/6499 1652/1642/6499 +f 1650/1810/6500 242/1811/6500 3023/1641/6500 +f 243/1814/6501 962/1618/6501 1655/1813/6501 +f 1653/1631/6502 243/1814/6502 3024/1632/6502 +f 243/1814/6503 1653/1631/6503 1187/1815/6503 +f 962/1618/6504 243/1814/6504 2507/1619/6504 +f 244/1818/6505 1374/1816/6505 796/1817/6505 +f 1654/1819/6506 244/1818/6506 2609/1468/6506 +f 244/1818/6507 1654/1819/6507 1655/1813/6507 +f 1374/1816/6508 244/1818/6508 2775/1617/6508 +f 245/1820/6509 1654/1819/6509 1208/1467/6509 +f 1598/1807/6510 245/1820/6510 2451/1466/6510 +f 245/1820/6511 1598/1807/6511 1656/1633/6511 +f 1654/1819/6512 245/1820/6512 3024/1632/6512 +f 246/1822/6513 852/43/6513 1659/1821/6513 +f 1657/1622/6514 246/1822/6514 3025/1623/6514 +f 246/1822/6515 1657/1622/6515 854/1823/6515 +f 852/43/6516 246/1822/6516 2432/44/6516 +f 247/1825/6517 1264/1824/6517 1187/1815/6517 +f 1658/1826/6518 247/1825/6518 3000/1639/6518 +f 247/1825/6519 1658/1826/6519 1659/1821/6519 +f 1264/1824/6520 247/1825/6520 2665/42/6520 +f 248/1827/6521 1658/1826/6521 1599/1638/6521 +f 1597/1828/6522 248/1827/6522 2598/1637/6522 +f 248/1827/6523 1597/1828/6523 1660/1624/6523 +f 1658/1826/6524 248/1827/6524 3025/1623/6524 +f 249/1830/6525 1182/1609/6525 1663/1829/6525 +f 1661/1613/6526 249/1830/6526 3026/1614/6526 +f 249/1830/6527 1661/1613/6527 1184/1831/6527 +f 1182/1609/6528 249/1830/6528 2597/1610/6528 +f 250/1834/6529 1594/1832/6529 918/1833/6529 +f 1662/1835/6530 250/1834/6530 2731/361/6530 +f 250/1834/6531 1662/1835/6531 1663/1829/6531 +f 1594/1832/6532 250/1834/6532 2995/1608/6532 +f 251/1836/6533 1662/1835/6533 1330/360/6533 +f 1374/1816/6534 251/1836/6534 2384/359/6534 +f 251/1836/6535 1374/1816/6535 1664/1615/6535 +f 1662/1835/6536 251/1836/6536 3026/1614/6536 +f 252/1838/6537 946/1672/6537 1667/1837/6537 +f 1665/1604/6538 252/1838/6538 3027/1605/6538 +f 252/1838/6539 1665/1604/6539 1183/1839/6539 +f 946/1672/6540 252/1838/6540 2491/1673/6540 +f 253/1841/6541 1358/1787/6541 808/1840/6541 +f 1666/1842/6542 253/1841/6542 2621/658/6542 +f 253/1841/6543 1666/1842/6543 1667/1837/6543 +f 1358/1787/6544 253/1841/6544 2759/1671/6544 +f 254/1843/6545 1666/1842/6545 1220/657/6545 +f 1594/1832/6546 254/1843/6546 2463/656/6546 +f 254/1843/6547 1594/1832/6547 1668/1606/6547 +f 1666/1842/6548 254/1843/6548 3027/1605/6548 +f 255/1845/6549 836/25/6549 1671/1844/6549 +f 1669/1595/6550 255/1845/6550 3028/1596/6550 +f 255/1845/6551 1669/1595/6551 853/1846/6551 +f 836/25/6552 255/1845/6552 2415/26/6552 +f 256/1848/6553 1248/1847/6553 1183/1839/6553 +f 1670/1849/6554 256/1848/6554 2996/1612/6554 +f 256/1848/6555 1670/1849/6555 1671/1844/6555 +f 1248/1847/6556 256/1848/6556 2649/24/6556 +f 257/1850/6557 1670/1849/6557 1595/1611/6557 +f 1593/1851/6558 257/1850/6558 2597/1610/6558 +f 257/1850/6559 1593/1851/6559 1672/1597/6559 +f 1670/1849/6560 257/1850/6560 3028/1596/6560 +f 258/1853/6561 1178/1582/6561 1675/1852/6561 +f 1673/1586/6562 258/1853/6562 3029/1587/6562 +f 258/1853/6563 1673/1586/6563 1180/1854/6563 +f 1178/1582/6564 258/1853/6564 2596/1583/6564 +f 259/1857/6565 1590/1855/6565 963/1856/6565 +f 1674/1858/6566 259/1857/6566 2776/46/6566 +f 259/1857/6567 1674/1858/6567 1675/1852/6567 +f 1590/1855/6568 259/1857/6568 2991/1581/6568 +f 260/1859/6569 1674/1858/6569 1375/45/6569 +f 1373/1860/6570 260/1859/6570 2432/44/6570 +f 260/1859/6571 1373/1860/6571 1676/1588/6571 +f 1674/1858/6572 260/1859/6572 3029/1587/6572 +f 261/1862/6573 927/1267/6573 1679/1861/6573 +f 1677/1577/6574 261/1862/6574 3030/1578/6574 +f 261/1862/6575 1677/1577/6575 1179/1863/6575 +f 927/1267/6576 261/1862/6576 2472/1268/6576 +f 262/1865/6577 1339/1864/6577 853/1846/6577 +f 1678/1866/6578 262/1865/6578 2666/1603/6578 +f 262/1865/6579 1678/1866/6579 1679/1861/6579 +f 1339/1864/6580 262/1865/6580 2740/1266/6580 +f 263/1867/6581 1678/1866/6581 1265/1602/6581 +f 1590/1855/6582 263/1867/6582 2508/1601/6582 +f 263/1867/6583 1590/1855/6583 1680/1579/6583 +f 1678/1866/6584 263/1867/6584 3030/1578/6584 +f 264/1869/6585 817/160/6585 1683/1868/6585 +f 1681/1568/6586 264/1869/6586 3031/1569/6586 +f 264/1869/6587 1681/1568/6587 835/1743/6587 +f 817/160/6588 264/1869/6588 2402/161/6588 +f 265/1871/6589 1229/1870/6589 1179/1863/6589 +f 1682/1872/6590 265/1871/6590 2992/1585/6590 +f 265/1871/6591 1682/1872/6591 1683/1868/6591 +f 1229/1870/6592 265/1871/6592 2630/159/6592 +f 266/1873/6593 1682/1872/6593 1591/1584/6593 +f 1589/1874/6594 266/1873/6594 2596/1583/6594 +f 266/1873/6595 1589/1874/6595 1684/1570/6595 +f 1682/1872/6596 266/1873/6596 3031/1569/6596 +f 267/1876/6597 1174/1555/6597 1687/1875/6597 +f 1685/1559/6598 267/1876/6598 3032/1560/6598 +f 267/1876/6599 1685/1559/6599 1176/1877/6599 +f 1174/1555/6600 267/1876/6600 2595/1556/6600 +f 268/1880/6601 1586/1878/6601 1008/1879/6601 +f 1686/1881/6602 268/1880/6602 2821/433/6602 +f 268/1880/6603 1686/1881/6603 1687/1875/6603 +f 1586/1878/6604 268/1880/6604 2987/1554/6604 +f 269/1882/6605 1686/1881/6605 1420/432/6605 +f 1327/1767/6606 269/1882/6606 2387/431/6606 +f 269/1882/6607 1327/1767/6607 1688/1561/6607 +f 1686/1881/6608 269/1882/6608 3032/1560/6608 +f 270/1884/6609 1005/511/6609 1691/1883/6609 +f 1689/1550/6610 270/1884/6610 3033/1551/6610 +f 270/1884/6611 1689/1550/6611 1175/1885/6611 +f 1005/511/6612 270/1884/6612 2550/512/6612 +f 271/1888/6613 1417/1886/6613 898/1887/6613 +f 1690/1889/6614 271/1888/6614 2711/442/6614 +f 271/1888/6615 1690/1889/6615 1691/1883/6615 +f 1417/1886/6616 271/1888/6616 2818/510/6616 +f 272/1890/6617 1690/1889/6617 1310/441/6617 +f 1586/1878/6618 272/1890/6618 2553/440/6618 +f 272/1890/6619 1586/1878/6619 1692/1552/6619 +f 1690/1889/6620 272/1890/6620 3033/1551/6620 +f 273/1892/6621 895/412/6621 1695/1891/6621 +f 1693/1541/6622 273/1892/6622 3034/1542/6622 +f 273/1892/6623 1693/1541/6623 1325/1893/6623 +f 895/412/6624 273/1892/6624 2388/413/6624 +f 274/1895/6625 1307/1894/6625 1175/1885/6625 +f 1694/1896/6626 274/1895/6626 2988/1558/6626 +f 274/1895/6627 1694/1896/6627 1695/1891/6627 +f 1307/1894/6628 274/1895/6628 2708/411/6628 +f 275/1897/6629 1694/1896/6629 1587/1557/6629 +f 1585/1898/6630 275/1897/6630 2595/1556/6630 +f 275/1897/6631 1585/1898/6631 1696/1543/6631 +f 1694/1896/6632 275/1897/6632 3034/1542/6632 +f 1699/1900/6633 276/1899/6633 2983/1527/6633 +f 276/1899/6634 1699/1900/6634 1697/1533/6634 +f 1172/1901/6635 276/1899/6635 2985/1540/6635 +f 276/1899/6636 1172/1901/6636 1170/1528/6636 +f 1004/1904/6637 277/1902/6637 2549/521/6637 +f 277/1902/6638 1004/1904/6638 1698/1905/6638 +f 1699/1900/6639 277/1902/6639 3035/1534/6639 +f 277/1902/6640 1699/1900/6640 1582/1903/6640 +f 1416/405/6641 278/1906/6641 2817/406/6641 +f 278/1906/6642 1416/405/6642 1328/1907/6642 +f 1700/1535/6643 278/1906/6643 2729/1536/6643 +f 278/1906/6644 1700/1535/6644 1698/1905/6644 +f 1703/1909/6645 279/1908/6645 2814/591/6645 +f 279/1908/6646 1703/1909/6646 1701/1524/6646 +f 1171/1910/6647 279/1908/6647 2984/1531/6647 +f 279/1908/6648 1171/1910/6648 1001/592/6648 +f 894/1913/6649 280/1911/6649 2442/395/6649 +f 280/1911/6650 894/1913/6650 1702/1914/6650 +f 1703/1909/6651 280/1911/6651 3036/1525/6651 +f 280/1911/6652 1703/1909/6652 1413/1912/6652 +f 1306/522/6653 281/1915/6653 2707/523/6653 +f 281/1915/6654 1306/522/6654 1582/1903/6654 +f 1704/1526/6655 281/1915/6655 2983/1527/6655 +f 281/1915/6656 1704/1526/6656 1702/1914/6656 +f 282/1917/3628 891/385/3628 1707/1916/3628 +f 282/1917/3629 1707/1916/3629 1705/1514/3629 +f 282/1917/3630 1705/1514/3630 820/1792/3630 +f 891/385/6657 282/1917/6657 2417/386/6657 +f 1171/1910/6658 283/1918/6658 2546/593/6658 +f 283/1918/6659 1171/1910/6659 1706/1920/6659 +f 1707/1916/3634 283/1918/3634 3037/1515/3634 +f 283/1918/6660 1707/1916/6660 1303/1919/6660 +f 1583/1530/6661 284/1921/6661 2984/1531/6661 +f 284/1921/6662 1583/1530/6662 1581/1922/6662 +f 1708/1516/3638 284/1921/3638 2982/1518/3638 +f 284/1921/6663 1708/1516/6663 1706/1920/6663 +f 1711/1924/3640 285/1923/3640 2979/1500/3640 +f 1709/1505/3641 285/1923/3641 3038/1506/3641 +f 285/1923/3642 1709/1505/3642 1168/1925/3642 +f 285/1923/6664 1168/1925/6664 1166/1501/6664 +f 929/1928/3644 286/1926/3644 2474/575/3644 +f 286/1926/3645 929/1928/3645 1710/1929/3645 +f 286/1926/3646 1710/1929/3646 1711/1924/3646 +f 286/1926/6665 1711/1924/6665 1578/1927/6665 +f 287/1930/3648 1710/1929/3648 1341/387/3648 +f 1382/1791/6666 287/1930/6666 2417/386/6666 +f 287/1930/6667 1382/1791/6667 1712/1507/6667 +f 1710/1929/6668 287/1930/6668 3038/1506/6668 +f 1715/1932/6669 288/1931/6669 2768/1104/6669 +f 288/1931/6670 1715/1932/6670 1713/1497/6670 +f 1167/1933/6671 288/1931/6671 2980/1504/6671 +f 288/1931/6672 1167/1933/6672 955/1105/6672 +f 819/1936/6673 289/1934/6673 2404/116/6673 +f 289/1934/6674 819/1936/6674 1714/1937/6674 +f 1715/1932/6675 289/1934/6675 3039/1498/6675 +f 289/1934/6676 1715/1932/6676 1367/1935/6676 +f 1231/576/6677 290/1938/6677 2632/577/6677 +f 290/1938/6678 1231/576/6678 1578/1927/6678 +f 1716/1499/6679 290/1938/6679 2979/1500/6679 +f 290/1938/6680 1716/1499/6680 1714/1937/6680 +f 1719/1940/6681 291/1939/6681 2658/213/6681 +f 291/1939/6682 1719/1940/6682 1717/1488/6682 +f 861/1941/6683 291/1939/6683 2674/1495/6683 +f 291/1939/6684 861/1941/6684 845/214/6684 +f 1167/1933/6685 292/1942/6685 2500/1106/6685 +f 292/1942/6686 1167/1933/6686 1718/1944/6686 +f 1719/1940/6687 292/1942/6687 3040/1489/6687 +f 292/1942/6688 1719/1940/6688 1257/1943/6688 +f 1579/1503/6689 293/1945/6689 2980/1504/6689 +f 293/1945/6690 1579/1503/6690 1577/1946/6690 +f 1720/1490/6691 293/1945/6691 2978/1491/6691 +f 293/1945/6692 1720/1490/6692 1718/1944/6692 +f 1723/1948/6693 294/1947/6693 2975/1473/6693 +f 294/1947/6694 1723/1948/6694 1721/1479/6694 +f 1164/1949/6695 294/1947/6695 2977/1486/6695 +f 294/1947/6696 1164/1949/6696 1162/1474/6696 +f 1000/1952/6697 295/1950/6697 2545/602/6697 +f 295/1950/6698 1000/1952/6698 1722/1953/6698 +f 1723/1948/6699 295/1950/6699 3041/1480/6699 +f 295/1950/6700 1723/1948/6700 1574/1951/6700 +f 1412/378/6701 296/1954/6701 2813/379/6701 +f 296/1954/6702 1412/378/6702 1343/1955/6702 +f 1724/1481/6703 296/1954/6703 2744/1482/6703 +f 296/1954/6704 1724/1481/6704 1722/1953/6704 +f 1727/1957/6705 297/1956/6705 2810/672/6705 +f 297/1956/6706 1727/1957/6706 1725/1470/6706 +f 1163/1958/6707 297/1956/6707 2976/1477/6707 +f 297/1956/6708 1163/1958/6708 997/673/6708 +f 890/1961/6709 298/1959/6709 2441/368/6709 +f 298/1959/6710 890/1961/6710 1726/1962/6710 +f 1727/1957/6711 298/1959/6711 3042/1471/6711 +f 298/1959/6712 1727/1957/6712 1409/1960/6712 +f 1302/603/6713 299/1963/6713 2703/604/6713 +f 299/1963/6714 1302/603/6714 1574/1951/6714 +f 1728/1472/6715 299/1963/6715 2975/1473/6715 +f 299/1963/6716 1728/1472/6716 1726/1962/6716 +f 300/1965/3700 887/358/3700 1731/1964/3700 +f 300/1965/3701 1731/1964/3701 1729/1460/3701 +f 300/1965/6717 1729/1460/6717 796/1817/6717 +f 887/358/6718 300/1965/6718 2384/359/6718 +f 1163/1958/6719 301/1966/6719 2542/674/6719 +f 301/1966/6720 1163/1958/6720 1730/1968/6720 +f 1731/1964/6721 301/1966/6721 3043/1461/6721 +f 301/1966/6722 1731/1964/6722 1299/1967/6722 +f 1575/1476/6723 302/1969/6723 2976/1477/6723 +f 302/1969/6724 1575/1476/6724 1573/1970/6724 +f 1732/1462/6725 302/1969/6725 2974/1464/6725 +f 302/1969/3711 1732/1462/3711 1730/1968/3711 +f 1735/1972/6726 303/1971/6726 2971/1446/6726 +f 303/1971/6727 1735/1972/6727 1733/1452/6727 +f 1160/1973/6728 303/1971/6728 2973/1459/6728 +f 303/1971/6729 1160/1973/6729 1158/1447/6729 +f 996/1976/6730 304/1974/6730 2541/683/6730 +f 304/1974/6731 996/1976/6731 1734/1977/6731 +f 1735/1972/6732 304/1974/6732 3044/1453/6732 +f 304/1974/6733 1735/1972/6733 1570/1975/6733 +f 1408/351/6734 305/1978/6734 2809/352/6734 +f 305/1978/6735 1408/351/6735 1344/1979/6735 +f 1736/1454/6736 305/1978/6736 2745/1455/6736 +f 305/1978/6737 1736/1454/6737 1734/1977/6737 +f 1739/1981/6738 306/1980/6738 2806/753/6738 +f 306/1980/6739 1739/1981/6739 1737/1443/6739 +f 1159/1982/6740 306/1980/6740 2972/1450/6740 +f 306/1980/6741 1159/1982/6741 993/754/6741 +f 886/1985/6742 307/1983/6742 2440/341/6742 +f 307/1983/6743 886/1985/6743 1738/1986/6743 +f 1739/1981/6744 307/1983/6744 3045/1444/6744 +f 307/1983/6745 1739/1981/6745 1405/1984/6745 +f 1298/684/6746 308/1987/6746 2699/685/6746 +f 308/1987/6747 1298/684/6747 1570/1975/6747 +f 1740/1445/6748 308/1987/6748 2971/1446/6748 +f 308/1987/6749 1740/1445/6749 1738/1986/6749 +f 1743/1989/6750 309/1988/6750 2696/330/6750 +f 309/1988/6751 1743/1989/6751 1741/1434/6751 +f 839/1990/6752 309/1988/6752 2652/1441/6752 +f 309/1988/6753 839/1990/6753 883/331/6753 +f 1159/1982/6754 310/1991/6754 2538/755/6754 +f 310/1991/6755 1159/1982/6755 1742/1993/6755 +f 1743/1989/6756 310/1991/6756 3046/1435/6756 +f 310/1991/6757 1743/1989/6757 1295/1992/6757 +f 1571/1449/6758 311/1994/6758 2972/1450/6758 +f 311/1994/6759 1571/1449/6759 1569/1995/6759 +f 1744/1436/6760 311/1994/6760 2970/1437/6760 +f 311/1994/6761 1744/1436/6761 1742/1993/6761 +f 1747/1997/6762 312/1996/6762 2967/1419/6762 +f 312/1996/3749 1747/1997/3749 1745/1424/3749 +f 312/1996/3750 1745/1424/3750 1156/1998/3750 +f 312/1996/6763 1156/1998/6763 1154/1420/6763 +f 971/2001/3752 313/1999/3752 2516/1493/3752 +f 313/1999/3753 971/2001/3753 1746/2002/3753 +f 313/1999/3754 1746/2002/3754 1747/1997/3754 +f 313/1999/6764 1747/1997/6764 1566/2000/6764 +f 314/2003/3756 1746/2002/3756 1383/81/3756 +f 1381/2004/6765 314/2003/6765 2434/80/6765 +f 314/2003/6766 1381/2004/6766 1748/1426/6766 +f 1746/2002/6767 314/2003/6767 3047/1425/6767 +f 1751/2006/6768 315/2005/6768 2753/1293/6768 +f 315/2005/6769 1751/2006/6769 1749/1416/6769 +f 1155/2007/6770 315/2005/6770 2968/1423/6770 +f 315/2005/6771 1155/2007/6771 940/1294/6771 +f 861/1941/6772 316/2008/6772 2426/215/6772 +f 316/2008/6773 861/1941/6773 1750/2010/6773 +f 1751/2006/6774 316/2008/6774 3048/1417/6774 +f 316/2008/6775 1751/2006/6775 1352/2009/6775 +f 1273/1494/6776 317/2011/6776 2674/1495/6776 +f 317/2011/6777 1273/1494/6777 1566/2000/6777 +f 1752/1418/6778 317/2011/6778 2967/1419/6778 +f 317/2011/6779 1752/1418/6779 1750/2010/6779 +f 1755/2013/6780 318/2012/6780 2643/150/6780 +f 318/2012/6781 1755/2013/6781 1753/1407/6781 +f 832/2014/6782 318/2012/6782 2645/1414/6782 +f 318/2012/6783 832/2014/6783 830/151/6783 +f 1155/2007/6784 319/2015/6784 2485/1295/6784 +f 319/2015/6785 1155/2007/6785 1754/2017/6785 +f 1755/2013/6786 319/2015/6786 3049/1408/6786 +f 319/2015/6787 1755/2013/6787 1242/2016/6787 +f 1567/1422/6788 320/2018/6788 2968/1423/6788 +f 320/2018/6789 1567/1422/6789 1565/2019/6789 +f 1756/1409/6790 320/2018/6790 2966/1410/6790 +f 320/2018/6791 1756/1409/6791 1754/2017/6791 +f 321/2021/6792 1150/1393/6792 1759/2020/6792 +f 1757/1397/6793 321/2021/6793 3050/1398/6793 +f 321/2021/6794 1757/1397/6794 1152/2022/6794 +f 1150/1393/6795 321/2021/6795 2589/1394/6795 +f 322/2025/6796 1562/2023/6796 992/2024/6796 +f 1758/2026/6797 322/2025/6797 2805/325/6797 +f 322/2025/6798 1758/2026/6798 1759/2020/6798 +f 1562/2023/6799 322/2025/6799 2963/1392/6799 +f 323/2027/6800 1758/2026/6800 1404/324/6800 +f 1347/2028/6801 323/2027/6801 2421/323/6801 +f 323/2027/6802 1347/2028/6802 1760/1399/6802 +f 1758/2026/6803 323/2027/6803 3050/1398/6803 +f 324/2030/6804 989/835/6804 1763/2029/6804 +f 1761/1388/6805 324/2030/6805 3051/1389/6805 +f 324/2030/6806 1761/1388/6806 1151/2031/6806 +f 989/835/6807 324/2030/6807 2534/836/6807 +f 325/2034/6808 1401/2032/6808 882/2033/6808 +f 1762/2035/6809 325/2034/6809 2695/766/6809 +f 325/2034/6810 1762/2035/6810 1763/2029/6810 +f 1401/2032/6811 325/2034/6811 2802/834/6811 +f 326/2036/6812 1762/2035/6812 1294/765/6812 +f 1562/2023/6813 326/2036/6813 2537/764/6813 +f 326/2036/6814 1562/2023/6814 1764/1390/6814 +f 1762/2035/6815 326/2036/6815 3051/1389/6815 +f 327/2038/3808 879/304/3808 1767/2037/3808 +f 1765/1379/3809 327/2038/3809 3052/1380/3809 +f 797/2039/6816 327/2038/6816 2610/1387/6816 +f 327/2038/6817 797/2039/6817 879/304/6817 +f 328/2041/6818 1291/2040/6818 1151/2031/6818 +f 1766/2042/6819 328/2041/6819 2964/1396/6819 +f 328/2041/6820 1766/2042/6820 1767/2037/6820 +f 1291/2040/6821 328/2041/6821 2692/303/6821 +f 329/2043/6822 1766/2042/6822 1563/1395/6822 +f 1561/2044/6823 329/2043/6823 2589/1394/6823 +f 329/2043/3818 1561/2044/3818 1768/1381/3818 +f 1766/2042/6824 329/2043/6824 3052/1380/6824 +f 330/2046/6825 1146/1366/6825 1771/2045/6825 +f 1769/1370/6826 330/2046/6826 3053/1371/6826 +f 330/2046/6827 1769/1370/6827 1148/2047/6827 +f 1146/1366/6828 330/2046/6828 2588/1367/6828 +f 331/2050/6829 1558/2048/6829 988/2049/6829 +f 1770/2051/6830 331/2050/6830 2801/298/6830 +f 331/2050/6831 1770/2051/6831 1771/2045/6831 +f 1558/2048/6832 331/2050/6832 2959/1365/6832 +f 332/2052/6833 1770/2051/6833 1400/297/6833 +f 1348/2053/6834 332/2052/6834 2422/296/6834 +f 332/2052/6835 1348/2053/6835 1772/1372/6835 +f 1770/2051/6836 332/2052/6836 3053/1371/6836 +f 333/2055/6837 985/916/6837 1775/2054/6837 +f 1773/1361/6838 333/2055/6838 3054/1362/6838 +f 333/2055/6839 1773/1361/6839 1147/2056/6839 +f 985/916/6840 333/2055/6840 2530/917/6840 +f 334/2059/6841 1397/2057/6841 878/2058/6841 +f 1774/2060/6842 334/2059/6842 2691/847/6842 +f 334/2059/6843 1774/2060/6843 1775/2054/6843 +f 1397/2057/6844 334/2059/6844 2798/915/6844 +f 335/2061/6845 1774/2060/6845 1290/846/6845 +f 1558/2048/6846 335/2061/6846 2533/845/6846 +f 335/2061/6847 1558/2048/6847 1776/1363/6847 +f 1774/2060/6848 335/2061/6848 3054/1362/6848 +f 336/2063/6849 875/277/6849 1779/2062/6849 +f 1777/1352/6850 336/2063/6850 3055/1353/6850 +f 336/2063/6851 1777/1352/6851 842/2064/6851 +f 875/277/6852 336/2063/6852 2423/278/6852 +f 337/2066/6853 1287/2065/6853 1147/2056/6853 +f 1778/2067/6854 337/2066/6854 2960/1369/6854 +f 337/2066/6855 1778/2067/6855 1779/2062/6855 +f 1287/2065/6856 337/2066/6856 2688/276/6856 +f 338/2068/6857 1778/2067/6857 1559/1368/6857 +f 1557/2069/6858 338/2068/6858 2588/1367/6858 +f 338/2068/6859 1557/2069/6859 1780/1354/6859 +f 1778/2067/6860 338/2068/6860 3055/1353/6860 +f 1783/2071/6861 339/2070/6861 2955/1338/6861 +f 339/2070/6862 1783/2071/6862 1781/1344/6862 +f 1144/2072/6863 339/2070/6863 2957/1351/6863 +f 339/2070/6864 1144/2072/6864 1142/1339/6864 +f 984/2075/6865 340/2073/6865 2529/926/6865 +f 340/2073/6866 984/2075/6866 1782/2076/6866 +f 1783/2071/6867 340/2073/6867 3056/1345/6867 +f 340/2073/6868 1783/2071/6868 1554/2074/6868 +f 1396/270/6869 341/2077/6869 2797/271/6869 +f 341/2077/6870 1396/270/6870 1340/2078/6870 +f 1784/1346/6871 341/2077/6871 2741/1347/6871 +f 341/2077/6872 1784/1346/6872 1782/2076/6872 +f 1787/2080/6873 342/2079/6873 2794/996/6873 +f 342/2079/6874 1787/2080/6874 1785/1335/6874 +f 1143/2081/6875 342/2079/6875 2956/1342/6875 +f 342/2079/6876 1143/2081/6876 981/997/6876 +f 874/2084/6877 343/2082/6877 2437/260/6877 +f 343/2082/6878 874/2084/6878 1786/2085/6878 +f 1787/2080/6879 343/2082/6879 3057/1336/6879 +f 343/2082/6880 1787/2080/6880 1393/2083/6880 +f 1286/927/6881 344/2086/6881 2687/928/6881 +f 344/2086/6882 1286/927/6882 1554/2074/6882 +f 1788/1337/6883 344/2086/6883 2955/1338/6883 +f 344/2086/6884 1788/1337/6884 1786/2085/6884 +f 1791/2088/6885 345/2087/6885 2684/249/6885 +f 345/2087/6886 1791/2088/6886 1789/1326/6886 +f 843/2089/6887 345/2087/6887 2656/1333/6887 +f 345/2087/6888 843/2089/6888 871/250/6888 +f 1143/2081/6889 346/2090/6889 2526/998/6889 +f 346/2090/6890 1143/2081/6890 1790/2092/6890 +f 1791/2088/6891 346/2090/6891 3058/1327/6891 +f 346/2090/6892 1791/2088/6892 1283/2091/6892 +f 1555/1341/6893 347/2093/6893 2956/1342/6893 +f 347/2093/6894 1555/1341/6894 1553/2094/6894 +f 1792/1328/6895 347/2093/6895 2954/1329/6895 +f 347/2093/6896 1792/1328/6896 1790/2092/6896 +f 1795/2096/6897 348/2095/6897 2951/1311/6897 +f 348/2095/6898 1795/2096/6898 1793/1317/6898 +f 1140/2097/6899 348/2095/6899 2953/1324/6899 +f 348/2095/6900 1140/2097/6900 1138/1312/6900 +f 980/2100/6901 349/2098/6901 2525/1007/6901 +f 349/2098/6902 980/2100/6902 1794/2101/6902 +f 1795/2096/6903 349/2098/6903 3059/1318/6903 +f 349/2098/6904 1795/2096/6904 1550/2099/6904 +f 1392/243/6905 350/2102/6905 2793/244/6905 +f 350/2102/6906 1392/243/6906 1351/2103/6906 +f 1796/1319/6907 350/2102/6907 2752/1320/6907 +f 350/2102/6908 1796/1319/6908 1794/2101/6908 +f 1799/2105/6909 351/2104/6909 2790/1077/6909 +f 351/2104/6910 1799/2105/6910 1797/1308/6910 +f 1139/2106/6911 351/2104/6911 2952/1315/6911 +f 351/2104/6912 1139/2106/6912 977/1078/6912 +f 870/2109/6913 352/2107/6913 2436/233/6913 +f 352/2107/6914 870/2109/6914 1798/2110/6914 +f 1799/2105/6915 352/2107/6915 3060/1309/6915 +f 352/2107/6916 1799/2105/6916 1389/2108/6916 +f 1282/1008/6917 353/2111/6917 2683/1009/6917 +f 353/2111/6918 1282/1008/6918 1550/2099/6918 +f 1800/1310/6919 353/2111/6919 2951/1311/6919 +f 353/2111/6920 1800/1310/6920 1798/2110/6920 +f 1803/2113/6921 354/2112/6921 2680/222/6921 +f 354/2112/6922 1803/2113/6922 1801/1299/6922 +f 1337/2114/6923 354/2112/6923 2738/1306/6923 +f 354/2112/6924 1337/2114/6924 867/223/6924 +f 1139/2106/6925 355/2115/6925 2522/1079/6925 +f 355/2115/6926 1139/2106/6926 1802/2117/6926 +f 1803/2113/6927 355/2115/6927 3061/1300/6927 +f 355/2115/6928 1803/2113/6928 1279/2116/6928 +f 1551/1314/6929 356/2118/6929 2952/1315/6929 +f 356/2118/6930 1551/1314/6930 1549/2119/6930 +f 1804/1301/6931 356/2118/6931 2950/1302/6931 +f 356/2118/6932 1804/1301/6932 1802/2117/6932 +f 1807/2121/6933 357/2120/6933 2947/1284/6933 +f 357/2120/6934 1807/2121/6934 1805/1290/6934 +f 1136/2122/6935 357/2120/6935 2949/1297/6935 +f 357/2120/6936 1136/2122/6936 1134/1285/6936 +f 976/2125/6937 358/2123/6937 2521/1088/6937 +f 358/2123/6938 976/2125/6938 1806/2126/6938 +f 1807/2121/6939 358/2123/6939 3062/1291/6939 +f 358/2123/6940 1807/2121/6940 1546/2124/6940 +f 1388/216/6941 359/2127/6941 2789/217/6941 +f 359/2127/6942 1388/216/6942 1352/2009/6942 +f 1808/1292/6943 359/2127/6943 2753/1293/6943 +f 359/2127/6944 1808/1292/6944 1806/2126/6944 +f 1811/2129/6945 360/2128/6945 2786/1158/6945 +f 360/2128/6946 1811/2129/6946 1809/1281/6946 +f 1135/2130/6947 360/2128/6947 2948/1288/6947 +f 360/2128/6948 1135/2130/6948 973/1159/6948 +f 866/2133/6949 361/2131/6949 2435/206/6949 +f 361/2131/6950 866/2133/6950 1810/2134/6950 +f 1811/2129/6951 361/2131/6951 3063/1282/6951 +f 361/2131/6952 1811/2129/6952 1385/2132/6952 +f 1278/1089/6953 362/2135/6953 2679/1090/6953 +f 362/2135/6954 1278/1089/6954 1546/2124/6954 +f 1812/1283/6955 362/2135/6955 2947/1284/6955 +f 362/2135/6956 1812/1283/6956 1810/2134/6956 +f 1815/2137/6957 363/2136/6957 2676/195/6957 +f 363/2136/6958 1815/2137/6958 1813/1272/6958 +f 846/2138/6959 363/2136/6959 2659/1279/6959 +f 363/2136/6960 846/2138/6960 863/196/6960 +f 1135/2130/6961 364/2139/6961 2518/1160/6961 +f 364/2139/6962 1135/2130/6962 1814/2141/6962 +f 1815/2137/6963 364/2139/6963 3064/1273/6963 +f 364/2139/6964 1815/2137/6964 1275/2140/6964 +f 1547/1287/6965 365/2142/6965 2948/1288/6965 +f 365/2142/6966 1547/1287/6966 1545/2143/6966 +f 1816/1274/6967 365/2142/6967 2946/1275/6967 +f 365/2142/6968 1816/1274/6968 1814/2141/6968 +f 366/2145/6969 1130/1258/6969 1819/2144/6969 +f 1817/1262/6970 366/2145/6970 3065/1263/6970 +f 366/2145/6971 1817/1262/6971 1132/2146/6971 +f 1130/1258/6972 366/2145/6972 2584/1259/6972 +f 367/2149/6973 1542/2147/6973 972/2148/6973 +f 1818/2150/6974 367/2149/6974 2785/28/6974 +f 367/2149/6975 1818/2150/6975 1819/2144/6975 +f 1542/2147/6976 367/2149/6976 2943/1257/6976 +f 368/2151/6977 1818/2150/6977 1384/27/6977 +f 1339/1864/6978 368/2151/6978 2415/26/6978 +f 368/2151/6979 1339/1864/6979 1820/1264/6979 +f 1818/2150/6980 368/2151/6980 3065/1263/6980 +f 369/2153/6981 969/1429/6981 1823/2152/6981 +f 1821/1253/6982 369/2153/6982 3066/1254/6982 +f 369/2153/6983 1821/1253/6983 1131/2154/6983 +f 969/1429/6984 369/2153/6984 2514/1430/6984 +f 370/2155/6985 1381/2004/6985 862/1798/6985 +f 1822/2156/6986 370/2155/6986 2675/1657/6986 +f 370/2155/6987 1822/2156/6987 1823/2152/6987 +f 1381/2004/6988 370/2155/6988 2782/1428/6988 +f 371/2157/6989 1822/2156/6989 1274/1656/6989 +f 1542/2147/6990 371/2157/6990 2517/1655/6990 +f 371/2157/6991 1542/2147/6991 1824/1255/6991 +f 1822/2156/6992 371/2157/6992 3066/1254/6992 +f 372/2159/6993 859/106/6993 1827/2158/6993 +f 1825/1244/6994 372/2159/6994 3067/1245/6994 +f 372/2159/6995 1825/1244/6995 847/2160/6995 +f 859/106/6996 372/2159/6996 2428/107/6996 +f 373/2162/6997 1271/2161/6997 1131/2154/6997 +f 1826/2163/6998 373/2162/6998 2944/1261/6998 +f 373/2162/6999 1826/2163/6999 1827/2158/6999 +f 1271/2161/7000 373/2162/7000 2672/105/7000 +f 374/2164/7001 1826/2163/7001 1543/1260/7001 +f 1541/2165/7002 374/2164/7002 2584/1259/7002 +f 374/2164/7003 1541/2165/7003 1828/1246/7003 +f 1826/2163/7004 374/2164/7004 3067/1245/7004 +f 375/2167/7005 1126/1231/7005 1831/2166/7005 +f 1829/1235/7006 375/2167/7006 3068/1236/7006 +f 375/2167/7007 1829/1235/7007 1128/2168/7007 +f 1126/1231/7008 375/2167/7008 2583/1232/7008 +f 376/2171/7009 1538/2169/7009 968/2170/7009 +f 1830/2172/7010 376/2171/7010 2781/190/7010 +f 376/2171/7011 1830/2172/7011 1831/2166/7011 +f 1538/2169/7012 376/2171/7012 2939/1230/7012 +f 377/2173/7013 1830/2172/7013 1380/189/7013 +f 1355/2174/7014 377/2173/7014 2429/188/7014 +f 377/2173/7015 1355/2174/7015 1832/1237/7015 +f 1830/2172/7016 377/2173/7016 3068/1236/7016 +f 378/2176/7017 965/1699/7017 1835/2175/7017 +f 1833/1226/7018 378/2176/7018 3069/1227/7018 +f 378/2176/7019 1833/1226/7019 1127/2177/7019 +f 965/1699/7020 378/2176/7020 2510/1700/7020 +f 379/2179/7021 1377/1763/7021 858/2178/7021 +f 1834/2180/7022 379/2179/7022 2671/1171/7022 +f 379/2179/7023 1834/2180/7023 1835/2175/7023 +f 1377/1763/7024 379/2179/7024 2778/1698/7024 +f 380/2181/7025 1834/2180/7025 1270/1170/7025 +f 1538/2169/7026 380/2181/7026 2513/1169/7026 +f 380/2181/7027 1538/2169/7027 1836/1228/7027 +f 1834/2180/7028 380/2181/7028 3069/1227/7028 +f 381/2183/7029 855/16/7029 1839/2182/7029 +f 1837/1217/7030 381/2183/7030 3070/1218/7030 +f 381/2183/7031 1837/1217/7031 1333/2184/7031 +f 855/16/7032 381/2183/7032 2411/17/7032 +f 382/2186/7033 1267/2185/7033 1127/2177/7033 +f 1838/2187/7034 382/2186/7034 2940/1234/7034 +f 382/2186/7035 1838/2187/7035 1839/2182/7035 +f 1267/2185/7036 382/2186/7036 2668/15/7036 +f 383/2188/7037 1838/2187/7037 1539/1233/7037 +f 1537/2189/7038 383/2188/7038 2583/1232/7038 +f 383/2188/7039 1537/2189/7039 1840/1219/7039 +f 1838/2187/7040 383/2188/7040 3070/1218/7040 +f 384/2191/7041 1122/1204/7041 1843/2190/7041 +f 1841/1208/7042 384/2191/7042 3071/1209/7042 +f 384/2191/7043 1841/1208/7043 1124/2192/7043 +f 1122/1204/7044 384/2191/7044 2582/1205/7044 +f 385/2195/7045 1534/2193/7045 964/2194/7045 +f 1842/2196/7046 385/2195/7046 2777/37/7046 +f 385/2195/7047 1842/2196/7047 1843/2190/7047 +f 1534/2193/7048 385/2195/7048 2935/1203/7048 +f 386/2197/7049 1842/2196/7049 1376/36/7049 +f 1356/2198/7050 386/2197/7050 2430/35/7050 +f 386/2197/7051 1356/2198/7051 1844/1210/7051 +f 1842/2196/7052 386/2197/7052 3071/1209/7052 +f 387/2200/7053 961/1591/7053 1847/2199/7053 +f 1845/1199/7054 387/2200/7054 3072/1200/7054 +f 387/2200/7055 1845/1199/7055 1123/2201/7055 +f 961/1591/7056 387/2200/7056 2506/1592/7056 +f 388/2202/7057 1373/1860/7057 854/1823/7057 +f 1846/2203/7058 388/2202/7058 2667/1630/7058 +f 388/2202/7059 1846/2203/7059 1847/2199/7059 +f 1373/1860/7060 388/2202/7060 2774/1590/7060 +f 389/2204/7061 1846/2203/7061 1266/1629/7061 +f 1534/2193/7062 389/2204/7062 2509/1628/7062 +f 389/2204/7063 1534/2193/7063 1848/1201/7063 +f 1846/2203/7064 389/2204/7064 3072/1200/7064 +f 390/2206/7065 851/52/7065 1851/2205/7065 +f 1849/1190/7066 390/2206/7066 3073/1191/7066 +f 390/2206/7067 1849/1190/7067 850/2207/7067 +f 851/52/7068 390/2206/7068 2431/53/7068 +f 391/2209/7069 1263/2208/7069 1123/2201/7069 +f 1850/2210/7070 391/2209/7070 2936/1207/7070 +f 391/2209/7071 1850/2210/7071 1851/2205/7071 +f 1263/2208/7072 391/2209/7072 2664/51/7072 +f 392/2211/7073 1850/2210/7073 1535/1206/7073 +f 1533/2212/7074 392/2211/7074 2582/1205/7074 +f 392/2211/7075 1533/2212/7075 1852/1192/7075 +f 1850/2210/7076 392/2211/7076 3073/1191/7076 +f 393/2214/7077 1118/1177/7077 1855/2213/7077 +f 1853/1181/7078 393/2214/7078 3074/1182/7078 +f 393/2214/7079 1853/1181/7079 1120/2215/7079 +f 1118/1177/7080 393/2214/7080 2581/1178/7080 +f 394/2218/7081 1530/2216/7081 960/2217/7081 +f 1854/2219/7082 394/2218/7082 2773/181/7082 +f 394/2218/7083 1854/2219/7083 1855/2213/7083 +f 1530/2216/7084 394/2218/7084 2931/1176/7084 +f 395/2220/7085 1854/2219/7085 1372/180/7085 +f 1370/2221/7086 395/2220/7086 2409/179/7086 +f 395/2220/7087 1370/2221/7087 1856/1183/7087 +f 1854/2219/7088 395/2220/7088 3074/1182/7088 +f 396/2223/7089 966/1726/7089 1859/2222/7089 +f 1857/1172/7090 396/2223/7090 3075/1173/7090 +f 396/2223/7091 1857/1172/7091 1119/2224/7091 +f 966/1726/7092 396/2223/7092 2511/1727/7092 +f 397/2225/7093 1378/1738/7093 850/2207/7093 +f 1858/2226/7094 397/2225/7094 2663/1198/7094 +f 397/2225/7095 1858/2226/7095 1859/2222/7095 +f 1378/1738/7096 397/2225/7096 2779/1725/7096 +f 398/2227/7097 1858/2226/7097 1262/1197/7097 +f 1530/2216/7098 398/2227/7098 2505/1196/7098 +f 398/2227/7099 1530/2216/7099 1860/1174/7099 +f 1858/2226/7100 398/2227/7100 3075/1173/7100 +f 399/2229/7101 856/7/7101 1863/2228/7101 +f 1861/1163/7102 399/2229/7102 3076/1164/7102 +f 399/2229/7103 1861/1163/7103 858/2178/7103 +f 856/7/7104 399/2229/7104 2433/8/7104 +f 400/2231/7105 1268/2230/7105 1119/2224/7105 +f 1862/2232/7106 400/2231/7106 2932/1180/7106 +f 400/2231/7107 1862/2232/7107 1863/2228/7107 +f 1268/2230/7108 400/2231/7108 2669/6/7108 +f 401/2233/7109 1862/2232/7109 1531/1179/7109 +f 1529/2234/7110 401/2233/7110 2581/1178/7110 +f 401/2233/7111 1529/2234/7111 1864/1165/7111 +f 1862/2232/7112 401/2233/7112 3076/1164/7112 +f 1867/2236/7113 402/2235/7113 2927/1149/7113 +f 402/2235/7114 1867/2236/7114 1865/1155/7114 +f 1116/2237/7115 402/2235/7115 2929/1162/7115 +f 402/2235/7116 1116/2237/7116 1114/1150/7116 +f 975/2240/7117 403/2238/7117 2520/1115/7117 +f 403/2238/7118 975/2240/7118 1866/2241/7118 +f 1867/2236/7119 403/2238/7119 3077/1156/7119 +f 403/2238/7120 1867/2236/7120 1526/2239/7120 +f 1387/207/7121 404/2242/7121 2788/208/7121 +f 404/2242/7122 1387/207/7122 1385/2132/7122 +f 1868/1157/7123 404/2242/7123 2786/1158/7123 +f 404/2242/7124 1868/1157/7124 1866/2241/7124 +f 1871/2246/7125 405/2243/7125 2732/2245/7125 +f 405/2243/7126 1871/2246/7126 1869/1146/7126 +f 1115/2247/7127 405/2243/7127 2928/1153/7127 +f 405/2243/7128 1115/2247/7128 919/2244/7128 +f 865/2252/7129 406/2249/7129 2383/2251/7129 +f 406/2249/7130 865/2252/7130 1870/2253/7130 +f 1871/2246/7131 406/2249/7131 3078/1147/7131 +f 406/2249/7132 1871/2246/7132 1331/2250/7132 +f 1277/1116/7133 407/2254/7133 2678/1117/7133 +f 407/2254/7134 1277/1116/7134 1526/2239/7134 +f 1872/1148/7135 407/2254/7135 2927/1149/7135 +f 407/2254/7136 1872/1148/7136 1870/2253/7136 +f 1875/2258/7137 408/2255/7137 2622/2257/7137 +f 408/2255/7138 1875/2258/7138 1873/1137/7138 +f 831/2259/7139 408/2255/7139 2644/1144/7139 +f 408/2255/7140 831/2259/7140 809/2256/7140 +f 1115/2247/7141 409/2261/7141 2464/2248/7141 +f 409/2261/7142 1115/2247/7142 1874/2263/7142 +f 1875/2258/7143 409/2261/7143 3079/1138/7143 +f 409/2261/7144 1875/2258/7144 1221/2262/7144 +f 1527/1152/7145 410/2264/7145 2928/1153/7145 +f 410/2264/7146 1527/1152/7146 1525/2265/7146 +f 1876/1139/7147 410/2264/7147 2926/1140/7147 +f 410/2264/7148 1876/1139/7148 1874/2263/7148 +f 1879/2267/7149 411/2266/7149 2923/1122/7149 +f 411/2266/7150 1879/2267/7150 1877/1128/7150 +f 1112/2268/7151 411/2266/7151 2925/1135/7151 +f 411/2266/7152 1112/2268/7152 1110/1123/7152 +f 917/2271/7153 412/2269/7153 2462/818/7153 +f 412/2269/7154 917/2271/7154 1878/2272/7154 +f 1879/2267/7155 412/2269/7155 3080/1129/7155 +f 412/2269/7156 1879/2267/7156 1522/2270/7156 +f 1329/306/7157 413/2273/7157 2730/307/7157 +f 413/2273/7158 1329/306/7158 1386/2274/7158 +f 1880/1130/7159 413/2273/7159 2787/1131/7159 +f 413/2273/7160 1880/1130/7160 1878/2272/7160 +f 1883/2278/7161 414/2275/7161 2718/2277/7161 +f 414/2275/7162 1883/2278/7162 1881/1119/7162 +f 1111/2279/7163 414/2275/7163 2924/1126/7163 +f 414/2275/7164 1111/2279/7164 905/2276/7164 +f 807/2284/7165 415/2281/7165 2389/2283/7165 +f 415/2281/7166 807/2284/7166 1882/2285/7166 +f 1883/2278/7167 415/2281/7167 3081/1120/7167 +f 415/2281/7168 1883/2278/7168 1317/2282/7168 +f 1219/819/7169 416/2286/7169 2620/820/7169 +f 416/2286/7170 1219/819/7170 1522/2270/7170 +f 1884/1121/7171 416/2286/7171 2923/1122/7171 +f 416/2286/7172 1884/1121/7172 1882/2285/7172 +f 1887/2290/7173 417/2287/7173 2608/2289/7173 +f 417/2287/7174 1887/2290/7174 1885/1110/7174 +f 865/2252/7175 417/2287/7175 2678/1117/7175 +f 417/2287/7176 865/2252/7176 795/2288/7176 +f 1111/2279/7177 418/2291/7177 2450/2280/7177 +f 418/2291/7178 1111/2279/7178 1886/2293/7178 +f 1887/2290/7179 418/2291/7179 3082/1111/7179 +f 418/2291/7180 1887/2290/7180 1207/2292/7180 +f 1523/1125/7181 419/2294/7181 2924/1126/7181 +f 419/2294/7182 1523/1125/7182 1521/2295/7182 +f 1888/1112/7183 419/2294/7183 2922/1113/7183 +f 419/2294/7184 1888/1112/7184 1886/2293/7184 +f 1891/2297/7185 420/2296/7185 2919/1095/7185 +f 420/2296/7186 1891/2297/7186 1889/1101/7186 +f 1108/2298/7187 420/2296/7187 2921/1108/7187 +f 420/2296/7188 1108/2298/7188 1106/1096/7188 +f 907/2301/7189 421/2299/7189 2452/1385/7189 +f 421/2299/7190 907/2301/7190 1890/2302/7190 +f 1891/2297/7191 421/2299/7191 3083/1102/7191 +f 421/2299/7192 1891/2297/7192 1518/2300/7192 +f 1319/117/7193 422/2303/7193 2720/118/7193 +f 422/2303/7194 1319/117/7194 1367/1935/7194 +f 1892/1103/7195 422/2303/7195 2768/1104/7195 +f 422/2303/7196 1892/1103/7196 1890/2302/7196 +f 1895/2305/7197 423/2304/7197 2787/1131/7197 +f 423/2304/7198 1895/2305/7198 1893/1092/7198 +f 1107/2306/7199 423/2304/7199 2920/1099/7199 +f 423/2304/7200 1107/2306/7200 974/1132/7200 +f 797/2039/7201 424/2307/7201 2385/305/7201 +f 424/2307/7202 797/2039/7202 1894/2308/7202 +f 1895/2305/7203 424/2307/7203 3084/1093/7203 +f 424/2307/7204 1895/2305/7204 1386/2274/7204 +f 1209/1386/7205 425/2309/7205 2610/1387/7205 +f 425/2309/7206 1209/1386/7206 1518/2300/7206 +f 1896/1094/7207 425/2309/7207 2919/1095/7207 +f 425/2309/7208 1896/1094/7208 1894/2308/7208 +f 1899/2311/7209 426/2310/7209 2677/204/7209 +f 426/2310/7210 1899/2311/7210 1897/1083/7210 +f 866/2133/7211 426/2310/7211 2679/1090/7211 +f 426/2310/7212 866/2133/7212 864/205/7212 +f 1107/2306/7213 427/2312/7213 2519/1133/7213 +f 427/2312/7214 1107/2306/7214 1898/2314/7214 +f 1899/2311/7215 427/2312/7215 3085/1084/7215 +f 427/2312/7216 1899/2311/7216 1276/2313/7216 +f 1519/1098/7217 428/2315/7217 2920/1099/7217 +f 428/2315/7218 1519/1098/7218 1517/2316/7218 +f 1900/1085/7219 428/2315/7219 2918/1086/7219 +f 428/2315/7220 1900/1085/7220 1898/2314/7220 +f 1903/2318/7221 429/2317/7221 2915/1068/7221 +f 429/2317/7222 1903/2318/7222 1901/1074/7222 +f 1104/2319/7223 429/2317/7223 2917/1081/7223 +f 429/2317/7224 1104/2319/7224 1102/1069/7224 +f 979/2322/7225 430/2320/7225 2524/1034/7225 +f 430/2320/7226 979/2322/7226 1902/2323/7226 +f 1903/2318/7227 430/2320/7227 3086/1075/7227 +f 430/2320/7228 1903/2318/7228 1514/2321/7228 +f 1391/234/7229 431/2324/7229 2792/235/7229 +f 431/2324/7230 1391/234/7230 1389/2108/7230 +f 1904/1076/7231 431/2324/7231 2790/1077/7231 +f 431/2324/7232 1904/1076/7232 1902/2323/7232 +f 1907/2328/7233 432/2325/7233 2712/2327/7233 +f 432/2325/7234 1907/2328/7234 1905/1065/7234 +f 1103/2329/7235 432/2325/7235 2916/1072/7235 +f 432/2325/7236 1103/2329/7236 899/2326/7236 +f 869/2334/7237 433/2331/7237 2401/2333/7237 +f 433/2331/7238 869/2334/7238 1906/2335/7238 +f 1907/2328/7239 433/2331/7239 3087/1066/7239 +f 433/2331/7240 1907/2328/7240 1311/2332/7240 +f 1281/1035/7241 434/2336/7241 2682/1036/7241 +f 434/2336/7242 1281/1035/7242 1514/2321/7242 +f 1908/1067/7243 434/2336/7243 2915/1068/7243 +f 434/2336/7244 1908/1067/7244 1906/2335/7244 +f 1911/2340/7245 435/2337/7245 2602/2339/7245 +f 435/2337/7246 1911/2340/7246 1909/1056/7246 +f 1312/2341/7247 435/2337/7247 2713/1063/7247 +f 789/2338/7248 435/2337/7248 2382/2342/7248 +f 1103/2329/7249 436/2343/7249 2444/2330/7249 +f 436/2343/7250 1103/2329/7250 1910/2345/7250 +f 1911/2340/7251 436/2343/7251 3088/1057/7251 +f 436/2343/7252 1911/2340/7252 1201/2344/7252 +f 1515/1071/7253 437/2346/7253 2916/1072/7253 +f 437/2346/7254 1515/1071/7254 1513/2347/7254 +f 1912/1058/7255 437/2346/7255 2914/1059/7255 +f 437/2346/7256 1912/1058/7256 1910/2345/7256 +f 1915/2349/7257 438/2348/7257 2911/1041/7257 +f 438/2348/7258 1915/2349/7258 1913/1047/7258 +f 1100/2350/7259 438/2348/7259 2913/1054/7259 +f 438/2348/7260 1100/2350/7260 1098/1042/7260 +f 941/2353/7261 439/2351/7261 2486/1142/7261 +f 439/2351/7262 941/2353/7262 1914/2354/7262 +f 1915/2349/7263 439/2351/7263 3089/1048/7263 +f 439/2351/7264 1915/2349/7264 1510/2352/7264 +f 1353/198/7265 440/2355/7265 2754/199/7265 +f 440/2355/7266 1353/198/7266 1390/2356/7266 +f 1916/1049/7267 440/2355/7267 2791/1050/7267 +f 440/2355/7268 1916/1049/7268 1914/2354/7268 +f 1919/2360/7269 441/2357/7269 2739/2359/7269 +f 441/2357/7270 1919/2360/7270 1917/1038/7270 +f 1099/2361/7271 441/2357/7271 2912/1045/7271 +f 441/2357/7272 1099/2361/7272 926/2358/7272 +f 831/2259/7273 442/2363/7273 2394/2260/7273 +f 442/2363/7274 831/2259/7274 1918/2365/7274 +f 1919/2360/7275 442/2363/7275 3090/1039/7275 +f 442/2363/7276 1919/2360/7276 1338/2364/7276 +f 1243/1143/7277 443/2366/7277 2644/1144/7277 +f 443/2366/7278 1243/1143/7278 1510/2352/7278 +f 1920/1040/7279 443/2366/7279 2911/1041/7279 +f 443/2366/7280 1920/1040/7280 1918/2365/7280 +f 1923/2370/7281 444/2367/7281 2629/2369/7281 +f 444/2367/7282 1923/2370/7282 1921/1029/7282 +f 869/2334/7283 444/2367/7283 2682/1036/7283 +f 444/2367/7284 869/2334/7284 816/2368/7284 +f 1099/2361/7285 445/2371/7285 2471/2362/7285 +f 445/2371/7286 1099/2361/7286 1922/2373/7286 +f 1923/2370/7287 445/2371/7287 3091/1030/7287 +f 445/2371/7288 1923/2370/7288 1228/2372/7288 +f 1511/1044/7289 446/2374/7289 2912/1045/7289 +f 446/2374/7290 1511/1044/7290 1509/2375/7290 +f 1924/1031/7291 446/2374/7291 2910/1032/7291 +f 446/2374/7292 1924/1031/7292 1922/2373/7292 +f 1927/2377/7293 447/2376/7293 2907/1014/7293 +f 447/2376/7294 1927/2377/7294 1925/1020/7294 +f 1096/2378/7295 447/2376/7295 2909/1027/7295 +f 447/2376/7296 1096/2378/7296 1094/1015/7296 +f 956/2381/7297 448/2379/7297 2501/1277/7297 +f 448/2379/7298 956/2381/7298 1926/2382/7298 +f 1927/2377/7299 448/2379/7299 3092/1021/7299 +f 448/2379/7300 1927/2377/7300 1506/2380/7300 +f 1368/153/7301 449/2383/7301 2769/154/7301 +f 449/2383/7302 1368/153/7302 1366/2384/7302 +f 1928/1022/7303 449/2383/7303 2767/1023/7303 +f 449/2383/7304 1928/1022/7304 1926/2382/7304 +f 1931/2386/7305 450/2385/7305 2791/1050/7305 +f 450/2385/7306 1931/2386/7306 1929/1011/7306 +f 1095/2387/7307 450/2385/7307 2908/1018/7307 +f 450/2385/7308 1095/2387/7308 978/1051/7308 +f 846/2138/7309 451/2388/7309 2427/197/7309 +f 451/2388/7310 846/2138/7310 1930/2389/7310 +f 1931/2386/7311 451/2388/7311 3093/1012/7311 +f 451/2388/7312 1931/2386/7312 1390/2356/7312 +f 1258/1278/7313 452/2390/7313 2659/1279/7313 +f 452/2390/7314 1258/1278/7314 1506/2380/7314 +f 1932/1013/7315 452/2390/7315 2907/1014/7315 +f 452/2390/7316 1932/1013/7316 1930/2389/7316 +f 1935/2392/7317 453/2391/7317 2681/231/7317 +f 453/2391/7318 1935/2392/7318 1933/1002/7318 +f 870/2109/7319 453/2391/7319 2683/1009/7319 +f 453/2391/7320 870/2109/7320 868/232/7320 +f 1095/2387/7321 454/2393/7321 2523/1052/7321 +f 454/2393/7322 1095/2387/7322 1934/2395/7322 +f 1935/2392/7323 454/2393/7323 3094/1003/7323 +f 454/2393/7324 1935/2392/7324 1280/2394/7324 +f 1507/1017/7325 455/2396/7325 2908/1018/7325 +f 455/2396/7326 1507/1017/7326 1505/2397/7326 +f 1936/1004/7327 455/2396/7327 2906/1005/7327 +f 455/2396/7328 1936/1004/7328 1934/2395/7328 +f 456/2399/7329 1090/988/7329 1939/2398/7329 +f 1937/993/4325 456/2399/4325 3095/994/4325 +f 456/2399/4326 1937/993/4326 1092/2400/4326 +f 1090/988/7330 456/2399/7330 2574/989/7330 +f 457/2404/7331 1502/2401/7331 983/2402/7331 +f 457/2404/4329 983/2402/4329 1938/2403/4329 +f 457/2404/4330 1938/2403/4330 1939/2398/4330 +f 1502/2401/4331 457/2404/4331 2903/987/4331 +f 1395/261/7332 458/2405/7332 2796/262/7332 +f 458/2405/7333 1395/261/7333 1393/2083/7333 +f 1940/995/7334 458/2405/7334 2794/996/7334 +f 458/2405/4335 1940/995/4335 1938/2403/4335 +f 459/2407/7335 936/1375/7335 1943/2406/7335 +f 1941/983/7336 459/2407/7336 3096/984/7336 +f 459/2407/7337 1941/983/7337 1091/2408/7337 +f 936/1375/7338 459/2407/7338 2481/1376/7338 +f 460/2410/7339 1348/2053/7339 873/2409/7339 +f 1942/2411/7340 460/2410/7340 2686/955/7340 +f 460/2410/7341 1942/2411/7341 1943/2406/7341 +f 1348/2053/7342 460/2410/7342 2749/1374/7342 +f 461/2412/7343 1942/2411/7343 1285/954/7343 +f 1502/2401/7344 461/2412/7344 2528/953/7344 +f 461/2412/7345 1502/2401/7345 1944/985/7345 +f 1942/2411/7346 461/2412/7346 3096/984/7346 +f 462/2414/7347 826/124/7347 1947/2413/7347 +f 1945/974/7348 462/2414/7348 3097/975/7348 +f 462/2414/7349 1945/974/7349 828/2415/7349 +f 826/124/7350 462/2414/7350 2407/125/7350 +f 463/2417/7351 1238/2416/7351 1091/2408/7351 +f 1946/2418/7352 463/2417/7352 2904/991/7352 +f 463/2417/7353 1946/2418/7353 1947/2413/7353 +f 1238/2416/7354 463/2417/7354 2639/123/7354 +f 464/2419/7355 1946/2418/7355 1503/990/7355 +f 1501/2420/7356 464/2419/7356 2574/989/7356 +f 464/2419/7357 1501/2420/7357 1948/976/7357 +f 1946/2418/7358 464/2419/7358 3097/975/7358 +f 465/2422/7359 1086/961/7359 1951/2421/7359 +f 1949/966/4361 465/2422/4361 3098/967/4361 +f 465/2422/4362 1949/966/4362 1088/2423/4362 +f 1086/961/7360 465/2422/7360 2573/962/7360 +f 466/2429/7361 1498/2424/7361 1216/2426/7361 +f 466/2429/4365 1216/2426/4365 1950/2428/4365 +f 466/2429/4366 1950/2428/4366 1951/2421/4366 +f 1498/2424/4367 466/2429/4367 2899/960/4367 +f 804/2431/7362 467/2430/7362 2617/2427/7362 +f 467/2430/7363 804/2431/7363 1394/2433/7363 +f 1952/968/7364 467/2430/7364 2795/969/7364 +f 467/2430/4371 1952/968/4371 1950/2428/4371 +f 468/2435/7365 951/862/7365 1955/2434/7365 +f 1953/956/7366 468/2435/7366 3099/957/7366 +f 468/2435/7367 1953/956/7367 1087/2436/7367 +f 951/862/7368 468/2435/7368 2496/863/7368 +f 469/2440/7369 1363/2437/7369 1326/2439/7369 +f 1954/2442/7370 469/2440/7370 2727/2441/7370 +f 469/2440/7371 1954/2442/7371 1955/2434/7371 +f 1363/2437/7372 469/2440/7372 2764/861/7372 +f 470/2444/7373 1954/2442/7373 914/2443/7373 +f 1498/2424/7374 470/2444/7374 2459/2425/7374 +f 470/2444/7375 1498/2424/7375 1956/958/7375 +f 1954/2442/7376 470/2444/7376 3099/957/7376 +f 471/2446/7377 841/295/7377 1959/2445/7377 +f 1957/947/7378 471/2446/7378 3100/948/7378 +f 471/2446/7379 1957/947/7379 873/2409/7379 +f 841/295/7380 471/2446/7380 2422/296/7380 +f 472/2448/7381 1253/2447/7381 1087/2436/7381 +f 1958/2449/7382 472/2448/7382 2900/964/7382 +f 472/2448/7383 1958/2449/7383 1959/2445/7383 +f 1253/2447/7384 472/2448/7384 2654/294/7384 +f 473/2450/7385 1958/2449/7385 1499/963/7385 +f 1497/2451/7386 473/2450/7386 2573/962/7386 +f 473/2450/7387 1497/2451/7387 1960/949/7387 +f 1958/2449/7388 473/2450/7388 3100/948/7388 +f 1963/2453/7389 474/2452/7389 2895/933/7389 +f 474/2452/7390 1963/2453/7390 1961/939/7390 +f 1084/2454/7391 474/2452/7391 2897/946/7391 +f 474/2452/7392 1084/2454/7392 1082/934/7392 +f 1214/2458/7393 475/2455/7393 2457/2457/7393 +f 475/2455/7394 1214/2458/7394 1962/2460/7394 +f 1963/2453/7395 475/2455/7395 3101/940/7395 +f 475/2455/7396 1963/2453/7396 1494/2456/7396 +f 802/2462/7397 476/2461/7397 2615/2459/7397 +f 476/2461/7398 802/2462/7398 1346/2464/7398 +f 1964/941/7399 476/2461/7399 2747/942/7399 +f 476/2461/7400 1964/941/7400 1962/2460/7400 +f 1967/2466/7401 477/2465/7401 2795/969/7401 +f 477/2465/7402 1967/2466/7402 1965/930/7402 +f 1083/2467/7403 477/2465/7403 2896/937/7403 +f 477/2465/7404 1083/2467/7404 982/970/7404 +f 1324/2469/7405 478/2468/7405 2392/2432/7405 +f 478/2468/7406 1324/2469/7406 1966/2471/7406 +f 1967/2466/7407 478/2468/7407 3102/931/7407 +f 478/2468/7408 1967/2466/7408 1394/2433/7408 +f 912/2473/7409 479/2472/7409 2725/2470/7409 +f 479/2472/7410 912/2473/7410 1494/2456/7410 +f 1968/932/7411 479/2472/7411 2895/933/7411 +f 479/2472/7412 1968/932/7412 1966/2471/7412 +f 1971/2475/7413 480/2474/7413 2685/258/7413 +f 480/2474/7414 1971/2475/7414 1969/921/7414 +f 874/2084/7415 480/2474/7415 2687/928/7415 +f 480/2474/7416 874/2084/7416 872/259/7416 +f 1083/2467/7417 481/2476/7417 2527/971/7417 +f 481/2476/7418 1083/2467/7418 1970/2478/7418 +f 1971/2475/7419 481/2476/7419 3103/922/7419 +f 481/2476/7420 1971/2475/7420 1284/2477/7420 +f 1495/936/7421 482/2479/7421 2896/937/7421 +f 482/2479/7422 1495/936/7422 1493/2480/7422 +f 1972/923/7423 482/2479/7423 2894/924/7423 +f 482/2479/7424 1972/923/7424 1970/2478/7424 +f 483/2482/7425 1078/907/7425 1975/2481/7425 +f 1973/911/7426 483/2482/7426 3104/912/7426 +f 483/2482/7427 1973/911/7427 1080/2483/7427 +f 1078/907/7428 483/2482/7428 2571/908/7428 +f 484/2486/7429 1490/2484/7429 987/2485/7429 +f 1974/2487/7430 484/2486/7430 2800/289/7430 +f 484/2486/7431 1974/2487/7431 1975/2481/7431 +f 1490/2484/7432 484/2486/7432 2891/906/7432 +f 485/2488/7433 1974/2487/7433 1399/288/7433 +f 1397/2057/7434 485/2488/7434 2438/287/7434 +f 485/2488/7435 1397/2057/7435 1976/913/7435 +f 1974/2487/7436 485/2488/7436 3104/912/7436 +f 486/2492/7437 923/2489/7437 1979/2491/7437 +f 1977/902/7438 486/2492/7438 3105/903/7438 +f 486/2492/7439 1977/902/7439 1079/2493/7439 +f 923/2489/7440 486/2492/7440 2468/2494/7440 +f 487/2498/7441 1335/2495/7441 877/2497/7441 +f 1978/2499/7442 487/2498/7442 2690/874/7442 +f 487/2498/7443 1978/2499/7443 1979/2491/7443 +f 1335/2495/7444 487/2498/7444 2736/2490/7444 +f 488/2500/7445 1978/2499/7445 1289/873/7445 +f 1490/2484/7446 488/2500/7446 2532/872/7446 +f 488/2500/7447 1490/2484/7447 1980/904/7447 +f 1978/2499/7448 488/2500/7448 3105/903/7448 +f 489/2504/7449 813/2501/7449 1983/2503/7449 +f 1981/893/7450 489/2504/7450 3106/894/7450 +f 489/2504/7451 1981/893/7451 827/2505/7451 +f 813/2501/7452 489/2504/7452 2398/2506/7452 +f 490/2508/7453 1225/2507/7453 1079/2493/7453 +f 1982/2509/7454 490/2508/7454 2892/910/7454 +f 490/2508/7455 1982/2509/7455 1983/2503/7455 +f 1225/2507/7456 490/2508/7456 2626/2502/7456 +f 491/2510/7457 1982/2509/7457 1491/909/7457 +f 1489/2511/7458 491/2510/7458 2571/908/7458 +f 491/2510/7459 1489/2511/7459 1984/895/7459 +f 1982/2509/7460 491/2510/7460 3106/894/7460 +f 492/2513/7461 1074/880/7461 1987/2512/7461 +f 1985/884/7462 492/2513/7462 3107/885/7462 +f 492/2513/7463 1985/884/7463 1076/2514/7463 +f 1074/880/7464 492/2513/7464 2570/881/7464 +f 493/2518/7465 1486/2515/7465 1203/2517/7465 +f 1986/2520/7466 493/2518/7466 2604/2519/7466 +f 493/2518/7467 1986/2520/7467 1987/2512/7467 +f 1486/2515/7468 493/2518/7468 2887/879/7468 +f 494/2522/7469 1986/2520/7469 791/2521/7469 +f 1398/2524/7470 494/2522/7470 2413/2523/7470 +f 494/2522/7471 1398/2524/7471 1988/886/7471 +f 1986/2520/7472 494/2522/7472 3107/885/7472 +f 495/2528/7473 902/2525/7473 1991/2527/7473 +f 1989/875/7474 495/2528/7474 3108/876/7474 +f 495/2528/7475 1989/875/7475 1075/2529/7475 +f 902/2525/7476 495/2528/7476 2447/2530/7476 +f 1313/2534/7477 496/2531/7477 2381/2533/7477 +f 1990/2536/7478 496/2531/7478 2714/2535/7478 +f 496/2531/7479 1990/2536/7479 1991/2527/7479 +f 1314/2532/7480 496/2531/7480 2715/2526/7480 +f 497/2538/7481 1990/2536/7481 901/2537/7481 +f 1486/2515/7482 497/2538/7482 2446/2516/7482 +f 497/2538/7483 1486/2515/7483 1992/877/7483 +f 1990/2536/7484 497/2538/7484 3108/876/7484 +f 498/2542/7485 792/2539/7485 1995/2541/7485 +f 1993/866/7486 498/2542/7486 3109/867/7486 +f 498/2542/7487 1993/866/7487 877/2497/7487 +f 792/2539/7488 498/2542/7488 2412/2496/7488 +f 499/2544/7489 1204/2543/7489 1075/2529/7489 +f 1994/2545/7490 499/2544/7490 2888/883/7490 +f 499/2544/7491 1994/2545/7491 1995/2541/7491 +f 1204/2543/7492 499/2544/7492 2605/2540/7492 +f 500/2546/7493 1994/2545/7493 1487/882/7493 +f 1485/2547/7494 500/2546/7494 2570/881/7494 +f 500/2546/7495 1485/2547/7495 1996/868/7495 +f 1994/2545/7496 500/2546/7496 3109/867/7496 +f 501/2549/7497 1070/853/7497 1999/2548/7497 +f 1997/857/7498 501/2549/7498 3110/858/7498 +f 501/2549/7499 1997/857/7499 1072/2550/7499 +f 1070/853/7500 501/2549/7500 2569/854/7500 +f 502/2554/7501 1482/2551/7501 1226/2553/7501 +f 1998/2556/7502 502/2554/7502 2627/2555/7502 +f 502/2554/7503 1998/2556/7503 1999/2548/7503 +f 1482/2551/7504 502/2554/7504 2883/852/7504 +f 503/2558/7505 1998/2556/7505 814/2557/7505 +f 1363/2437/7506 503/2558/7506 2399/2438/7506 +f 503/2558/7507 1363/2437/7507 2000/859/7507 +f 1998/2556/7508 503/2558/7508 3110/858/7508 +f 504/2560/7509 986/889/7509 2003/2559/7509 +f 2001/848/7510 504/2560/7510 3111/849/7510 +f 504/2560/7511 2001/848/7511 1071/2561/7511 +f 986/889/7512 504/2560/7512 2531/890/7512 +f 505/2563/7513 1398/2524/7513 1336/2562/7513 +f 2002/2565/7514 505/2563/7514 2737/2564/7514 +f 505/2563/7515 2002/2565/7515 2003/2559/7515 +f 1398/2524/7516 505/2563/7516 2799/888/7516 +f 506/2567/7517 2002/2565/7517 924/2566/7517 +f 1482/2551/7518 506/2567/7518 2469/2552/7518 +f 506/2567/7519 1482/2551/7519 2004/850/7519 +f 2002/2565/7520 506/2567/7520 3111/849/7520 +f 507/2569/7521 876/286/7521 2007/2568/7521 +f 2005/839/7522 507/2569/7522 3112/840/7522 +f 507/2569/7523 2005/839/7523 878/2058/7523 +f 876/286/7524 507/2569/7524 2438/287/7524 +f 508/2571/7525 1288/2570/7525 1071/2561/7525 +f 2006/2572/7526 508/2571/7526 2884/856/7526 +f 508/2571/7527 2006/2572/7527 2007/2568/7527 +f 1288/2570/7528 508/2571/7528 2689/285/7528 +f 509/2573/7529 2006/2572/7529 1483/855/7529 +f 1481/2574/7530 509/2573/7530 2569/854/7530 +f 509/2573/7531 1481/2574/7531 2008/841/7531 +f 2006/2572/7532 509/2573/7532 3112/840/7532 +f 510/2576/7533 1066/826/7533 2011/2575/7533 +f 2009/830/7534 510/2576/7534 3113/831/7534 +f 510/2576/7535 2009/830/7535 1068/2577/7535 +f 1066/826/7536 510/2576/7536 2568/827/7536 +f 511/2580/7537 1478/2578/7537 991/2579/7537 +f 2010/2581/7538 511/2580/7538 2804/316/7538 +f 511/2580/7539 2010/2581/7539 2011/2575/7539 +f 1478/2578/7540 511/2580/7540 2879/825/7540 +f 512/2582/7541 2010/2581/7541 1403/315/7541 +f 1401/2032/7542 512/2582/7542 2439/314/7542 +f 512/2582/7543 1401/2032/7543 2012/832/7543 +f 2010/2581/7544 512/2582/7544 3113/831/7544 +f 513/2586/7545 911/2583/7545 2015/2585/7545 +f 2013/821/7546 513/2586/7546 3114/822/7546 +f 513/2586/7547 2013/821/7547 1067/2587/7547 +f 911/2583/7548 513/2586/7548 2456/2588/7548 +f 514/2592/7549 1323/2589/7549 881/2591/7549 +f 2014/2593/7550 514/2592/7550 2694/793/7550 +f 514/2592/7551 2014/2593/7551 2015/2585/7551 +f 1323/2589/7552 514/2592/7552 2724/2584/7552 +f 515/2594/7553 2014/2593/7553 1293/792/7553 +f 1478/2578/7554 515/2594/7554 2536/791/7554 +f 515/2594/7555 1478/2578/7555 2016/823/7555 +f 2014/2593/7556 515/2594/7556 3114/822/7556 +f 516/2598/4564 801/2595/4564 2019/2597/4564 +f 2017/812/4565 516/2598/4565 3115/813/4565 +f 807/2284/7557 516/2598/7557 2620/820/7557 +f 516/2598/4567 807/2284/4567 801/2595/4567 +f 517/2600/7558 1213/2599/7558 1067/2587/7558 +f 2018/2601/7559 517/2600/7559 2880/829/7559 +f 517/2600/7560 2018/2601/7560 2019/2597/7560 +f 1213/2599/4571 517/2600/4571 2614/2596/4571 +f 518/2602/7561 2018/2601/7561 1479/828/7561 +f 1477/2603/7562 518/2602/7562 2568/827/7562 +f 518/2602/7563 1477/2603/7563 2020/814/7563 +f 2018/2601/7564 518/2602/7564 3115/813/7564 +f 519/2605/7565 1062/799/7565 2023/2604/7565 +f 2021/803/7566 519/2605/7566 3116/804/7566 +f 519/2605/7567 2021/803/7567 1064/2606/7567 +f 1062/799/7568 519/2605/7568 2567/800/7568 +f 520/2609/7569 1474/2607/7569 937/2608/7569 +f 2022/2610/7570 520/2609/7570 2750/280/7570 +f 520/2609/7571 2022/2610/7571 2023/2604/7571 +f 1474/2607/7572 520/2609/7572 2875/798/7572 +f 521/2611/7573 2022/2610/7573 1349/279/7573 +f 1402/2612/7574 521/2611/7574 2423/278/7574 +f 521/2611/7575 1402/2612/7575 2024/805/7575 +f 2022/2610/7576 521/2611/7576 3116/804/7576 +f 522/2616/7577 922/2613/7577 2027/2615/7577 +f 2025/794/7578 522/2616/7578 3117/795/7578 +f 522/2616/7579 2025/794/7579 1063/2617/7579 +f 922/2613/7580 522/2616/7580 2467/2618/7580 +f 523/2620/7581 1334/2619/7581 827/2505/7581 +f 2026/2621/7582 523/2620/7582 2640/901/7582 +f 523/2620/7583 2026/2621/7583 2027/2615/7583 +f 1334/2619/7584 523/2620/7584 2735/2614/7584 +f 524/2622/7585 2026/2621/7585 1239/900/7585 +f 1474/2607/7586 524/2622/7586 2482/899/7586 +f 524/2622/7587 1474/2607/7587 2028/796/7587 +f 2026/2621/7588 524/2622/7588 3117/795/7588 +f 525/2626/7589 812/2623/7589 2031/2625/7589 +f 2029/785/7590 525/2626/7590 3118/786/7590 +f 525/2626/7591 2029/785/7591 881/2591/7591 +f 812/2623/7592 525/2626/7592 2397/2590/7592 +f 526/2628/7593 1224/2627/7593 1063/2617/7593 +f 2030/2629/7594 526/2628/7594 2876/802/7594 +f 526/2628/7595 2030/2629/7595 2031/2625/7595 +f 1224/2627/7596 526/2628/7596 2625/2624/7596 +f 527/2630/7597 2030/2629/7597 1475/801/7597 +f 1473/2631/7598 527/2630/7598 2567/800/7598 +f 527/2630/7599 1473/2631/7599 2032/787/7599 +f 2030/2629/7600 527/2630/7600 3118/786/7600 +f 528/2633/7601 1058/772/7601 2035/2632/7601 +f 2033/776/7602 528/2633/7602 3119/777/7602 +f 528/2633/7603 2033/776/7603 1060/2634/7603 +f 1058/772/7604 528/2633/7604 2566/773/7604 +f 529/2637/7605 1470/2635/7605 952/2636/7605 +f 2034/2638/7606 529/2637/7606 2765/127/7606 +f 529/2637/7607 2034/2638/7607 2035/2632/7607 +f 1470/2635/7608 529/2637/7608 2871/771/7608 +f 530/2639/7609 2034/2638/7609 1364/126/7609 +f 1362/2640/7610 530/2639/7610 2407/125/7610 +f 530/2639/7611 1362/2640/7611 2036/778/7611 +f 2034/2638/7612 530/2639/7612 3119/777/7612 +f 531/2642/7613 990/808/7613 2039/2641/7613 +f 2037/767/7614 531/2642/7614 3120/768/7614 +f 531/2642/7615 2037/767/7615 1059/2643/7615 +f 990/808/7616 531/2642/7616 2535/809/7616 +f 532/2644/7617 1402/2612/7617 842/2064/7617 +f 2038/2645/7618 532/2644/7618 2655/1360/7618 +f 532/2644/7619 2038/2645/7619 2039/2641/7619 +f 1402/2612/7620 532/2644/7620 2803/807/7620 +f 533/2646/7621 2038/2645/7621 1254/1359/7621 +f 1470/2635/7622 533/2646/7622 2497/1358/7622 +f 533/2646/7623 1470/2635/7623 2040/769/7623 +f 2038/2645/7624 533/2646/7624 3120/768/7624 +f 534/2648/7625 880/313/7625 2043/2647/7625 +f 2041/758/7626 534/2648/7626 3121/759/7626 +f 534/2648/7627 2041/758/7627 882/2033/7627 +f 880/313/7628 534/2648/7628 2439/314/7628 +f 535/2650/7629 1292/2649/7629 1059/2643/7629 +f 2042/2651/7630 535/2650/7630 2872/775/7630 +f 535/2650/7631 2042/2651/7631 2043/2647/7631 +f 1292/2649/7632 535/2650/7632 2693/312/7632 +f 536/2652/7633 2042/2651/7633 1471/774/7633 +f 1469/2653/7634 536/2652/7634 2566/773/7634 +f 536/2652/7635 1469/2653/7635 2044/760/7635 +f 2042/2651/7636 536/2652/7636 3121/759/7636 +f 2047/2655/7637 537/2654/7637 2867/744/7637 +f 537/2654/7638 2047/2655/7638 2045/750/7638 +f 1056/2656/7639 537/2654/7639 2869/757/7639 +f 537/2654/7640 1056/2656/7640 1054/745/7640 +f 995/2659/7641 538/2657/7641 2540/710/7641 +f 538/2657/7642 995/2659/7642 2046/2660/7642 +f 2047/2655/7643 538/2657/7643 3122/751/7643 +f 538/2657/7644 2047/2655/7644 1466/2658/7644 +f 1407/342/7645 539/2661/7645 2808/343/7645 +f 539/2661/7646 1407/342/7646 1405/1984/7646 +f 2048/752/7647 539/2661/7647 2806/753/7647 +f 539/2661/7648 2048/752/7648 2046/2660/7648 +f 2051/2663/7649 540/2662/7649 2741/1347/7649 +f 540/2662/7650 2051/2663/7650 2049/741/7650 +f 1055/2664/7651 540/2662/7651 2868/748/7651 +f 540/2662/7652 1055/2664/7652 928/1348/7652 +f 885/2666/7653 541/2665/7653 2416/269/7653 +f 541/2665/7654 885/2666/7654 2050/2667/7654 +f 2051/2663/7655 541/2665/7655 3123/742/7655 +f 541/2665/7656 2051/2663/7656 1340/2078/7656 +f 1297/711/7657 542/2668/7657 2698/712/7657 +f 542/2668/7658 1297/711/7658 1466/2658/7658 +f 2052/743/7659 542/2668/7659 2867/744/7659 +f 542/2668/7660 2052/743/7660 2050/2667/7660 +f 2055/2670/7661 543/2669/7661 2631/132/7661 +f 543/2669/7662 2055/2670/7662 2053/732/7662 +f 823/2671/7663 543/2669/7663 2636/739/7663 +f 543/2669/7664 823/2671/7664 818/133/7664 +f 1055/2664/7665 544/2672/7665 2473/1349/7665 +f 544/2672/7666 1055/2664/7666 2054/2674/7666 +f 2055/2670/7667 544/2672/7667 3124/733/7667 +f 544/2672/7668 2055/2670/7668 1230/2673/7668 +f 1467/747/7669 545/2675/7669 2868/748/7669 +f 545/2675/7670 1467/747/7670 1465/2676/7670 +f 2056/734/7671 545/2675/7671 2866/735/7671 +f 545/2675/7672 2056/734/7672 2054/2674/7672 +f 2059/2678/7673 546/2677/7673 2863/717/7673 +f 546/2677/7674 2059/2678/7674 2057/723/7674 +f 1052/2679/7675 546/2677/7675 2865/730/7675 +f 546/2677/7676 1052/2679/7676 1050/718/7676 +f 1206/2683/7677 547/2680/7677 2449/2682/7677 +f 547/2680/7678 1206/2683/7678 2058/2685/7678 +f 2059/2678/7679 547/2680/7679 3125/724/7679 +f 547/2680/7680 2059/2678/7680 1462/2681/7680 +f 794/2687/7681 548/2686/7681 2607/2684/7681 +f 548/2686/7682 794/2687/7682 1406/2689/7682 +f 2060/725/7683 548/2686/7683 2807/726/7683 +f 548/2686/7684 2060/725/7684 2058/2685/7684 +f 2063/2691/7685 549/2690/7685 2747/942/7685 +f 549/2690/7686 2063/2691/7686 2061/714/7686 +f 1051/2692/7687 549/2690/7687 2864/721/7687 +f 549/2690/7688 1051/2692/7688 934/943/7688 +f 1316/2694/7689 550/2693/7689 2390/2463/7689 +f 550/2693/7690 1316/2694/7690 2062/2696/7690 +f 2063/2691/7691 550/2693/7691 3126/715/7691 +f 550/2693/7692 2063/2691/7692 1346/2464/7692 +f 904/2698/7693 551/2697/7693 2717/2695/7693 +f 551/2697/7694 904/2698/7694 1462/2681/7694 +f 2064/716/7695 551/2697/7695 2863/717/7695 +f 551/2697/7696 2064/716/7696 2062/2696/7696 +f 2067/2700/7697 552/2699/7697 2637/267/7697 +f 552/2699/7698 2067/2700/7698 2065/705/7698 +f 885/2666/7699 552/2699/7699 2698/712/7699 +f 552/2699/7700 885/2666/7700 824/268/7700 +f 1051/2692/7701 553/2701/7701 2479/944/7701 +f 553/2701/7702 1051/2692/7702 2066/2703/7702 +f 2067/2700/7703 553/2701/7703 3127/706/7703 +f 553/2701/7704 2067/2700/7704 1236/2702/7704 +f 1463/720/7705 554/2704/7705 2864/721/7705 +f 554/2704/7706 1463/720/7706 1461/2705/7706 +f 2068/707/7707 554/2704/7707 2862/708/7707 +f 554/2704/7708 2068/707/7708 2066/2703/7708 +f 2071/2707/7709 555/2706/7709 2859/690/7709 +f 555/2706/7710 2071/2707/7710 2069/696/7710 +f 1048/2708/7711 555/2706/7711 2861/703/7711 +f 555/2706/7712 1048/2708/7712 1046/691/7712 +f 1222/2712/7713 556/2709/7713 2465/2711/7713 +f 556/2709/7714 1222/2712/7714 2070/2714/7714 +f 2071/2707/7715 556/2709/7715 3128/697/7715 +f 556/2709/7716 2071/2707/7716 1458/2710/7716 +f 810/2716/7717 557/2715/7717 2623/2713/7717 +f 1360/2718/7718 557/2715/7718 2395/2717/7718 +f 2072/698/7719 557/2715/7719 2761/699/7719 +f 557/2715/7720 2072/698/7720 2070/2714/7720 +f 2075/2720/7721 558/2719/7721 2807/726/7721 +f 558/2719/7722 2075/2720/7722 2073/687/7722 +f 1047/2721/7723 558/2719/7723 2860/694/7723 +f 558/2719/7724 1047/2721/7724 994/727/7724 +f 1332/2723/7725 559/2722/7725 2410/2688/7725 +f 559/2722/7726 1332/2723/7726 2074/2725/7726 +f 2075/2720/7727 559/2722/7727 3129/688/7727 +f 559/2722/7728 2075/2720/7728 1406/2689/7728 +f 920/2727/7729 560/2726/7729 2733/2724/7729 +f 560/2726/7730 920/2727/7730 1458/2710/7730 +f 2076/689/7731 560/2726/7731 2859/690/7731 +f 560/2726/7732 2076/689/7732 2074/2725/7732 +f 2079/2729/7733 561/2728/7733 2697/339/7733 +f 561/2728/7734 2079/2729/7734 2077/678/7734 +f 886/1985/7735 561/2728/7735 2699/685/7735 +f 561/2728/7736 886/1985/7736 884/340/7736 +f 1047/2721/7737 562/2730/7737 2539/728/7737 +f 562/2730/7738 1047/2721/7738 2078/2732/7738 +f 2079/2729/7739 562/2730/7739 3130/679/7739 +f 562/2730/7740 2079/2729/7740 1296/2731/7740 +f 1459/693/7741 563/2733/7741 2860/694/7741 +f 563/2733/7742 1459/693/7742 1457/2734/7742 +f 2080/680/7743 563/2733/7743 2858/681/7743 +f 563/2733/7744 2080/680/7744 2078/2732/7744 +f 2083/2736/7745 564/2735/7745 2855/663/7745 +f 564/2735/7746 2083/2736/7746 2081/669/7746 +f 1044/2737/7747 564/2735/7747 2857/676/7747 +f 564/2735/7748 1044/2737/7748 1042/664/7748 +f 999/2740/7749 565/2738/7749 2544/629/7749 +f 565/2738/7750 999/2740/7750 2082/2741/7750 +f 2083/2736/7751 565/2738/7751 3131/670/7751 +f 565/2738/7752 2083/2736/7752 1454/2739/7752 +f 1411/369/7753 566/2742/7753 2812/370/7753 +f 566/2742/7754 1411/369/7754 1409/1960/7754 +f 2084/671/7755 566/2742/7755 2810/672/7755 +f 566/2742/7756 2084/671/7756 2082/2741/7756 +f 2087/2744/7757 567/2743/7757 2729/1536/7757 +f 567/2743/7758 2087/2744/7758 2085/660/7758 +f 1043/2745/7759 567/2743/7759 2856/667/7759 +f 567/2743/7760 1043/2745/7760 916/1537/7760 +f 889/2747/7761 568/2746/7761 2386/404/7761 +f 568/2746/7762 889/2747/7762 2086/2748/7762 +f 2087/2744/7763 568/2746/7763 3132/661/7763 +f 568/2746/7764 2087/2744/7764 1328/1907/7764 +f 1301/630/7765 569/2749/7765 2702/631/7765 +f 569/2749/7766 1301/630/7766 1454/2739/7766 +f 2088/662/7767 569/2749/7767 2855/663/7767 +f 569/2749/7768 2088/662/7768 2086/2748/7768 +f 570/2751/4780 806/70/4780 2091/2750/4780 +f 2089/650/4781 570/2751/4781 3133/651/4781 +f 570/2751/7769 2089/650/7769 808/1840/7769 +f 806/70/7770 570/2751/7770 2393/71/7770 +f 1043/2745/7771 571/2752/7771 2461/1538/7771 +f 571/2752/7772 1043/2745/7772 2090/2754/7772 +f 2091/2750/7773 571/2752/7773 3133/651/7773 +f 571/2752/7774 2091/2750/7774 1218/2753/7774 +f 1455/666/7775 572/2755/7775 2856/667/7775 +f 572/2755/7776 1455/666/7776 1453/2756/7776 +f 2092/652/7777 572/2755/7777 2854/654/7777 +f 572/2755/7778 2092/652/7778 2090/2754/7778 +f 2095/2758/7779 573/2757/7779 2851/636/7779 +f 573/2757/7780 2095/2758/7780 2093/642/7780 +f 1040/2759/7781 573/2757/7781 2853/649/7781 +f 573/2757/7782 1040/2759/7782 1038/637/7782 +f 933/2762/7783 574/2760/7783 2478/737/7783 +f 574/2760/7784 933/2762/7784 2094/2763/7784 +f 2095/2758/7785 574/2760/7785 3134/643/7785 +f 574/2760/7786 2095/2758/7786 1450/2761/7786 +f 1345/333/7787 575/2764/7787 2746/334/7787 +f 575/2764/7788 1345/333/7788 1410/2765/7788 +f 2096/644/7789 575/2764/7789 2811/645/7789 +f 575/2764/7790 2096/644/7790 2094/2763/7790 +f 2099/2767/7791 576/2766/7791 2721/537/7791 +f 576/2766/7792 2099/2767/7792 2097/633/7792 +f 1039/2768/7793 576/2766/7793 2852/640/7793 +f 576/2766/7794 1039/2768/7794 908/538/7794 +f 823/2671/7795 577/2769/7795 2403/134/7795 +f 577/2769/7796 823/2671/7796 2098/2771/7796 +f 2099/2767/7797 577/2769/7797 3135/634/7797 +f 577/2769/7798 2099/2767/7798 1320/2770/7798 +f 1235/738/7799 578/2772/7799 2636/739/7799 +f 578/2772/7800 1235/738/7800 1450/2761/7800 +f 2100/635/7801 578/2772/7801 2851/636/7801 +f 578/2772/7802 2100/635/7802 2098/2771/7802 +f 2103/2774/7803 579/2773/7803 2611/402/7803 +f 579/2773/7804 2103/2774/7804 2101/624/7804 +f 889/2747/7805 579/2773/7805 2702/631/7805 +f 579/2773/7806 889/2747/7806 798/403/7806 +f 1039/2768/7807 580/2775/7807 2453/539/7807 +f 580/2775/7808 1039/2768/7808 2102/2777/7808 +f 2103/2774/7809 580/2775/7809 3136/625/7809 +f 580/2775/7810 2103/2774/7810 1210/2776/7810 +f 1451/639/7811 581/2778/7811 2852/640/7811 +f 581/2778/7812 1451/639/7812 1449/2779/7812 +f 2104/626/7813 581/2778/7813 2850/627/7813 +f 581/2778/7814 2104/626/7814 2102/2777/7814 +f 2107/2781/7815 582/2780/7815 2847/609/7815 +f 582/2780/7816 2107/2781/7816 2105/615/7816 +f 1036/2782/7817 582/2780/7817 2849/622/7817 +f 582/2780/7818 1036/2782/7818 1034/610/7818 +f 949/2785/7819 583/2783/7819 2494/1439/7819 +f 583/2783/7820 949/2785/7820 2106/2786/7820 +f 2107/2781/7821 583/2783/7821 3137/616/7821 +f 583/2783/7822 2107/2781/7822 1446/2784/7822 +f 1361/99/7823 584/2787/7823 2762/100/7823 +f 584/2787/7824 1361/99/7824 1359/2788/7824 +f 2108/617/7825 584/2787/7825 2760/618/7825 +f 584/2787/7826 2108/617/7826 2106/2786/7826 +f 2111/2790/7827 585/2789/7827 2811/645/7827 +f 585/2789/7828 2111/2790/7828 2109/606/7828 +f 1035/2791/7829 585/2789/7829 2848/613/7829 +f 585/2789/7830 1035/2791/7830 998/646/7830 +f 839/1990/7831 586/2792/7831 2420/332/7831 +f 586/2792/7832 839/1990/7832 2110/2793/7832 +f 2111/2790/7833 586/2792/7833 3138/607/7833 +f 586/2792/7834 2111/2790/7834 1410/2765/7834 +f 1251/1440/7835 587/2794/7835 2652/1441/7835 +f 587/2794/7836 1251/1440/7836 1446/2784/7836 +f 2112/608/7837 587/2794/7837 2847/609/7837 +f 587/2794/7838 2112/608/7838 2110/2793/7838 +f 2115/2796/7839 588/2795/7839 2701/366/7839 +f 588/2795/7840 2115/2796/7840 2113/597/7840 +f 890/1961/7841 588/2795/7841 2703/604/7841 +f 588/2795/7842 890/1961/7842 888/367/7842 +f 1035/2791/7843 589/2797/7843 2543/647/7843 +f 589/2797/7844 1035/2791/7844 2114/2799/7844 +f 2115/2796/7845 589/2797/7845 3139/598/7845 +f 589/2797/7846 2115/2796/7846 1300/2798/7846 +f 1447/612/7847 590/2800/7847 2848/613/7847 +f 590/2800/7848 1447/612/7848 1445/2801/7848 +f 2116/599/7849 590/2800/7849 2846/600/7849 +f 590/2800/7850 2116/599/7850 2114/2799/7850 +f 591/2803/4864 1030/583/4864 2119/2802/4864 +f 2117/588/4865 591/2803/4865 3140/589/4865 +f 591/2803/4866 2117/588/4866 1032/2804/4866 +f 1030/583/7851 591/2803/7851 2559/584/7851 +f 592/2808/4868 1442/2805/4868 1003/2806/4868 +f 592/2808/4869 1003/2806/4869 2118/2807/4869 +f 592/2808/4870 2118/2807/4870 2119/2802/4870 +f 1442/2805/7852 592/2808/7852 2843/582/7852 +f 1415/396/4872 593/2809/4872 2816/397/4872 +f 593/2809/7853 1415/396/7853 1413/1912/7853 +f 2120/590/7854 593/2809/7854 2814/591/7854 +f 593/2809/7855 2120/590/7855 2118/2807/7855 +f 594/2811/7856 935/1402/7856 2123/2810/7856 +f 2121/578/7857 594/2811/7857 3141/579/7857 +f 594/2811/7858 2121/578/7858 1031/2812/7858 +f 935/1402/7859 594/2811/7859 2480/1403/7859 +f 595/2814/7860 1347/2028/7860 893/2813/7860 +f 2122/2815/7861 595/2814/7861 2706/550/7861 +f 595/2814/7862 2122/2815/7862 2123/2810/7862 +f 1347/2028/7863 595/2814/7863 2748/1401/7863 +f 596/2816/7864 2122/2815/7864 1305/549/7864 +f 1442/2805/7865 596/2816/7865 2548/548/7865 +f 596/2816/7866 1442/2805/7866 2124/580/7866 +f 2122/2815/7867 596/2816/7867 3141/579/7867 +f 597/2818/4888 825/115/4888 2127/2817/4888 +f 597/2818/4889 2127/2817/4889 2125/570/4889 +f 819/1936/4890 597/2818/4890 2632/577/4890 +f 597/2818/7868 819/1936/7868 825/115/7868 +f 598/2820/7869 1237/2819/7869 1031/2812/7869 +f 2126/2821/7870 598/2820/7870 2844/586/7870 +f 598/2820/4894 2126/2821/4894 2127/2817/4894 +f 1237/2819/7871 598/2820/7871 2638/114/7871 +f 599/2822/7872 2126/2821/7872 1443/585/7872 +f 1441/2823/7873 599/2822/7873 2559/584/7873 +f 599/2822/4898 1441/2823/4898 2128/572/4898 +f 2126/2821/7874 599/2822/7874 3142/571/7874 +f 600/2825/7875 1026/556/7875 2131/2824/7875 +f 2129/561/4901 600/2825/4901 3143/562/4901 +f 600/2825/4902 2129/561/4902 1028/2826/4902 +f 1026/556/7876 600/2825/7876 2558/557/7876 +f 601/2829/7877 1438/2827/7877 938/2828/7877 +f 2130/2830/4905 601/2829/4905 2751/253/4905 +f 601/2829/4906 2130/2830/4906 2131/2824/4906 +f 1438/2827/7878 601/2829/7878 2839/555/7878 +f 1350/252/7879 602/2831/7879 2751/253/7879 +f 602/2831/7880 1350/252/7880 1414/2832/7880 +f 2132/563/7881 602/2831/7881 2815/564/7881 +f 602/2831/7882 2132/563/7882 2130/2830/7882 +f 603/2834/7883 950/781/7883 2135/2833/7883 +f 2133/551/7884 603/2834/7884 3144/552/7884 +f 603/2834/7885 2133/551/7885 1027/2835/7885 +f 950/781/7886 603/2834/7886 2495/782/7886 +f 604/2836/7887 1362/2640/7887 828/2415/7887 +f 2134/2837/7888 604/2836/7888 2641/982/7888 +f 604/2836/7889 2134/2837/7889 2135/2833/7889 +f 1362/2640/7890 604/2836/7890 2763/780/7890 +f 605/2838/7891 2134/2837/7891 1240/981/7891 +f 1438/2827/7892 605/2838/7892 2483/980/7892 +f 605/2838/7893 1438/2827/7893 2136/553/7893 +f 2134/2837/7894 605/2838/7894 3144/552/7894 +f 606/2840/7895 840/322/7895 2139/2839/7895 +f 2137/542/7896 606/2840/7896 3145/543/7896 +f 606/2840/7897 2137/542/7897 893/2813/7897 +f 840/322/7898 606/2840/7898 2421/323/7898 +f 607/2842/7899 1252/2841/7899 1027/2835/7899 +f 2138/2843/7900 607/2842/7900 2840/559/7900 +f 607/2842/7901 2138/2843/7901 2139/2839/7901 +f 1252/2841/7902 607/2842/7902 2653/321/7902 +f 608/2844/7903 2138/2843/7903 1439/558/7903 +f 1437/2845/7904 608/2844/7904 2558/557/7904 +f 608/2844/7905 1437/2845/7905 2140/544/7905 +f 2138/2843/7906 608/2844/7906 3145/543/7906 +f 2143/2847/7907 609/2846/7907 2835/528/7907 +f 609/2846/7908 2143/2847/7908 2141/534/7908 +f 1024/2848/7909 609/2846/7909 2837/541/7909 +f 609/2846/7910 1024/2848/7910 1022/529/7910 +f 953/2851/7911 610/2849/7911 2498/1331/7911 +f 610/2849/7912 953/2851/7912 2142/2852/7912 +f 2143/2847/7913 610/2849/7913 3146/535/7913 +f 610/2849/7914 2143/2847/7914 1434/2850/7914 +f 1365/135/7915 611/2853/7915 2766/136/7915 +f 611/2853/7916 1365/135/7916 1320/2770/7916 +f 2144/536/7917 611/2853/7917 2721/537/7917 +f 611/2853/7918 2144/536/7918 2142/2852/7918 +f 2147/2855/7919 612/2854/7919 2815/564/7919 +f 612/2854/7920 2147/2855/7920 2145/525/7920 +f 1023/2856/7921 612/2854/7921 2836/532/7921 +f 612/2854/7922 1023/2856/7922 1002/565/7922 +f 843/2089/7923 613/2857/7923 2424/251/7923 +f 613/2857/7924 843/2089/7924 2146/2858/7924 +f 2147/2855/7925 613/2857/7925 3147/526/7925 +f 613/2857/7926 2147/2855/7926 1414/2832/7926 +f 1255/1332/7927 614/2859/7927 2656/1333/7927 +f 614/2859/7928 1255/1332/7928 1434/2850/7928 +f 2148/527/7929 614/2859/7929 2835/528/7929 +f 614/2859/7930 2148/527/7930 2146/2858/7930 +f 2151/2861/7931 615/2860/7931 2705/393/7931 +f 615/2860/7932 2151/2861/7932 2149/516/7932 +f 894/1913/7933 615/2860/7933 2707/523/7933 +f 615/2860/7934 894/1913/7934 892/394/7934 +f 1023/2856/7935 616/2862/7935 2547/566/7935 +f 616/2862/7936 1023/2856/7936 2150/2864/7936 +f 2151/2861/7937 616/2862/7937 3148/517/7937 +f 616/2862/7938 2151/2861/7938 1304/2863/7938 +f 1435/531/7939 617/2865/7939 2836/532/7939 +f 617/2865/7940 1435/531/7940 1433/2866/7940 +f 2152/518/7941 617/2865/7941 2834/519/7941 +f 617/2865/7942 2152/518/7942 2150/2864/7942 +f 2155/2868/7943 618/2867/7943 2831/501/7943 +f 618/2867/4973 2155/2868/4973 2153/506/4973 +f 618/2867/4974 2153/506/4974 1020/2869/4974 +f 618/2867/4975 1020/2869/4975 1018/502/4975 +f 1007/2872/7944 619/2870/7944 2552/467/7944 +f 619/2870/4977 1007/2872/4977 2154/2873/4977 +f 619/2870/4978 2154/2873/4978 2155/2868/4978 +f 619/2870/7945 2155/2868/7945 1430/2871/7945 +f 620/2874/7946 2154/2873/7946 1419/423/7946 +f 1417/1886/7947 620/2874/7947 2443/422/7947 +f 620/2874/7948 1417/1886/7948 2156/508/7948 +f 2154/2873/7949 620/2874/7949 3149/507/7949 +f 2159/2876/7950 621/2875/7950 2752/1320/7950 +f 621/2875/7951 2159/2876/7951 2157/498/7951 +f 1019/2877/7952 621/2875/7952 2832/505/7952 +f 621/2875/7953 1019/2877/7953 939/1321/7953 +f 897/2879/7954 622/2878/7954 2425/242/7954 +f 622/2878/7955 897/2879/7955 2158/2880/7955 +f 2159/2876/7956 622/2878/7956 3150/499/7956 +f 622/2878/7957 2159/2876/7957 1351/2103/7957 +f 1309/468/7958 623/2881/7958 2710/469/7958 +f 623/2881/7959 1309/468/7959 1430/2871/7959 +f 2160/500/7960 623/2881/7960 2831/501/7960 +f 623/2881/7961 2160/500/7961 2158/2880/7961 +f 2163/2883/7962 624/2882/7962 2642/141/7962 +f 624/2882/7963 2163/2883/7963 2161/489/7963 +f 1322/2884/7964 624/2882/7964 2723/496/7964 +f 624/2882/7965 1322/2884/7965 829/142/7965 +f 1019/2877/7966 625/2885/7966 2484/1322/7966 +f 625/2885/7967 1019/2877/7967 2162/2887/7967 +f 2163/2883/7968 625/2885/7968 3151/490/7968 +f 625/2885/7969 2163/2883/7969 1241/2886/7969 +f 1431/504/7970 626/2888/7970 2832/505/7970 +f 626/2888/7971 1431/504/7971 1429/2889/7971 +f 2164/491/7972 626/2888/7972 2830/492/7972 +f 626/2888/7973 2164/491/7973 2162/2887/7973 +f 2167/2891/7974 627/2890/7974 2827/474/7974 +f 627/2890/5009 2167/2891/5009 2165/479/5009 +f 627/2890/5010 2165/479/5010 1016/2892/5010 +f 627/2890/5011 1016/2892/5011 1014/475/5011 +f 942/2895/7975 628/2893/7975 2487/1412/7975 +f 628/2893/5013 942/2895/5013 2166/2896/5013 +f 628/2893/5014 2166/2896/5014 2167/2891/5014 +f 628/2893/7976 2167/2891/7976 1426/2894/7976 +f 629/2897/7977 2166/2896/7977 1354/108/7977 +f 1418/2898/7978 629/2897/7978 2428/107/7978 +f 629/2897/7979 1418/2898/7979 2168/481/7979 +f 2166/2896/7980 629/2897/7980 3152/480/7980 +f 2171/2900/7981 630/2899/7981 2767/1023/7981 +f 630/2899/7982 2171/2900/7982 2169/471/7982 +f 1015/2901/7983 630/2899/7983 2828/478/7983 +f 630/2899/7984 1015/2901/7984 954/1024/7984 +f 832/2014/7985 631/2902/7985 2408/152/7985 +f 631/2902/7986 832/2014/7986 2170/2903/7986 +f 2171/2900/7987 631/2902/7987 3153/472/7987 +f 631/2902/7988 2171/2900/7988 1366/2384/7988 +f 1244/1413/7989 632/2904/7989 2645/1414/7989 +f 632/2904/7990 1244/1413/7990 1426/2894/7990 +f 2172/473/7991 632/2904/7991 2827/474/7991 +f 632/2904/7992 2172/473/7992 2170/2903/7992 +f 2175/2906/7993 633/2905/7993 2657/240/7993 +f 633/2905/7994 2175/2906/7994 2173/462/7994 +f 897/2879/7995 633/2905/7995 2710/469/7995 +f 633/2905/7996 897/2879/7996 844/241/7996 +f 1015/2901/7997 634/2907/7997 2499/1025/7997 +f 634/2907/7998 1015/2901/7998 2174/2909/7998 +f 2175/2906/7999 634/2907/7999 3154/463/7999 +f 634/2907/8000 2175/2906/8000 1256/2908/8000 +f 1427/477/8001 635/2910/8001 2828/478/8001 +f 635/2910/8002 1427/477/8002 1425/2911/8002 +f 2176/464/8003 635/2910/8003 2826/465/8003 +f 635/2910/8004 2176/464/8004 2174/2909/8004 +f 636/2913/8005 1010/448/8005 2179/2912/8005 +f 2177/452/8006 636/2913/8006 3155/453/8006 +f 636/2913/8007 2177/452/8007 1012/2914/8007 +f 1010/448/8008 636/2913/8008 2554/449/8008 +f 637/2917/8009 1422/2915/8009 957/2916/8009 +f 2178/2918/8010 637/2917/8010 2770/163/8010 +f 637/2917/8011 2178/2918/8011 2179/2912/8011 +f 1422/2915/8012 637/2917/8012 2823/447/8012 +f 638/2919/8013 2178/2918/8013 1369/162/8013 +f 1321/1742/8014 638/2919/8014 2402/161/8014 +f 638/2919/8015 1321/1742/8015 2180/454/8015 +f 2178/2918/8016 638/2919/8016 3155/453/8016 +f 639/2921/8017 1006/484/8017 2183/2920/8017 +f 2181/443/8018 639/2921/8018 3156/444/8018 +f 639/2921/8019 2181/443/8019 1011/2922/8019 +f 1006/484/8020 639/2921/8020 2551/485/8020 +f 640/2923/8021 1418/2898/8021 847/2160/8021 +f 2182/2924/8022 640/2923/8022 2660/1252/8022 +f 640/2923/8023 2182/2924/8023 2183/2920/8023 +f 1418/2898/8024 640/2923/8024 2819/483/8024 +f 641/2925/8025 2182/2924/8025 1259/1251/8025 +f 1422/2915/8026 641/2925/8026 2502/1250/8026 +f 641/2925/8027 1422/2915/8027 2184/445/8027 +f 2182/2924/8028 641/2925/8028 3156/444/8028 +f 642/2927/8029 896/421/8029 2187/2926/8029 +f 2185/434/8030 642/2927/8030 3157/435/8030 +f 642/2927/8031 2185/434/8031 898/1887/8031 +f 896/421/8032 642/2927/8032 2443/422/8032 +f 643/2929/8033 1308/2928/8033 1011/2922/8033 +f 2186/2930/8034 643/2929/8034 2824/451/8034 +f 643/2929/8035 2186/2930/8035 2187/2926/8035 +f 1308/2928/8036 643/2929/8036 2709/420/8036 +f 644/2931/8037 2186/2930/8037 1423/450/8037 +f 1421/2932/8038 644/2931/8038 2554/449/8038 +f 644/2931/8039 1421/2932/8039 2188/436/8039 +f 2186/2930/8040 644/2931/8040 3157/435/8040 +f 645/2934/8041 1009/439/8041 2191/2933/8041 +f 2189/425/8042 645/2934/8042 3158/426/8042 +f 645/2934/8043 2189/425/8043 1008/1879/8043 +f 1009/439/8044 645/2934/8044 2553/440/8044 +f 646/2935/8045 1421/2932/8045 1012/2914/8045 +f 2190/2936/8046 646/2935/8046 2825/460/8046 +f 646/2935/8047 2190/2936/8047 2191/2933/8047 +f 1421/2932/8048 646/2935/8048 2822/438/8048 +f 647/2937/8049 2190/2936/8049 1424/459/8049 +f 1211/1750/8050 647/2937/8050 2454/458/8050 +f 647/2937/8051 1211/1750/8051 2192/427/8051 +f 2190/2936/8052 647/2937/8052 3158/426/8052 +f 2195/2939/8053 648/2938/8053 2826/465/8053 +f 2193/416/5093 648/2938/5093 3159/417/5093 +f 648/2938/5094 2193/416/5094 1007/2872/5094 +f 648/2938/8054 1007/2872/8054 1013/466/8054 +f 1016/2892/8055 649/2940/8055 2555/476/8055 +f 2194/2941/5097 649/2940/5097 2829/487/5097 +f 649/2940/5098 2194/2941/5098 2195/2939/5098 +f 649/2940/8056 2195/2939/8056 1425/2911/8056 +f 650/2942/8057 2194/2941/8057 1428/486/8057 +f 1308/2928/8058 650/2942/8058 2551/485/8058 +f 650/2942/8059 1308/2928/8059 2196/418/8059 +f 2194/2941/8060 650/2942/8060 3159/417/8060 +f 2199/2944/5104 651/2943/5104 2830/492/5104 +f 651/2943/5105 2199/2944/5105 2197/407/5105 +f 651/2943/5106 2197/407/5106 1212/2945/5106 +f 651/2943/8061 1212/2945/8061 1017/493/8061 +f 1020/2869/8062 652/2946/8062 2556/503/8062 +f 652/2946/5109 1020/2869/5109 2198/2947/5109 +f 2199/2944/5110 652/2946/5110 3160/408/5110 +f 652/2946/5111 2199/2944/5111 1429/2889/5111 +f 653/2948/8063 2198/2947/8063 1432/513/8063 +f 1307/1894/8064 653/2948/8064 2550/512/8064 +f 653/2948/8065 1307/1894/8065 2200/409/8065 +f 2198/2947/5115 653/2948/5115 3160/408/5115 +f 2203/2950/8066 654/2949/8066 2834/519/8066 +f 654/2949/8067 2203/2950/8067 2201/399/8067 +f 1004/1904/8068 654/2949/8068 2817/406/8068 +f 654/2949/8069 1004/1904/8069 1021/520/8069 +f 1024/2848/8070 655/2951/8070 2557/530/8070 +f 655/2951/8071 1024/2848/8071 2202/2952/8071 +f 2203/2950/8072 655/2951/8072 3161/400/8072 +f 655/2951/8073 2203/2950/8073 1433/2866/8073 +f 1436/540/8074 656/2953/8074 2837/541/8074 +f 656/2953/8075 1436/540/8075 1210/2776/8075 +f 2204/401/8076 656/2953/8076 2611/402/8076 +f 656/2953/8077 2204/401/8077 2202/2952/8077 +f 657/2955/5128 1025/547/5128 2207/2954/5128 +f 657/2955/5129 2207/2954/5129 2205/390/5129 +f 657/2955/5130 2205/390/5130 1003/2806/5130 +f 1025/547/8078 657/2955/8078 2548/548/8078 +f 658/2956/5132 1437/2845/5132 1028/2826/5132 +f 2206/2957/5133 658/2956/5133 2841/568/5133 +f 658/2956/5134 2206/2957/5134 2207/2954/5134 +f 1437/2845/8079 658/2956/8079 2838/546/8079 +f 1440/567/5136 659/2958/5136 2841/568/5136 +f 659/2958/8080 1440/567/8080 1304/2863/8080 +f 2208/392/8081 659/2958/8081 2705/393/8081 +f 659/2958/8082 2208/392/8082 2206/2957/8082 +f 660/2960/5140 1029/574/5140 2211/2959/5140 +f 2209/380/5141 660/2960/5141 3163/381/5141 +f 660/2960/5142 2209/380/5142 929/1928/5142 +f 660/2960/5143 929/1928/5143 1029/574/5143 +f 661/2962/5144 1441/2823/5144 1032/2804/5144 +f 661/2962/5145 1032/2804/5145 2210/2961/5145 +f 661/2962/5146 2210/2961/5146 2211/2959/5146 +f 1441/2823/5147 661/2962/5147 2842/573/5147 +f 1444/594/5148 662/2963/5148 2845/595/5148 +f 662/2963/8083 1444/594/8083 1303/1919/8083 +f 2212/382/8084 662/2963/8084 2704/384/8084 +f 662/2963/5151 2212/382/5151 2210/2961/5151 +f 2215/2965/8085 663/2964/8085 2846/600/8085 +f 663/2964/8086 2215/2965/8086 2213/372/8086 +f 1000/1952/8087 663/2964/8087 2813/379/8087 +f 663/2964/8088 1000/1952/8088 1033/601/8088 +f 1036/2782/8089 664/2966/8089 2560/611/8089 +f 664/2966/8090 1036/2782/8090 2214/2967/8090 +f 2215/2965/8091 664/2966/8091 3164/373/8091 +f 664/2966/8092 2215/2965/8092 1445/2801/8092 +f 1448/621/8093 665/2968/8093 2849/622/8093 +f 665/2968/8094 1448/621/8094 1249/2969/8094 +f 2216/374/8095 665/2968/8095 2650/375/8095 +f 665/2968/8096 2216/374/8096 2214/2967/8096 +f 2219/2971/8097 666/2970/8097 2850/627/8097 +f 666/2970/8098 2219/2971/8098 2217/363/8098 +f 999/2740/8099 666/2970/8099 2812/370/8099 +f 666/2970/8100 999/2740/8100 1037/628/8100 +f 1040/2759/8101 667/2972/8101 2561/638/8101 +f 667/2972/8102 1040/2759/8102 2218/2973/8102 +f 2219/2971/8103 667/2972/8103 3165/364/8103 +f 667/2972/8104 2219/2971/8104 1449/2779/8104 +f 1452/648/8105 668/2974/8105 2853/649/8105 +f 668/2974/8106 1452/648/8106 1300/2798/8106 +f 2220/365/8107 668/2974/8107 2701/366/8107 +f 668/2974/8108 2220/365/8108 2218/2973/8108 +f 669/2976/5176 1041/655/5176 2223/2975/5176 +f 2221/353/5177 669/2976/5177 3166/354/5177 +f 669/2976/5178 2221/353/5178 918/1833/5178 +f 1041/655/8109 669/2976/8109 2463/656/8109 +f 1044/2737/8110 670/2977/8110 2562/665/8110 +f 670/2977/8111 1044/2737/8111 2222/2978/8111 +f 2223/2975/5182 670/2977/5182 3166/354/5182 +f 670/2977/8112 2223/2975/8112 1453/2756/8112 +f 1456/675/8113 671/2979/8113 2857/676/8113 +f 671/2979/8114 1456/675/8114 1299/1967/8114 +f 2224/355/8115 671/2979/8115 2700/357/8115 +f 671/2979/5187 2224/355/5187 2222/2978/5187 +f 2227/2981/8116 672/2980/8116 2858/681/8116 +f 672/2980/8117 2227/2981/8117 2225/345/8117 +f 996/1976/8118 672/2980/8118 2809/352/8118 +f 672/2980/8119 996/1976/8119 1045/682/8119 +f 1048/2708/8120 673/2982/8120 2563/692/8120 +f 673/2982/8121 1048/2708/8121 2226/2983/8121 +f 2227/2981/8122 673/2982/8122 3167/346/8122 +f 673/2982/8123 2227/2981/8123 1457/2734/8123 +f 1460/702/8124 674/2984/8124 2861/703/8124 +f 674/2984/8125 1460/702/8125 1250/2985/8125 +f 2228/347/8126 674/2984/8126 2651/348/8126 +f 674/2984/8127 2228/347/8127 2226/2983/8127 +f 2231/2987/8128 675/2986/8128 2862/708/8128 +f 675/2986/8129 2231/2987/8129 2229/336/8129 +f 995/2659/8130 675/2986/8130 2808/343/8130 +f 675/2986/8131 995/2659/8131 1049/709/8131 +f 1052/2679/8132 676/2988/8132 2564/719/8132 +f 676/2988/8133 1052/2679/8133 2230/2989/8133 +f 2231/2987/8134 676/2988/8134 3168/337/8134 +f 676/2988/8135 2231/2987/8135 1461/2705/8135 +f 1464/729/8136 677/2990/8136 2865/730/8136 +f 677/2990/8137 1464/729/8137 1296/2731/8137 +f 2232/338/8138 677/2990/8138 2697/339/8138 +f 677/2990/8139 2232/338/8139 2230/2989/8139 +f 2235/2992/8140 678/2991/8140 2866/735/8140 +f 678/2991/8141 2235/2992/8141 2233/327/8141 +f 933/2762/8142 678/2991/8142 2746/334/8142 +f 678/2991/8143 933/2762/8143 1053/736/8143 +f 1056/2656/8144 679/2993/8144 2565/746/8144 +f 679/2993/8145 1056/2656/8145 2234/2994/8145 +f 2235/2992/8146 679/2993/8146 3169/328/8146 +f 679/2993/8147 2235/2992/8147 1465/2676/8147 +f 1468/756/8148 680/2995/8148 2869/757/8148 +f 680/2995/8149 1468/756/8149 1295/1992/8149 +f 2236/329/8150 680/2995/8150 2696/330/8150 +f 680/2995/8151 2236/329/8151 2234/2994/8151 +f 681/2997/8152 1057/763/8152 2239/2996/8152 +f 2237/317/8153 681/2997/8153 3170/318/8153 +f 681/2997/8154 2237/317/8154 992/2024/8154 +f 1057/763/8155 681/2997/8155 2537/764/8155 +f 682/2998/8156 1469/2653/8156 1060/2634/8156 +f 2238/2999/8157 682/2998/8157 2873/784/8157 +f 682/2998/8158 2238/2999/8158 2239/2996/8158 +f 1469/2653/8159 682/2998/8159 2870/762/8159 +f 683/3000/8160 2238/2999/8160 1472/783/8160 +f 1252/2841/8161 683/3000/8161 2495/782/8161 +f 683/3000/8162 1252/2841/8162 2240/319/8162 +f 2238/2999/8163 683/3000/8163 3170/318/8163 +f 684/3002/8164 1061/790/8164 2243/3001/8164 +f 2241/308/8165 684/3002/8165 3171/309/8165 +f 684/3002/8166 2241/308/8166 991/2579/8166 +f 1061/790/8167 684/3002/8167 2536/791/8167 +f 685/3003/8168 1473/2631/8168 1064/2606/8168 +f 2242/3004/8169 685/3003/8169 2877/811/8169 +f 685/3003/8170 2242/3004/8170 2243/3001/8170 +f 1473/2631/8171 685/3003/8171 2874/789/8171 +f 686/3005/8172 2242/3004/8172 1476/810/8172 +f 1292/2649/8173 686/3005/8173 2535/809/8173 +f 686/3005/8174 1292/2649/8174 2244/310/8174 +f 2242/3004/8175 686/3005/8175 3171/309/8175 +f 687/3007/5248 1065/817/5248 2247/3006/5248 +f 2245/299/5249 687/3007/5249 3172/300/5249 +f 917/2271/5250 687/3007/5250 2730/307/5250 +f 687/3007/5251 917/2271/5251 1065/817/5251 +f 688/3008/8176 1477/2603/8176 1068/2577/8176 +f 2246/3009/8177 688/3008/8177 2881/838/8177 +f 688/3008/5254 2246/3009/5254 2247/3006/5254 +f 1477/2603/5255 688/3008/5255 2878/816/5255 +f 689/3010/8178 2246/3009/8178 1480/837/8178 +f 1291/2040/8179 689/3010/8179 2534/836/8179 +f 689/3010/8180 1291/2040/8180 2248/301/8180 +f 2246/3009/8181 689/3010/8181 3172/300/8181 +f 690/3012/8182 1069/844/8182 2251/3011/8182 +f 2249/290/8183 690/3012/8183 3173/291/8183 +f 690/3012/8184 2249/290/8184 988/2049/8184 +f 1069/844/8185 690/3012/8185 2533/845/8185 +f 691/3013/8186 1481/2574/8186 1072/2550/8186 +f 2250/3014/8187 691/3013/8187 2885/865/8187 +f 691/3013/8188 2250/3014/8188 2251/3011/8188 +f 1481/2574/8189 691/3013/8189 2882/843/8189 +f 692/3015/8190 2250/3014/8190 1484/864/8190 +f 1253/2447/8191 692/3015/8191 2496/863/8191 +f 692/3015/8192 1253/2447/8192 2252/292/8192 +f 2250/3014/8193 692/3015/8193 3173/291/8193 +f 693/3017/8194 1073/871/8194 2255/3016/8194 +f 2253/281/8195 693/3017/8195 3174/282/8195 +f 693/3017/8196 2253/281/8196 987/2485/8196 +f 1073/871/8197 693/3017/8197 2532/872/8197 +f 694/3018/8198 1485/2547/8198 1076/2514/8198 +f 2254/3019/8199 694/3018/8199 2889/892/8199 +f 694/3018/8200 2254/3019/8200 2255/3016/8200 +f 1485/2547/8201 694/3018/8201 2886/870/8201 +f 695/3020/8202 2254/3019/8202 1488/891/8202 +f 1288/2570/8203 695/3020/8203 2531/890/8203 +f 695/3020/8204 1288/2570/8204 2256/283/8204 +f 2254/3019/8205 695/3020/8205 3174/282/8205 +f 696/3022/8206 1077/898/8206 2259/3021/8206 +f 2257/272/8207 696/3022/8207 3175/273/8207 +f 696/3022/8208 2257/272/8208 937/2608/8208 +f 1077/898/8209 696/3022/8209 2482/899/8209 +f 697/3023/8210 1489/2511/8210 1080/2483/8210 +f 2258/3024/8211 697/3023/8211 2893/919/8211 +f 697/3023/8212 2258/3024/8212 2259/3021/8212 +f 1489/2511/8213 697/3023/8213 2890/897/8213 +f 698/3025/8214 2258/3024/8214 1492/918/8214 +f 1287/2065/8215 698/3025/8215 2530/917/8215 +f 698/3025/8216 1287/2065/8216 2260/274/8216 +f 2258/3024/8217 698/3025/8217 3175/273/8217 +f 2263/3027/8218 699/3026/8218 2894/924/8218 +f 699/3026/8219 2263/3027/8219 2261/264/8219 +f 984/2075/8220 699/3026/8220 2797/271/8220 +f 699/3026/8221 984/2075/8221 1081/925/8221 +f 1084/2454/8222 700/3028/8222 2572/935/8222 +f 700/3028/8223 1084/2454/8223 2262/3029/8223 +f 2263/3027/8224 700/3028/8224 3176/265/8224 +f 700/3028/8225 2263/3027/8225 1493/2480/8225 +f 1496/945/8226 701/3030/8226 2897/946/8226 +f 701/3030/8227 1496/945/8227 1236/2702/8227 +f 2264/266/8228 701/3030/8228 2637/267/8228 +f 701/3030/8229 2264/266/8229 2262/3029/8229 +f 702/3032/8230 1085/952/8230 2267/3031/8230 +f 2265/255/5309 702/3032/5309 3177/256/5309 +f 983/2402/5310 702/3032/5310 2796/262/5310 +f 1085/952/8231 702/3032/8231 2528/953/8231 +f 703/3034/8232 1497/2451/8232 1088/2423/8232 +f 703/3034/5313 1088/2423/5313 2266/3033/5313 +f 703/3034/5314 2266/3033/5314 2267/3031/5314 +f 1497/2451/8233 703/3034/8233 2898/951/8233 +f 1500/972/8234 704/3035/8234 2901/973/8234 +f 704/3035/8235 1500/972/8235 1284/2477/8235 +f 2268/257/8236 704/3035/8236 2685/258/8236 +f 704/3035/8237 2268/257/8237 2266/3033/8237 +f 705/3037/5320 1089/979/5320 2271/3036/5320 +f 2269/246/5321 705/3037/5321 3178/247/5321 +f 938/2828/5322 705/3037/5322 2751/253/5322 +f 1089/979/8238 705/3037/8238 2483/980/8238 +f 706/3039/8239 1501/2420/8239 1092/2400/8239 +f 706/3039/5325 1092/2400/5325 2270/3038/5325 +f 2271/3036/5326 706/3039/5326 3178/247/5326 +f 1501/2420/5327 706/3039/5327 2902/978/5327 +f 1504/999/8240 707/3040/8240 2905/1000/8240 +f 707/3040/8241 1504/999/8241 1283/2091/8241 +f 2272/248/8242 707/3040/8242 2684/249/8242 +f 707/3040/5331 2272/248/5331 2270/3038/5331 +f 2275/3042/8243 708/3041/8243 2906/1005/8243 +f 708/3041/8244 2275/3042/8244 2273/237/8244 +f 980/2100/8245 708/3041/8245 2793/244/8245 +f 708/3041/8246 980/2100/8246 1093/1006/8246 +f 1096/2378/8247 709/3043/8247 2575/1016/8247 +f 709/3043/8248 1096/2378/8248 2274/3044/8248 +f 2275/3042/8249 709/3043/8249 3179/238/8249 +f 709/3043/8250 2275/3042/8250 1505/2397/8250 +f 1508/1026/8251 710/3045/8251 2909/1027/8251 +f 710/3045/8252 1508/1026/8252 1256/2908/8252 +f 2276/239/8253 710/3045/8253 2657/240/8253 +f 710/3045/8254 2276/239/8254 2274/3044/8254 +f 2279/3047/8255 711/3046/8255 2910/1032/8255 +f 711/3046/8256 2279/3047/8256 2277/228/8256 +f 979/2322/8257 711/3046/8257 2792/235/8257 +f 711/3046/8258 979/2322/8258 1097/1033/8258 +f 1100/2350/8259 712/3048/8259 2576/1043/8259 +f 712/3048/8260 1100/2350/8260 2278/3049/8260 +f 2279/3047/8261 712/3048/8261 3180/229/8261 +f 712/3048/8262 2279/3047/8262 1509/2375/8262 +f 1512/1053/8263 713/3050/8263 2913/1054/8263 +f 713/3050/8264 1512/1053/8264 1280/2394/8264 +f 2280/230/8265 713/3050/8265 2681/231/8265 +f 713/3050/8266 2280/230/8266 2278/3049/8266 +f 2283/3052/8267 714/3051/8267 2914/1059/8267 +f 714/3051/8268 2283/3052/8268 2281/219/8268 +f 1202/3053/8269 714/3051/8269 2603/226/8269 +f 714/3051/8270 1202/3053/8270 1101/1060/8270 +f 1104/2319/8271 715/3054/8271 2577/1070/8271 +f 715/3054/8272 1104/2319/8272 2282/3055/8272 +f 2283/3052/8273 715/3054/8273 3181/220/8273 +f 715/3054/8274 2283/3052/8274 1513/2347/8274 +f 1516/1080/8275 716/3056/8275 2917/1081/8275 +f 716/3056/8276 1516/1080/8276 1279/2116/8276 +f 2284/221/8277 716/3056/8277 2680/222/8277 +f 716/3056/8278 2284/221/8278 2282/3055/8278 +f 2287/3058/8279 717/3057/8279 2918/1086/8279 +f 717/3057/8280 2287/3058/8280 2285/210/8280 +f 976/2125/8281 717/3057/8281 2789/217/8281 +f 717/3057/8282 976/2125/8282 1105/1087/8282 +f 1108/2298/8283 718/3059/8283 2578/1097/8283 +f 718/3059/8284 1108/2298/8284 2286/3060/8284 +f 2287/3058/8285 718/3059/8285 3182/211/8285 +f 718/3059/8286 2287/3058/8286 1517/2316/8286 +f 1520/1107/8287 719/3061/8287 2921/1108/8287 +f 719/3061/8288 1520/1107/8288 1257/1943/8288 +f 2288/212/8289 719/3061/8289 2658/213/8289 +f 719/3061/8290 2288/212/8290 2286/3060/8290 +f 2291/3063/8291 720/3062/8291 2922/1113/8291 +f 720/3062/8292 2291/3063/8292 2289/201/8292 +f 975/2240/8293 720/3062/8293 2788/208/8293 +f 720/3062/8294 975/2240/8294 1109/1114/8294 +f 1112/2268/8295 721/3064/8295 2579/1124/8295 +f 721/3064/8296 1112/2268/8296 2290/3065/8296 +f 2291/3063/8297 721/3064/8297 3183/202/8297 +f 721/3064/8298 2291/3063/8298 1521/2295/8298 +f 1524/1134/8299 722/3066/8299 2925/1135/8299 +f 722/3066/8300 1524/1134/8300 1276/2313/8300 +f 2292/203/8301 722/3066/8301 2677/204/8301 +f 722/3066/8302 2292/203/8302 2290/3065/8302 +f 2295/3068/8303 723/3067/8303 2926/1140/8303 +f 723/3067/8304 2295/3068/8304 2293/192/8304 +f 941/2353/8305 723/3067/8305 2754/199/8305 +f 723/3067/8306 941/2353/8306 1113/1141/8306 +f 1116/2237/8307 724/3069/8307 2580/1151/8307 +f 724/3069/8308 1116/2237/8308 2294/3070/8308 +f 2295/3068/8309 724/3069/8309 3184/193/8309 +f 724/3069/8310 2295/3068/8310 1525/2265/8310 +f 1528/1161/8311 725/3071/8311 2929/1162/8311 +f 725/3071/8312 1528/1161/8312 1275/2140/8312 +f 2296/194/8313 725/3071/8313 2676/195/8313 +f 725/3071/8314 2296/194/8314 2294/3070/8314 +f 726/3073/8315 1117/1168/8315 2299/3072/8315 +f 2297/182/8316 726/3073/8316 3185/183/8316 +f 726/3073/8317 2297/182/8317 968/2170/8317 +f 1117/1168/8318 726/3073/8318 2513/1169/8318 +f 727/3074/8319 1529/2234/8319 1120/2215/8319 +f 2298/3075/8320 727/3074/8320 2933/1189/8320 +f 727/3074/8321 2298/3075/8321 2299/3072/8321 +f 1529/2234/8322 727/3074/8322 2930/1167/8322 +f 728/3076/8323 2298/3075/8323 1532/1188/8323 +f 1260/3077/8324 728/3076/8324 2503/1187/8324 +f 728/3076/8325 1260/3077/8325 2300/184/8325 +f 2298/3075/8326 728/3076/8326 3185/183/8326 +f 729/3079/8327 1121/1195/8327 2303/3078/8327 +f 2301/173/8328 729/3079/8328 3186/174/8328 +f 729/3079/8329 2301/173/8329 960/2217/8329 +f 1121/1195/8330 729/3079/8330 2505/1196/8330 +f 730/3080/8331 1533/2212/8331 1124/2192/8331 +f 2302/3081/8332 730/3080/8332 2937/1216/8332 +f 730/3080/8333 2302/3081/8333 2303/3078/8333 +f 1533/2212/8334 730/3080/8334 2934/1194/8334 +f 731/3082/8335 2302/3081/8335 1536/1215/8335 +f 1246/3083/8336 731/3082/8336 2489/1214/8336 +f 731/3082/8337 1246/3083/8337 2304/175/8337 +f 2302/3081/8338 731/3082/8338 3186/174/8338 +f 732/3085/8339 1125/1222/8339 2307/3084/8339 +f 2305/164/8340 732/3085/8340 3187/165/8340 +f 732/3085/8341 2305/164/8341 1223/3086/8341 +f 1125/1222/8342 732/3085/8342 2466/1223/8342 +f 733/3087/8343 1537/2189/8343 1128/2168/8343 +f 2306/3088/8344 733/3087/8344 2941/1243/8344 +f 733/3087/8345 2306/3088/8345 2307/3084/8345 +f 1537/2189/8346 733/3087/8346 2938/1221/8346 +f 734/3089/8347 2306/3088/8347 1540/1242/8347 +f 1245/3090/8348 734/3089/8348 2488/1241/8348 +f 734/3089/8349 1245/3090/8349 2308/166/8349 +f 2306/3088/8350 734/3089/8350 3187/165/8350 +f 735/3092/8351 1129/1249/8351 2311/3091/8351 +f 2309/155/8352 735/3092/8352 3188/156/8352 +f 735/3092/8353 2309/155/8353 957/2916/8353 +f 1129/1249/8354 735/3092/8354 2502/1250/8354 +f 736/3093/8355 1541/2165/8355 1132/2146/8355 +f 2310/3094/8356 736/3093/8356 2945/1270/8356 +f 736/3093/8357 2310/3094/8357 2311/3091/8357 +f 1541/2165/8358 736/3093/8358 2942/1248/8358 +f 737/3095/8359 2310/3094/8359 1544/1269/8359 +f 1229/1870/8360 737/3095/8360 2472/1268/8360 +f 737/3095/8361 1229/1870/8361 2312/157/8361 +f 2310/3094/8362 737/3095/8362 3188/156/8362 +f 2315/3097/8363 738/3096/8363 2946/1275/8363 +f 738/3096/8364 2315/3097/8364 2313/147/8364 +f 956/2381/8365 738/3096/8365 2769/154/8365 +f 738/3096/8366 956/2381/8366 1133/1276/8366 +f 1136/2122/8367 739/3098/8367 2585/1286/8367 +f 739/3098/8368 1136/2122/8368 2314/3099/8368 +f 2315/3097/8369 739/3098/8369 3189/148/8369 +f 739/3098/8370 2315/3097/8370 1545/2143/8370 +f 1548/1296/8371 740/3100/8371 2949/1297/8371 +f 740/3100/8372 1548/1296/8372 1242/2016/8372 +f 2316/149/8373 740/3100/8373 2643/150/8373 +f 740/3100/8374 2316/149/8374 2314/3099/8374 +f 2319/3102/8375 741/3101/8375 2950/1302/8375 +f 741/3101/8376 2319/3102/8376 2317/138/8376 +f 1227/3103/8377 741/3101/8377 2628/145/8377 +f 741/3101/8378 1227/3103/8378 1137/1303/8378 +f 1140/2097/8379 742/3104/8379 2586/1313/8379 +f 742/3104/8380 1140/2097/8380 2318/3105/8380 +f 2319/3102/8381 742/3104/8381 3190/139/8381 +f 742/3104/8382 2319/3102/8382 1549/2119/8382 +f 1552/1323/8383 743/3106/8383 2953/1324/8383 +f 743/3106/8384 1552/1323/8384 1241/2886/8384 +f 2320/140/8385 743/3106/8385 2642/141/8385 +f 743/3106/8386 2320/140/8386 2318/3105/8386 +f 2323/3108/8387 744/3107/8387 2954/1329/8387 +f 744/3107/8388 2323/3108/8388 2321/129/8388 +f 953/2851/8389 744/3107/8389 2766/136/8389 +f 744/3107/8390 953/2851/8390 1141/1330/8390 +f 1144/2072/8391 745/3109/8391 2587/1340/8391 +f 745/3109/8392 1144/2072/8392 2322/3110/8392 +f 2323/3108/8393 745/3109/8393 3191/130/8393 +f 745/3109/8394 2323/3108/8394 1553/2094/8394 +f 1556/1350/8395 746/3111/8395 2957/1351/8395 +f 746/3111/8396 1556/1350/8396 1230/2673/8396 +f 2324/131/8397 746/3111/8397 2631/132/8397 +f 746/3111/8398 2324/131/8398 2322/3110/8398 +f 747/3113/8399 1145/1357/8399 2327/3112/8399 +f 2325/119/8400 747/3113/8400 3192/120/8400 +f 747/3113/8401 2325/119/8401 952/2636/8401 +f 1145/1357/8402 747/3113/8402 2497/1358/8402 +f 748/3114/8403 1557/2069/8403 1148/2047/8403 +f 2326/3115/8404 748/3114/8404 2961/1378/8404 +f 748/3114/8405 2326/3115/8405 2327/3112/8405 +f 1557/2069/8406 748/3114/8406 2958/1356/8406 +f 749/3116/8407 2326/3115/8407 1560/1377/8407 +f 1238/2416/8408 749/3116/8408 2481/1376/8408 +f 749/3116/8409 1238/2416/8409 2328/121/8409 +f 2326/3115/8410 749/3116/8410 3192/120/8410 +f 750/3118/5500 1149/1384/5500 2331/3117/5500 +f 2329/110/5501 750/3118/5501 3193/111/5501 +f 907/2301/5502 750/3118/5502 2720/118/5502 +f 750/3118/8411 907/2301/8411 1149/1384/8411 +f 751/3119/8412 1561/2044/8412 1152/2022/8412 +f 2330/3120/8413 751/3119/8413 2965/1405/8413 +f 751/3119/5506 2330/3120/5506 2331/3117/5506 +f 1561/2044/8414 751/3119/8414 2962/1383/8414 +f 752/3121/8415 2330/3120/8415 1564/1404/8415 +f 1237/2819/8416 752/3121/8416 2480/1403/8416 +f 752/3121/5510 1237/2819/5510 2332/112/5510 +f 2330/3120/8417 752/3121/8417 3193/111/8417 +f 2335/3123/5512 753/3122/5512 2966/1410/5512 +f 753/3122/5513 2335/3123/5513 2333/101/5513 +f 753/3122/5514 2333/101/5514 942/2895/5514 +f 753/3122/5515 942/2895/5515 1153/1411/5515 +f 1156/1998/8418 754/3124/8418 2590/1421/8418 +f 2334/3125/5517 754/3124/5517 2969/1432/5517 +f 2335/3123/5518 754/3124/5518 3194/102/5518 +f 754/3124/8419 2335/3123/8419 1565/2019/8419 +f 755/3126/8420 2334/3125/8420 1568/1431/8420 +f 1271/2161/8421 755/3126/8421 2514/1430/8421 +f 755/3126/8422 1271/2161/8422 2336/103/8422 +f 2334/3125/8423 755/3126/8423 3194/102/8423 +f 2339/3128/8424 756/3127/8424 2970/1437/8424 +f 756/3127/8425 2339/3128/8425 2337/93/8425 +f 949/2785/8426 756/3127/8426 2762/100/8426 +f 756/3127/8427 949/2785/8427 1157/1438/8427 +f 1160/1973/8428 757/3129/8428 2591/1448/8428 +f 757/3129/8429 1160/1973/8429 2338/3130/8429 +f 2339/3128/8430 757/3129/8430 3195/94/8430 +f 757/3129/8431 2339/3128/8431 1569/1995/8431 +f 1572/1458/8432 758/3131/8432 2973/1459/8432 +f 758/3131/8433 1572/1458/8433 1234/3132/8433 +f 2340/95/8434 758/3131/8434 2635/96/8434 +f 758/3131/8435 2340/95/8435 2338/3130/8435 +f 759/3134/5536 1161/1465/5536 2343/3133/5536 +f 2341/83/5537 759/3134/5537 3196/84/5537 +f 759/3134/8436 2341/83/8436 906/1808/8436 +f 1161/1465/8437 759/3134/8437 2451/1466/8437 +f 1164/1949/8438 760/3135/8438 2592/1475/8438 +f 760/3135/8439 1164/1949/8439 2342/3136/8439 +f 2343/3133/8440 760/3135/8440 3196/84/8440 +f 760/3135/8441 2343/3133/8441 1573/1970/8441 +f 1576/1485/8442 761/3137/8442 2977/1486/8442 +f 761/3137/8443 1576/1485/8443 1233/3138/8443 +f 2344/85/8444 761/3137/8444 2634/87/8444 +f 761/3137/8445 2344/85/8445 2342/3136/8445 +f 2347/3140/5548 762/3139/5548 2978/1491/5548 +f 2345/74/5549 762/3139/5549 3197/75/5549 +f 762/3139/5550 2345/74/5550 971/2001/5550 +f 762/3139/8446 971/2001/8446 1165/1492/8446 +f 1168/1925/5552 763/3141/5552 2593/1502/5552 +f 2346/3142/5553 763/3141/5553 2981/1513/5553 +f 763/3141/5554 2346/3142/5554 2347/3140/5554 +f 763/3141/8447 2347/3140/8447 1577/1946/8447 +f 764/3143/5556 2346/3142/5556 1580/1512/5556 +f 1272/1799/8448 764/3143/8448 2515/1511/8448 +f 764/3143/8449 1272/1799/8449 2348/76/8449 +f 2346/3142/8450 764/3143/8450 3197/75/8450 +f 765/3145/5560 1169/1519/5560 2351/3144/5560 +f 765/3145/5561 2351/3144/5561 2349/65/5561 +f 765/3145/5562 2349/65/5562 930/1783/5562 +f 1169/1519/8451 765/3145/8451 2475/1520/8451 +f 1172/1901/8452 766/3146/8452 2594/1529/8452 +f 766/3146/8453 1172/1901/8453 2350/3147/8453 +f 2351/3144/5566 766/3146/5566 3198/66/5566 +f 766/3146/8454 2351/3144/8454 1581/1922/8454 +f 1584/1539/8455 767/3148/8455 2985/1540/8455 +f 767/3148/8456 1584/1539/8456 1218/2753/8456 +f 2352/67/5570 767/3148/5570 2619/69/5570 +f 767/3148/8457 2352/67/8457 2350/3147/8457 +f 768/3150/8458 1173/1546/8458 2355/3149/8458 +f 2353/56/8459 768/3150/8459 3199/57/8459 +f 768/3150/8460 2353/56/8460 1215/3151/8460 +f 1173/1546/8461 768/3150/8461 2458/1547/8461 +f 769/3152/8462 1585/1898/8462 1176/1877/8462 +f 2354/3153/8463 769/3152/8463 2989/1567/8463 +f 769/3152/8464 2354/3153/8464 2355/3149/8464 +f 1585/1898/8465 769/3152/8465 2986/1545/8465 +f 770/3154/8466 2354/3153/8466 1588/1566/8466 +f 1217/1774/8467 770/3154/8467 2460/1565/8467 +f 770/3154/8468 1217/1774/8468 2356/58/8468 +f 2354/3153/8469 770/3154/8469 3199/57/8469 +f 771/3156/8470 1177/1573/8470 2359/3155/8470 +f 2357/47/8471 771/3156/8471 3200/48/8471 +f 771/3156/8472 2357/47/8472 945/1734/8472 +f 1177/1573/8473 771/3156/8473 2490/1574/8473 +f 772/3157/8474 1589/1874/8474 1180/1854/8474 +f 2358/3158/8475 772/3157/8475 2993/1594/8475 +f 772/3157/8476 2358/3158/8476 2359/3155/8476 +f 1589/1874/8477 772/3157/8477 2990/1572/8477 +f 773/3159/8478 2358/3158/8478 1592/1593/8478 +f 1263/2208/8479 773/3159/8479 2506/1592/8479 +f 773/3159/8480 1263/2208/8480 2360/49/8480 +f 2358/3158/8481 773/3159/8481 3200/48/8481 +f 774/3161/8482 1181/1600/8482 2363/3160/8482 +f 2361/38/8483 774/3161/8483 3201/39/8483 +f 774/3161/8484 2361/38/8484 963/1856/8484 +f 1181/1600/8485 774/3161/8485 2508/1601/8485 +f 775/3162/8486 1593/1851/8486 1184/1831/8486 +f 2362/3163/8487 775/3162/8487 2997/1621/8487 +f 775/3162/8488 2362/3163/8488 2363/3160/8488 +f 1593/1851/8489 775/3162/8489 2994/1599/8489 +f 776/3164/8490 2362/3163/8490 1596/1620/8490 +f 1264/1824/8491 776/3164/8491 2507/1619/8491 +f 776/3164/8492 1264/1824/8492 2364/40/8492 +f 2362/3163/8493 776/3164/8493 3201/39/8493 +f 777/3166/8494 1185/1627/8494 2367/3165/8494 +f 2365/29/8495 777/3166/8495 3202/30/8495 +f 777/3166/8496 2365/29/8496 964/2194/8496 +f 1185/1627/8497 777/3166/8497 2509/1628/8497 +f 778/3167/8498 1597/1828/8498 1188/1806/8498 +f 2366/3168/8499 778/3167/8499 3001/1648/8499 +f 778/3167/8500 2366/3168/8500 2367/3165/8500 +f 1597/1828/8501 778/3167/8501 2998/1626/8501 +f 779/3169/8502 2366/3168/8502 1600/1647/8502 +f 1261/3170/8503 779/3169/8503 2504/1646/8503 +f 779/3169/8504 1261/3170/8504 2368/31/8504 +f 2366/3168/8505 779/3169/8505 3202/30/8505 +f 780/3172/8506 1189/1654/8506 2371/3171/8506 +f 2369/20/8507 780/3172/8507 3203/21/8507 +f 780/3172/8508 2369/20/8508 972/2148/8508 +f 1189/1654/8509 780/3172/8509 2517/1655/8509 +f 781/3173/8510 1601/1803/8510 1192/1781/8510 +f 2370/3174/8511 781/3173/8511 3005/1675/8511 +f 781/3173/8512 2370/3174/8512 2371/3171/8512 +f 1601/1803/8513 781/3173/8513 3002/1653/8513 +f 782/3175/8514 2370/3174/8514 1604/1674/8514 +f 1248/1847/8515 782/3175/8515 2491/1673/8515 +f 782/3175/8516 1248/1847/8516 2372/22/8516 +f 2370/3174/8517 782/3175/8517 3203/21/8517 +f 783/3177/8518 1193/1681/8518 2375/3176/8518 +f 2373/11/8519 783/3177/8519 3204/12/8519 +f 783/3177/8520 2373/11/8520 1205/3178/8520 +f 1193/1681/8521 783/3177/8521 2448/1682/8521 +f 784/3179/8522 1605/1778/8522 1196/1757/8522 +f 2374/3180/8523 784/3179/8523 3009/1702/8523 +f 784/3179/8524 2374/3180/8524 2375/3176/8524 +f 1605/1778/8525 784/3179/8525 3006/1680/8525 +f 785/3181/8526 2374/3180/8526 1608/1701/8526 +f 1267/2185/8527 785/3181/8527 2510/1700/8527 +f 785/3181/8528 1267/2185/8528 2376/13/8528 +f 2374/3180/8529 785/3181/8529 3204/12/8529 +f 786/3183/8530 1197/1708/8530 2379/3182/8530 +f 2377/2/8531 786/3183/8531 3205/3/8531 +f 786/3183/8532 2377/2/8532 967/1759/8532 +f 1197/1708/8533 786/3183/8533 2512/1709/8533 +f 787/3184/8534 1609/1754/8534 1200/1732/8534 +f 2378/3185/8535 787/3184/8535 3013/1729/8535 +f 787/3184/8536 2378/3185/8536 2379/3182/8536 +f 1609/1754/8537 787/3184/8537 3010/1707/8537 +f 788/3186/8538 2378/3185/8538 1612/1728/8538 +f 1268/2230/8539 788/3186/8539 2511/1727/8539 +f 788/3186/8540 1268/2230/8540 2380/4/8540 +f 2378/3185/8541 788/3186/8541 3205/3/8541 diff --git a/src/components/mappable.h b/src/components/mappable.h new file mode 100644 index 0000000..7530919 --- /dev/null +++ b/src/components/mappable.h @@ -0,0 +1,146 @@ +#ifndef MAPPABLE_H_0B0316FB +#define MAPPABLE_H_0B0316FB + +#include +#include "component.h" +#include "renderer.h" +#include "map.h" + +class MappableComponent : public Component { +public: + + class Boundary { + public: + + enum class Type { + wall, + wrap, + teleport, + reverse, + platform, + danger + }; + + Boundary( + double axis, + double lower, + double upper, + Type type) : + axis_(axis), + lower_(lower), + upper_(upper), + type_(type) + { + } + + inline double getAxis() const + { + return axis_; + } + + inline double getLower() const + { + return lower_; + } + + inline double getUpper() const + { + return upper_; + } + + inline Type getType() const + { + return type_; + } + + private: + + double axis_; + double lower_; + double upper_; + Type type_; + }; + + MappableComponent( + Texture tileset, + Texture font) : + tileset_(std::move(tileset)), + font_(std::move(font)) + { + } + + using asc_boundaries_type = + std::multimap< + double, + Boundary, + std::less>; + + using desc_boundaries_type = + std::multimap< + double, + Boundary, + std::greater>; + + inline size_t getMapId() const + { + return mapId_; + } + + inline void setMapId(size_t v) + { + mapId_ = v; + } + + inline desc_boundaries_type& getLeftBoundaries() + { + return leftBoundaries_; + } + + inline asc_boundaries_type& getRightBoundaries() + { + return rightBoundaries_; + } + + inline desc_boundaries_type& getUpBoundaries() + { + return upBoundaries_; + } + + inline asc_boundaries_type& getDownBoundaries() + { + return downBoundaries_; + } + + inline const Texture& getTileset() const + { + return tileset_; + } + + inline void setTileset(Texture v) + { + tileset_ = std::move(v); + } + + inline const Texture& getFont() const + { + return font_; + } + + inline void setFont(Texture v) + { + font_ = std::move(v); + } + +private: + + size_t mapId_ = -1; + + desc_boundaries_type leftBoundaries_; + asc_boundaries_type rightBoundaries_; + desc_boundaries_type upBoundaries_; + asc_boundaries_type downBoundaries_; + Texture tileset_; + Texture font_; +}; + +#endif /* end of include guard: MAPPABLE_H_0B0316FB */ diff --git a/src/components/ponderable.h b/src/components/ponderable.h index dfbf908..ac759b6 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -6,13 +6,27 @@ class PonderableComponent : public Component { public: - enum class state { + enum class Type { + vacuumed, + freefalling + }; + + enum class State { grounded, jumping, falling, dropping }; + PonderableComponent(Type type) : type_(type) + { + } + + inline Type getType() const + { + return type_; + } + inline double getVelocityX() const { return velX_; @@ -53,12 +67,12 @@ public: accelY_ = v; } - inline state getState() const + inline State getState() const { return state_; } - inline void setState(state arg) + inline void setState(State arg) { state_ = arg; } @@ -69,7 +83,8 @@ private: double velY_ = 0.0; double accelX_ = 0.0; double accelY_ = 0.0; - state state_ = state::grounded; + Type type_ = Type::vacuumed; + State state_ = State::grounded; }; #endif /* end of include guard: TANGIBLE_H_746DB3EE */ diff --git a/src/consts.h b/src/consts.h index 4595719..a6c9985 100644 --- a/src/consts.h +++ b/src/consts.h @@ -7,6 +7,9 @@ const int GAME_WIDTH = 320; const int GAME_HEIGHT = 200; const int MAP_WIDTH = GAME_WIDTH/TILE_WIDTH; const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT - 1; +const int WALL_GAP = 6; +const int TILESET_COLS = 8; +const int FONT_COLS = 16; const int FRAMES_PER_SECOND = 60; const double SECONDS_PER_FRAME = 1.0 / FRAMES_PER_SECOND; diff --git a/src/direction.h b/src/direction.h index 32d6b41..9a4c801 100644 --- a/src/direction.h +++ b/src/direction.h @@ -2,10 +2,10 @@ #define DIRECTION_H_9C49EAFD enum class Direction { - Left, - Right, - Up, - Down + left, + right, + up, + down }; #endif /* end of include guard: DIRECTION_H_9C49EAFD */ diff --git a/src/entity_manager.h b/src/entity_manager.h index 9068fe3..7fd82fc 100644 --- a/src/entity_manager.h +++ b/src/entity_manager.h @@ -106,7 +106,7 @@ public: { if ((entity >= entities.size()) || slotAvailable[entity]) { - throw std::invalid_argument("Cannot delete non-existent entity"); + throw std::invalid_argument("Cannot get non-existent entity"); } EntityData& data = entities[entity]; @@ -138,7 +138,7 @@ public: { if ((entity >= entities.size()) || slotAvailable[entity]) { - throw std::invalid_argument("Cannot delete non-existent entity"); + throw std::invalid_argument("Cannot get non-existent entity"); } EntityData& data = entities[entity]; @@ -167,7 +167,7 @@ public: { if ((entity >= entities.size()) || slotAvailable[entity]) { - throw std::invalid_argument("Cannot delete non-existent entity"); + throw std::invalid_argument("Cannot get non-existent entity"); } EntityData& data = entities[entity]; @@ -181,6 +181,20 @@ public: return *dynamic_cast(data.components[componentType].get()); } + template + bool hasComponent(id_type entity) + { + if ((entity >= entities.size()) || slotAvailable[entity]) + { + throw std::invalid_argument("Cannot get non-existent entity"); + } + + EntityData& data = entities[entity]; + std::type_index componentType = typeid(T); + + return data.components.count(componentType); + } + template std::set getEntitiesWithComponents() { diff --git a/src/game.cpp b/src/game.cpp index dfe700e..7cbe7e0 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -8,6 +8,7 @@ #include "systems/controlling.h" #include "systems/pondering.h" #include "systems/animating.h" +#include "systems/mapping.h" #include "animation.h" #include "renderer.h" #include "consts.h" @@ -26,10 +27,14 @@ void key_callback(GLFWwindow* window, int key, int, int action, int) game.systemManager_.input(key, action); } -Game::Game(GLFWwindow* window) : window_(window) +Game::Game( + GLFWwindow* window) : + window_(window), + world_("res/maps.xml") { systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); + systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); int player = entityManager_.emplaceEntity(); @@ -49,11 +54,16 @@ Game::Game(GLFWwindow* window) : window_(window) player, 203, 44, 10, 12); + systemManager_.getSystem().initializeBody( + player, + PonderableComponent::Type::freefalling); + entityManager_.emplaceComponent(player); - entityManager_.emplaceComponent(player); entityManager_.emplaceComponent(player); entityManager_.emplaceComponent(player); + systemManager_.getSystem().loadMap(world_.getStartingMapId()); + glfwSwapInterval(1); glfwSetWindowUserPointer(window_, this); glfwSetKeyCallback(window_, key_callback); diff --git a/src/game.h b/src/game.h index 7bd038e..346d67e 100644 --- a/src/game.h +++ b/src/game.h @@ -4,6 +4,7 @@ #include "renderer.h" #include "entity_manager.h" #include "system_manager.h" +#include "world.h" class Game { public: @@ -22,6 +23,11 @@ public: return systemManager_; } + inline const World& getWorld() + { + return world_; + } + friend void key_callback( GLFWwindow* window, int key, @@ -31,9 +37,10 @@ public: private: + GLFWwindow* const window_; EntityManager entityManager_; SystemManager systemManager_; - GLFWwindow* const window_; + World world_; bool shouldQuit_ = false; }; diff --git a/src/map.h b/src/map.h new file mode 100644 index 0000000..9177870 --- /dev/null +++ b/src/map.h @@ -0,0 +1,45 @@ +#ifndef MAP_H_74055FC0 +#define MAP_H_74055FC0 + +#include +#include +#include +#include +#include + +class Map { +public: + + Map( + int id, + std::vector tiles, + std::string title) : + id_(id), + tiles_(std::move(tiles)), + title_(std::move(title)) + { + } + + inline size_t getId() const + { + return id_; + } + + inline const std::vector& getTiles() const + { + return tiles_; + } + + inline const std::string& getTitle() const + { + return title_; + } + +private: + + int id_; + std::vector tiles_; + std::string title_; +}; + +#endif /* end of include guard: MAP_H_74055FC0 */ diff --git a/src/systems/controlling.cpp b/src/systems/controlling.cpp index 3647ff8..fa09d11 100644 --- a/src/systems/controlling.cpp +++ b/src/systems/controlling.cpp @@ -123,7 +123,7 @@ void ControllingSystem::walkLeft(id_type entity) auto& animating = game_.getSystemManager().getSystem(); - if (ponderable.getState() == PonderableComponent::state::grounded) + if (ponderable.getState() == PonderableComponent::State::grounded) { animating.startAnimation(entity, "walkingLeft"); } else { @@ -141,7 +141,7 @@ void ControllingSystem::walkRight(id_type entity) auto& animating = game_.getSystemManager().getSystem(); - if (ponderable.getState() == PonderableComponent::state::grounded) + if (ponderable.getState() == PonderableComponent::State::grounded) { animating.startAnimation(entity, "walkingRight"); } else { @@ -156,7 +156,7 @@ void ControllingSystem::stopWalking(id_type entity) ponderable.setVelocityX(0); - if (ponderable.getState() == PonderableComponent::state::grounded) + if (ponderable.getState() == PonderableComponent::State::grounded) { auto& animating = game_.getSystemManager().getSystem(); @@ -173,13 +173,13 @@ void ControllingSystem::jump(id_type entity) { auto& ponderable = game_.getEntityManager().getComponent(entity); - if (ponderable.getState() == PonderableComponent::state::grounded) + if (ponderable.getState() == PonderableComponent::State::grounded) { playSound("res/Randomize87.wav", 0.25); ponderable.setVelocityY(JUMP_VELOCITY(TILE_HEIGHT*4.5, 0.3)); ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*4.5, 0.3)); - ponderable.setState(PonderableComponent::state::jumping); + ponderable.setState(PonderableComponent::State::jumping); } } @@ -187,10 +187,10 @@ void ControllingSystem::stopJumping(id_type entity) { auto& ponderable = game_.getEntityManager().getComponent(entity); - if (ponderable.getState() == PonderableComponent::state::jumping) + if (ponderable.getState() == PonderableComponent::State::jumping) { ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233)); - ponderable.setState(PonderableComponent::state::falling); + ponderable.setState(PonderableComponent::State::falling); } } @@ -199,12 +199,12 @@ void ControllingSystem::drop(id_type entity, bool start) auto& droppable = game_.getEntityManager().getComponent(entity); auto& ponderable = game_.getEntityManager().getComponent(entity); - if (start && (ponderable.getState() == PonderableComponent::state::grounded)) + if (start && (ponderable.getState() == PonderableComponent::State::grounded)) { - ponderable.setState(PonderableComponent::state::dropping); - } else if ((!start) && (ponderable.getState() == PonderableComponent::state::dropping)) + ponderable.setState(PonderableComponent::State::dropping); + } else if ((!start) && (ponderable.getState() == PonderableComponent::State::dropping)) { - ponderable.setState(PonderableComponent::state::grounded); + ponderable.setState(PonderableComponent::State::grounded); } droppable.setDroppable(start); } diff --git a/src/systems/mapping.cpp b/src/systems/mapping.cpp new file mode 100644 index 0000000..8723e16 --- /dev/null +++ b/src/systems/mapping.cpp @@ -0,0 +1,143 @@ +#include "mapping.h" +#include "components/mappable.h" +#include "game.h" +#include "consts.h" + +#include + +template +inline void addBoundary( + Storage& boundaries, + int axis, + int lower, + int upper, + MappableComponent::Boundary::Type type) +{ + boundaries.emplace(std::piecewise_construct, + std::tie(axis), + std::tie(axis, lower, upper, type)); +} + +void MappingSystem::render(Texture& texture) +{ + auto entities = game_.getEntityManager().getEntitiesWithComponents< + MappableComponent>(); + + for (id_type entity : entities) + { + auto& mappable = game_.getEntityManager(). + getComponent(entity); + + const Map& map = game_.getWorld().getMap(mappable.getMapId()); + + for (int i = 0; i < MAP_WIDTH * MAP_HEIGHT; i++) + { + int x = i % MAP_WIDTH; + int y = i / MAP_WIDTH; + int tile = map.getTiles()[i]; + + if (tile > 0) + { + Rectangle dst { + x * TILE_WIDTH, + y * TILE_HEIGHT, + TILE_WIDTH, + TILE_HEIGHT}; + + Rectangle src { + (tile % TILESET_COLS) * TILE_WIDTH, + (tile / TILESET_COLS) * TILE_HEIGHT, + TILE_WIDTH, + TILE_HEIGHT}; + + texture.blit(mappable.getTileset(), std::move(src), std::move(dst)); + } + } + + int startX = ((GAME_WIDTH / TILE_WIDTH) / 2) - (map.getTitle().size() / 2); + for (size_t i = 0; i < map.getTitle().size(); i++) + { + Rectangle src { + (map.getTitle()[i] % FONT_COLS) * TILE_WIDTH, + (map.getTitle()[i] / FONT_COLS) * TILE_HEIGHT, + TILE_WIDTH, + TILE_HEIGHT}; + + Rectangle dst { + (startX + static_cast(i)) * TILE_WIDTH, + 24 * TILE_HEIGHT, + TILE_WIDTH, + TILE_HEIGHT}; + + texture.blit(mappable.getFont(), std::move(src), std::move(dst)); + } + } +} + +void MappingSystem::loadMap(size_t mapId) +{ + id_type mapEntity = game_.getEntityManager().emplaceEntity(); + + auto& mappable = game_.getEntityManager(). + emplaceComponent(mapEntity, + Texture("res/tiles.png"), + Texture("res/font.bmp")); + + mappable.setMapId(mapId); + + const Map& map = game_.getWorld().getMap(mappable.getMapId()); + + for (size_t i = 0; i < MAP_WIDTH * MAP_HEIGHT; i++) + { + size_t x = i % MAP_WIDTH; + size_t y = i / MAP_WIDTH; + int tile = map.getTiles()[i]; + + if ((tile >= 5) && (tile <= 7)) + { + addBoundary( + mappable.getDownBoundaries(), + y * TILE_HEIGHT, + x * TILE_WIDTH, + (x + 1) * TILE_WIDTH, + MappableComponent::Boundary::Type::platform); + } else if ((tile > 0) && (tile < 28)) + { + addBoundary( + mappable.getRightBoundaries(), + x * TILE_WIDTH, + y * TILE_HEIGHT, + (y+1) * TILE_HEIGHT, + MappableComponent::Boundary::Type::wall); + + addBoundary( + mappable.getLeftBoundaries(), + (x+1) * TILE_WIDTH, + y * TILE_HEIGHT, + (y+1) * TILE_HEIGHT, + MappableComponent::Boundary::Type::wall); + + addBoundary( + mappable.getDownBoundaries(), + y * TILE_HEIGHT, + x * TILE_WIDTH, + (x+1) * TILE_WIDTH, + MappableComponent::Boundary::Type::wall); + + addBoundary( + mappable.getUpBoundaries(), + (y+1) * TILE_HEIGHT, + x * TILE_WIDTH, + (x+1) * TILE_WIDTH, + MappableComponent::Boundary::Type::wall); + } else if (tile == 42) + { + addBoundary( + mappable.getDownBoundaries(), + y * TILE_HEIGHT, + x * TILE_WIDTH, + (x+1) * TILE_WIDTH, + MappableComponent::Boundary::Type::danger); + } + } +} diff --git a/src/systems/mapping.h b/src/systems/mapping.h new file mode 100644 index 0000000..53d054b --- /dev/null +++ b/src/systems/mapping.h @@ -0,0 +1,19 @@ +#ifndef MAPPING_H_33FC2294 +#define MAPPING_H_33FC2294 + +#include "system.h" + +class MappingSystem : public System { +public: + + MappingSystem(Game& game) : System(game) + { + } + + void render(Texture& texture); + + void loadMap(size_t mapId); + +}; + +#endif /* end of include guard: MAPPING_H_33FC2294 */ diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index e40db1d..26a6f56 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -2,6 +2,8 @@ #include "game.h" #include "components/ponderable.h" #include "components/transformable.h" +#include "components/droppable.h" +#include "consts.h" void PonderingSystem::tick(double dt) { @@ -9,17 +11,251 @@ void PonderingSystem::tick(double dt) PonderableComponent, TransformableComponent>(); + auto maps = game_.getEntityManager().getEntitiesWithComponents< + MappableComponent>(); + for (id_type entity : entities) { - auto& transformable = game_.getEntityManager().getComponent(entity); - auto& ponderable = game_.getEntityManager().getComponent(entity); + auto& transformable = game_.getEntityManager(). + getComponent(entity); + + auto& ponderable = game_.getEntityManager(). + getComponent(entity); // Accelerate - ponderable.setVelocityX(ponderable.getVelocityX() + ponderable.getAccelX() * dt); - ponderable.setVelocityY(ponderable.getVelocityY() + ponderable.getAccelY() * dt); + ponderable.setVelocityX( + ponderable.getVelocityX() + ponderable.getAccelX() * dt); + + ponderable.setVelocityY( + ponderable.getVelocityY() + ponderable.getAccelY() * dt); + + const double oldX = transformable.getX(); + const double oldY = transformable.getY(); + const double oldRight = oldX + transformable.getW(); + const double oldBottom = oldY + transformable.getH(); + + double newX = oldX + ponderable.getVelocityX() * dt; + double newY = oldY + ponderable.getVelocityY() * dt; + + if (ponderable.getVelocityY() > 0.0) + { + ponderable.setState(PonderableComponent::State::falling); + } + + for (id_type mapEntity : maps) + { + auto& mappable = game_.getEntityManager(). + getComponent(mapEntity); + + if (newX < oldX) + { + for (auto it = mappable.getLeftBoundaries().lower_bound(oldX); + (it != std::end(mappable.getLeftBoundaries())) && (it->first >= newX); + it++) + { + if ((oldBottom > it->second.getLower()) + && (oldY < it->second.getUpper())) + { + // We have a collision! + processCollision( + entity, + Direction::left, + newX, + newY, + it->first, + it->second.getType()); + + break; + } + } + } else if (newX > oldX) + { + for (auto it = mappable.getRightBoundaries().lower_bound(oldRight); + (it != std::end(mappable.getRightBoundaries())) + && (it->first <= (newX + transformable.getW())); + it++) + { + if ((oldBottom > it->second.getLower()) + && (oldY < it->second.getUpper())) + { + // We have a collision! + processCollision( + entity, + Direction::right, + newX, + newY, + it->first, + it->second.getType()); + + break; + } + } + } + + if (newY < oldY) + { + for (auto it = mappable.getUpBoundaries().lower_bound(oldY); + (it != std::end(mappable.getUpBoundaries())) && (it->first >= newY); + it++) + { + if ((oldRight > it->second.getLower()) + && (oldX < it->second.getUpper())) + { + // We have a collision! + processCollision( + entity, + Direction::up, + newX, + newY, + it->first, + it->second.getType()); + + break; + } + } + } else if (newY > oldY) + { + for (auto it = mappable.getDownBoundaries().lower_bound(oldBottom); + (it != std::end(mappable.getDownBoundaries())) + && (it->first <= (newY + transformable.getH())); + it++) + { + if ((oldRight > it->second.getLower()) + && (oldX < it->second.getUpper())) + { + // We have a collision! + processCollision( + entity, + Direction::down, + newX, + newY, + it->first, + it->second.getType()); + + break; + } + } + } + } // Move - transformable.setX(transformable.getX() + ponderable.getVelocityX() * dt); - transformable.setY(transformable.getY() + ponderable.getVelocityY() * dt); + transformable.setX(newX); + transformable.setY(newY); + } +} + +void PonderingSystem::initializeBody( + id_type entity, + PonderableComponent::Type type) +{ + auto& ponderable = game_.getEntityManager(). + emplaceComponent(entity, type); + + if (type == PonderableComponent::Type::freefalling) + { + ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233)); + ponderable.setState(PonderableComponent::State::falling); + } +} + +void PonderingSystem::processCollision( + id_type entity, + Direction dir, + double& newX, + double& newY, + int axis, + MappableComponent::Boundary::Type type) +{ + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + auto& transformable = game_.getEntityManager(). + getComponent(entity); + + switch (type) + { + case MappableComponent::Boundary::Type::wall: + { + switch (dir) + { + case Direction::left: + { + newX = axis; + ponderable.setVelocityX(0.0); + + break; + } + + case Direction::right: + { + newX = axis - transformable.getW(); + ponderable.setVelocityX(0.0); + + break; + } + + case Direction::up: + { + newY = axis; + ponderable.setVelocityY(0.0); + + break; + } + + case Direction::down: + { + newY = axis - transformable.getH(); + ponderable.setVelocityY(0.0); + + if (ponderable.getState() == PonderableComponent::State::falling) + { + ponderable.setState(PonderableComponent::State::grounded); + } + + break; + } + } + + break; + } + + case MappableComponent::Boundary::Type::platform: + { + if (game_.getEntityManager().hasComponent(entity)) + { + auto& droppable = game_.getEntityManager(). + getComponent(entity); + + if (droppable.isDroppable()) + { + droppable.setDroppable(false); + } else { + newY = axis - transformable.getH(); + ponderable.setVelocityY(0.0); + + if (ponderable.getState() == PonderableComponent::State::falling) + { + ponderable.setState(PonderableComponent::State::grounded); + } + } + } else { + newY = axis - transformable.getH(); + ponderable.setVelocityY(0.0); + + if (ponderable.getState() == PonderableComponent::State::falling) + { + ponderable.setState(PonderableComponent::State::grounded); + } + } + + break; + } + + default: + { + // Not yet implemented. + + break; + } } } diff --git a/src/systems/pondering.h b/src/systems/pondering.h index 44e7600..a16622b 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -2,6 +2,9 @@ #define PONDERING_H_F2530E0E #include "system.h" +#include "components/mappable.h" +#include "components/ponderable.h" +#include "direction.h" class PonderingSystem : public System { public: @@ -11,6 +14,19 @@ public: } void tick(double dt); + + void initializeBody(id_type entity, PonderableComponent::Type type); + +private: + + void processCollision( + id_type entity, + Direction dir, + double& newX, + double& newY, + int axis, + MappableComponent::Boundary::Type type); + }; #endif /* end of include guard: PONDERING_H_F2530E0E */ diff --git a/src/world.cpp b/src/world.cpp new file mode 100644 index 0000000..9b1e4f6 --- /dev/null +++ b/src/world.cpp @@ -0,0 +1,99 @@ +#include "world.h" +#include +#include +#include +#include "consts.h" + +inline xmlChar* getProp(xmlNodePtr node, const char* attr) +{ + xmlChar* key = xmlGetProp(node, reinterpret_cast(attr)); + if (key == nullptr) + { + throw std::invalid_argument("Error parsing world file"); + } + + return key; +} + +World::World(std::string filename) +{ + xmlDocPtr doc = xmlParseFile(filename.c_str()); + if (doc == nullptr) + { + throw std::invalid_argument("Cannot find world file"); + } + + xmlNodePtr top = xmlDocGetRootElement(doc); + if (top == nullptr) + { + throw std::invalid_argument("Error parsing world file"); + } + + if (xmlStrcmp(top->name, reinterpret_cast("world"))) + { + throw std::invalid_argument("Error parsing world file"); + } + + xmlChar* key = nullptr; + + key = getProp(top, "startx"); + startX_ = atoi(reinterpret_cast(key)); + xmlFree(key); + + key = getProp(top, "starty"); + startY_ = atoi(reinterpret_cast(key)); + xmlFree(key); + + key = getProp(top, "startmap"); + startMap_ = atoi(reinterpret_cast(key)); + xmlFree(key); + + for (xmlNodePtr node = top->xmlChildrenNode; + node != nullptr; + node = node->next) + { + if (!xmlStrcmp(node->name, reinterpret_cast("map"))) + { + key = getProp(node, "id"); + size_t mapId = atoi(reinterpret_cast(key)); + xmlFree(key); + + key = getProp(node, "title"); + std::string mapTitle(reinterpret_cast(key)); + xmlFree(key); + + std::vector mapTiles; + + for (xmlNodePtr mapNode = node->xmlChildrenNode; + mapNode != nullptr; + mapNode = mapNode->next) + { + if (!xmlStrcmp( + mapNode->name, + reinterpret_cast("environment"))) + { + key = xmlNodeGetContent(mapNode); + + mapTiles.clear(); + mapTiles.push_back(atoi(strtok(reinterpret_cast(key), ",\n"))); + for (size_t i = 1; i < (MAP_WIDTH * MAP_HEIGHT); i++) + { + mapTiles.push_back(atoi(strtok(nullptr, ",\n"))); + } + + xmlFree(key); + } + } + + maps_.emplace( + std::piecewise_construct, + std::forward_as_tuple(mapId), + std::forward_as_tuple( + mapId, + std::move(mapTiles), + std::move(mapTitle))); + } + } + + xmlFreeDoc(doc); +} diff --git a/src/world.h b/src/world.h new file mode 100644 index 0000000..b88adf4 --- /dev/null +++ b/src/world.h @@ -0,0 +1,41 @@ +#ifndef WORLD_H_153C698B +#define WORLD_H_153C698B + +#include +#include +#include "map.h" + +class World { +public: + + explicit World(std::string filename); + + inline const Map& getMap(size_t id) const + { + return maps_.at(id); + } + + inline size_t getStartingMapId() const + { + return startMap_; + } + + inline int getStartingX() const + { + return startX_; + } + + inline int getStartingY() const + { + return startY_; + } + +private: + + std::map maps_; + size_t startMap_; + int startX_; + int startY_; +}; + +#endif /* end of include guard: WORLD_H_153C698B */ -- cgit 1.4.1 From 5cc80ec58ea5bd66456f6f5286fa5f26d3fe702b Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Mon, 12 Feb 2018 16:39:49 -0500 Subject: Abstracted behavior related to "orientable" entities A lot of the stuff that ControllingSystem did to control the player character was moved into the new OrientingSystem. This is so that the player, or any player-like entities, can also be controlled by AI, with the underlying behavior being delegated in the same way as if the player were being controlled by the user. Fixed the issue where, if the player were blocked while moving horizontally, they would remain blocked even if vertical movement were to remove the collision. Fixed cases of the player animating incorrectly after performing certain movements. --- CMakeLists.txt | 1 + src/components/droppable.h | 24 ----- src/components/orientable.h | 45 +++++++++ src/components/ponderable.h | 17 +--- src/consts.h | 10 +- src/game.cpp | 4 +- src/systems/controlling.cpp | 129 +++--------------------- src/systems/controlling.h | 8 -- src/systems/mapping.cpp | 2 - src/systems/orienting.cpp | 236 ++++++++++++++++++++++++++++++++++++++++++++ src/systems/orienting.h | 35 +++++++ src/systems/pondering.cpp | 89 +++++++++-------- 12 files changed, 393 insertions(+), 207 deletions(-) delete mode 100644 src/components/droppable.h create mode 100644 src/systems/orienting.cpp create mode 100644 src/systems/orienting.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index f918156..39b1bbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,7 @@ add_executable(Aromatherapy src/systems/pondering.cpp src/systems/animating.cpp src/systems/mapping.cpp + src/systems/orienting.cpp ) target_link_libraries(Aromatherapy ${ALL_LIBS}) install(TARGETS Aromatherapy RUNTIME DESTINATION ${BIN_DIR}) diff --git a/src/components/droppable.h b/src/components/droppable.h deleted file mode 100644 index 722c139..0000000 --- a/src/components/droppable.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef DROPPABLE_H_5DB254EF -#define DROPPABLE_H_5DB254EF - -#include "component.h" - -class DroppableComponent : public Component { -public: - - inline bool isDroppable() const - { - return droppable_; - } - - inline void setDroppable(bool can) - { - droppable_ = can; - } - -private: - - bool droppable_ = false; -}; - -#endif /* end of include guard: DROPPABLE_H_5DB254EF */ diff --git a/src/components/orientable.h b/src/components/orientable.h index 8f56912..e356b78 100644 --- a/src/components/orientable.h +++ b/src/components/orientable.h @@ -6,6 +6,18 @@ class OrientableComponent : public Component { public: + enum class WalkState { + still, + left, + right + }; + + enum class DropState { + none, + ready, + active + }; + inline bool isFacingRight() const { return facingRight_; @@ -16,9 +28,42 @@ public: facingRight_ = v; } + inline WalkState getWalkState() const + { + return walkState_; + } + + inline void setWalkState(WalkState v) + { + walkState_ = v; + } + + inline bool isJumping() const + { + return jumping_; + } + + inline void setJumping(bool v) + { + jumping_ = v; + } + + inline DropState getDropState() const + { + return dropState_; + } + + inline void setDropState(DropState v) + { + dropState_ = v; + } + private: bool facingRight_ = false; + WalkState walkState_ = WalkState::still; + bool jumping_ = false; + DropState dropState_ = DropState::none; }; #endif /* end of include guard: ORIENTABLE_H_EDB6C4A1 */ diff --git a/src/components/ponderable.h b/src/components/ponderable.h index ac759b6..e21cbab 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -11,13 +11,6 @@ public: freefalling }; - enum class State { - grounded, - jumping, - falling, - dropping - }; - PonderableComponent(Type type) : type_(type) { } @@ -67,14 +60,14 @@ public: accelY_ = v; } - inline State getState() const + inline bool isGrounded() const { - return state_; + return grounded_; } - inline void setState(State arg) + inline void setGrounded(bool v) { - state_ = arg; + grounded_ = v; } private: @@ -84,7 +77,7 @@ private: double accelX_ = 0.0; double accelY_ = 0.0; Type type_ = Type::vacuumed; - State state_ = State::grounded; + bool grounded_ = false; }; #endif /* end of include guard: TANGIBLE_H_746DB3EE */ diff --git a/src/consts.h b/src/consts.h index a6c9985..581018d 100644 --- a/src/consts.h +++ b/src/consts.h @@ -14,7 +14,13 @@ const int FONT_COLS = 16; const int FRAMES_PER_SECOND = 60; const double SECONDS_PER_FRAME = 1.0 / FRAMES_PER_SECOND; -#define JUMP_VELOCITY(h, l) (-2 * (h) / (l)) -#define JUMP_GRAVITY(h, l) (2 * ((h) / (l)) / (l)) +#define CALC_VELOCITY(h, l) (-2 * (h) / (l)) +#define CALC_GRAVITY(h, l) (2 * ((h) / (l)) / (l)) + +const double NORMAL_GRAVITY = CALC_GRAVITY(TILE_HEIGHT*3.5, 0.233); +const double JUMP_GRAVITY = CALC_GRAVITY(TILE_HEIGHT*4.5, 0.3); +const double JUMP_VELOCITY = CALC_VELOCITY(TILE_HEIGHT*4.5, 0.3); + +const double WALK_SPEED = 90; #endif diff --git a/src/game.cpp b/src/game.cpp index 7cbe7e0..39bb3f1 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2,13 +2,13 @@ #include "components/animatable.h" #include "components/transformable.h" #include "components/controllable.h" -#include "components/droppable.h" #include "components/ponderable.h" #include "components/orientable.h" #include "systems/controlling.h" #include "systems/pondering.h" #include "systems/animating.h" #include "systems/mapping.h" +#include "systems/orienting.h" #include "animation.h" #include "renderer.h" #include "consts.h" @@ -33,6 +33,7 @@ Game::Game( world_("res/maps.xml") { systemManager_.emplaceSystem(*this); + systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); @@ -58,7 +59,6 @@ Game::Game( player, PonderableComponent::Type::freefalling); - entityManager_.emplaceComponent(player); entityManager_.emplaceComponent(player); entityManager_.emplaceComponent(player); diff --git a/src/systems/controlling.cpp b/src/systems/controlling.cpp index fa09d11..e1609bd 100644 --- a/src/systems/controlling.cpp +++ b/src/systems/controlling.cpp @@ -1,14 +1,8 @@ #include "controlling.h" #include "game.h" #include "components/controllable.h" -#include "components/ponderable.h" -#include "components/animatable.h" -#include "components/droppable.h" #include "components/orientable.h" -#include "systems/animating.h" -#include "direction.h" -#include "muxer.h" -#include "consts.h" +#include "systems/orienting.h" void ControllingSystem::tick(double) { @@ -19,9 +13,6 @@ void ControllingSystem::tick(double) auto entities = game_.getEntityManager().getEntitiesWithComponents< ControllableComponent, - PonderableComponent, - AnimatableComponent, - DroppableComponent, OrientableComponent>(); for (auto entity : entities) @@ -29,6 +20,8 @@ void ControllingSystem::tick(double) auto& controllable = game_.getEntityManager(). getComponent(entity); + auto& orienting = game_.getSystemManager().getSystem(); + if (action == GLFW_PRESS) { if (key == controllable.getLeftKey()) @@ -37,7 +30,7 @@ void ControllingSystem::tick(double) if (!controllable.isFrozen()) { - walkLeft(entity); + orienting.moveLeft(entity); } } else if (key == controllable.getRightKey()) { @@ -45,19 +38,19 @@ void ControllingSystem::tick(double) if (!controllable.isFrozen()) { - walkRight(entity); + orienting.moveRight(entity); } } else if (key == controllable.getJumpKey()) { if (!controllable.isFrozen()) { - jump(entity); + orienting.jump(entity); } } else if (key == controllable.getDropKey()) { if (!controllable.isFrozen()) { - drop(entity, true); + orienting.drop(entity); } } } else if (action == GLFW_RELEASE) @@ -70,9 +63,9 @@ void ControllingSystem::tick(double) { if (controllable.isHoldingRight()) { - walkRight(entity); + orienting.moveRight(entity); } else { - stopWalking(entity); + orienting.stopWalking(entity); } } } else if (key == controllable.getRightKey()) @@ -83,22 +76,22 @@ void ControllingSystem::tick(double) { if (controllable.isHoldingLeft()) { - walkLeft(entity); + orienting.moveLeft(entity); } else { - stopWalking(entity); + orienting.stopWalking(entity); } } } else if (key == controllable.getDropKey()) { if (!controllable.isFrozen()) { - drop(entity, false); + orienting.stopDropping(entity); } } else if (key == controllable.getJumpKey()) { if (!controllable.isFrozen()) { - stopJumping(entity); + orienting.stopJumping(entity); } } } @@ -112,99 +105,3 @@ void ControllingSystem::input(int key, int action) { actions_.push(std::make_pair(key, action)); } - -void ControllingSystem::walkLeft(id_type entity) -{ - auto& ponderable = game_.getEntityManager().getComponent(entity); - auto& orientable = game_.getEntityManager().getComponent(entity); - - orientable.setFacingRight(false); - ponderable.setVelocityX(-90); - - auto& animating = game_.getSystemManager().getSystem(); - - if (ponderable.getState() == PonderableComponent::State::grounded) - { - animating.startAnimation(entity, "walkingLeft"); - } else { - animating.startAnimation(entity, "stillLeft"); - } -} - -void ControllingSystem::walkRight(id_type entity) -{ - auto& ponderable = game_.getEntityManager().getComponent(entity); - auto& orientable = game_.getEntityManager().getComponent(entity); - - orientable.setFacingRight(true); - ponderable.setVelocityX(90); - - auto& animating = game_.getSystemManager().getSystem(); - - if (ponderable.getState() == PonderableComponent::State::grounded) - { - animating.startAnimation(entity, "walkingRight"); - } else { - animating.startAnimation(entity, "stillRight"); - } -} - -void ControllingSystem::stopWalking(id_type entity) -{ - auto& ponderable = game_.getEntityManager().getComponent(entity); - auto& orientable = game_.getEntityManager().getComponent(entity); - - ponderable.setVelocityX(0); - - if (ponderable.getState() == PonderableComponent::State::grounded) - { - auto& animating = game_.getSystemManager().getSystem(); - - if (orientable.isFacingRight()) - { - animating.startAnimation(entity, "stillRight"); - } else { - animating.startAnimation(entity, "stillLeft"); - } - } -} - -void ControllingSystem::jump(id_type entity) -{ - auto& ponderable = game_.getEntityManager().getComponent(entity); - - if (ponderable.getState() == PonderableComponent::State::grounded) - { - playSound("res/Randomize87.wav", 0.25); - - ponderable.setVelocityY(JUMP_VELOCITY(TILE_HEIGHT*4.5, 0.3)); - ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*4.5, 0.3)); - ponderable.setState(PonderableComponent::State::jumping); - } -} - -void ControllingSystem::stopJumping(id_type entity) -{ - auto& ponderable = game_.getEntityManager().getComponent(entity); - - if (ponderable.getState() == PonderableComponent::State::jumping) - { - ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233)); - ponderable.setState(PonderableComponent::State::falling); - } -} - -void ControllingSystem::drop(id_type entity, bool start) -{ - auto& droppable = game_.getEntityManager().getComponent(entity); - auto& ponderable = game_.getEntityManager().getComponent(entity); - - if (start && (ponderable.getState() == PonderableComponent::State::grounded)) - { - ponderable.setState(PonderableComponent::State::dropping); - } else if ((!start) && (ponderable.getState() == PonderableComponent::State::dropping)) - { - ponderable.setState(PonderableComponent::State::grounded); - } - droppable.setDroppable(start); -} diff --git a/src/systems/controlling.h b/src/systems/controlling.h index 1f1e8a0..01ed7a0 100644 --- a/src/systems/controlling.h +++ b/src/systems/controlling.h @@ -3,7 +3,6 @@ #include "system.h" #include -#include "entity_manager.h" class ControllingSystem : public System { public: @@ -17,13 +16,6 @@ public: private: - void walkLeft(id_type entity); - void walkRight(id_type entity); - void stopWalking(id_type entity); - void jump(id_type entity); - void stopJumping(id_type entity); - void drop(id_type entity, bool start); - std::queue> actions_; }; diff --git a/src/systems/mapping.cpp b/src/systems/mapping.cpp index 8723e16..5b63ded 100644 --- a/src/systems/mapping.cpp +++ b/src/systems/mapping.cpp @@ -3,8 +3,6 @@ #include "game.h" #include "consts.h" -#include - template inline void addBoundary( Storage& boundaries, diff --git a/src/systems/orienting.cpp b/src/systems/orienting.cpp new file mode 100644 index 0000000..187bebc --- /dev/null +++ b/src/systems/orienting.cpp @@ -0,0 +1,236 @@ +#include "orienting.h" +#include "game.h" +#include "components/orientable.h" +#include "components/ponderable.h" +#include "systems/animating.h" +#include "consts.h" +#include "muxer.h" + +void OrientingSystem::tick(double) +{ + auto entities = game_.getEntityManager().getEntitiesWithComponents< + OrientableComponent, + PonderableComponent>(); + + for (id_type entity : entities) + { + auto& orientable = game_.getEntityManager(). + getComponent(entity); + + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + switch (orientable.getWalkState()) + { + case OrientableComponent::WalkState::still: + { + ponderable.setVelocityX(0); + + break; + } + + case OrientableComponent::WalkState::left: + { + ponderable.setVelocityX(-WALK_SPEED); + + break; + } + + case OrientableComponent::WalkState::right: + { + ponderable.setVelocityX(WALK_SPEED); + + break; + } + } + + if (orientable.isJumping() && (ponderable.getVelocityY() > 0)) + { + orientable.setJumping(false); + } + } +} + +void OrientingSystem::moveLeft(id_type entity) +{ + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + auto& orientable = game_.getEntityManager(). + getComponent(entity); + + orientable.setFacingRight(false); + orientable.setWalkState(OrientableComponent::WalkState::left); + + auto& animating = game_.getSystemManager().getSystem(); + if (ponderable.isGrounded()) + { + animating.startAnimation(entity, "walkingLeft"); + } else { + animating.startAnimation(entity, "stillLeft"); + } +} + +void OrientingSystem::moveRight(id_type entity) +{ + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + auto& orientable = game_.getEntityManager(). + getComponent(entity); + + orientable.setFacingRight(true); + orientable.setWalkState(OrientableComponent::WalkState::right); + + auto& animating = game_.getSystemManager().getSystem(); + if (ponderable.isGrounded()) + { + animating.startAnimation(entity, "walkingRight"); + } else { + animating.startAnimation(entity, "stillRight"); + } +} + +void OrientingSystem::stopWalking(id_type entity) +{ + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + auto& orientable = game_.getEntityManager(). + getComponent(entity); + + orientable.setWalkState(OrientableComponent::WalkState::still); + + if (ponderable.isGrounded()) + { + auto& animating = game_.getSystemManager().getSystem(); + + if (orientable.isFacingRight()) + { + animating.startAnimation(entity, "stillRight"); + } else { + animating.startAnimation(entity, "stillLeft"); + } + } +} + +void OrientingSystem::jump(id_type entity) +{ + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + if (ponderable.isGrounded()) + { + auto& orientable = game_.getEntityManager(). + getComponent(entity); + + orientable.setJumping(true); + + playSound("res/Randomize87.wav", 0.25); + + ponderable.setVelocityY(JUMP_VELOCITY); + ponderable.setAccelY(JUMP_GRAVITY); + + auto& animating = game_.getSystemManager().getSystem(); + if (orientable.isFacingRight()) + { + animating.startAnimation(entity, "stillRight"); + } else { + animating.startAnimation(entity, "stillLeft"); + } + } +} + +void OrientingSystem::stopJumping(id_type entity) +{ + auto& orientable = game_.getEntityManager(). + getComponent(entity); + + if (orientable.isJumping()) + { + orientable.setJumping(false); + + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + ponderable.setAccelY(NORMAL_GRAVITY); + } +} + +void OrientingSystem::land(id_type entity) +{ + auto& orientable = game_.getEntityManager(). + getComponent(entity); + + auto& animating = game_.getSystemManager().getSystem(); + + switch (orientable.getWalkState()) + { + case OrientableComponent::WalkState::still: + { + if (orientable.isFacingRight()) + { + animating.startAnimation(entity, "stillRight"); + } else { + animating.startAnimation(entity, "stillLeft"); + } + + break; + } + + case OrientableComponent::WalkState::left: + { + animating.startAnimation(entity, "walkingLeft"); + + break; + } + + case OrientableComponent::WalkState::right: + { + animating.startAnimation(entity, "walkingRight"); + + break; + } + } +} + +void OrientingSystem::startFalling(id_type entity) +{ + auto& orientable = game_.getEntityManager(). + getComponent(entity); + + auto& animating = game_.getSystemManager().getSystem(); + + if (orientable.isFacingRight()) + { + animating.startAnimation(entity, "stillRight"); + } else { + animating.startAnimation(entity, "stillLeft"); + } +} + +void OrientingSystem::drop(id_type entity) +{ + auto& orientable = game_.getEntityManager(). + getComponent(entity); + + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + if (ponderable.isGrounded() + && (orientable.getDropState() == OrientableComponent::DropState::none)) + { + orientable.setDropState(OrientableComponent::DropState::ready); + } +} + +void OrientingSystem::stopDropping(id_type entity) +{ + auto& orientable = game_.getEntityManager(). + getComponent(entity); + + if (orientable.getDropState() == OrientableComponent::DropState::ready) + { + orientable.setDropState(OrientableComponent::DropState::none); + } +} diff --git a/src/systems/orienting.h b/src/systems/orienting.h new file mode 100644 index 0000000..4ded612 --- /dev/null +++ b/src/systems/orienting.h @@ -0,0 +1,35 @@ +#ifndef ORIENTING_H_099F0C23 +#define ORIENTING_H_099F0C23 + +#include "system.h" + +class OrientingSystem : public System { +public: + + OrientingSystem(Game& game) : System(game) + { + } + + void tick(double dt); + + void moveLeft(id_type entity); + + void moveRight(id_type entity); + + void stopWalking(id_type entity); + + void jump(id_type entity); + + void stopJumping(id_type entity); + + void land(id_type entity); + + void startFalling(id_type entity); + + void drop(id_type entity); + + void stopDropping(id_type entity); + +}; + +#endif /* end of include guard: ORIENTING_H_099F0C23 */ diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 26a6f56..4a165b1 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -2,7 +2,9 @@ #include "game.h" #include "components/ponderable.h" #include "components/transformable.h" -#include "components/droppable.h" +#include "components/orientable.h" +#include "components/mappable.h" +#include "systems/orienting.h" #include "consts.h" void PonderingSystem::tick(double dt) @@ -37,10 +39,8 @@ void PonderingSystem::tick(double dt) double newX = oldX + ponderable.getVelocityX() * dt; double newY = oldY + ponderable.getVelocityY() * dt; - if (ponderable.getVelocityY() > 0.0) - { - ponderable.setState(PonderableComponent::State::falling); - } + bool oldGrounded = ponderable.isGrounded(); + ponderable.setGrounded(false); for (id_type mapEntity : maps) { @@ -64,8 +64,6 @@ void PonderingSystem::tick(double dt) newY, it->first, it->second.getType()); - - break; } } } else if (newX > oldX) @@ -86,8 +84,6 @@ void PonderingSystem::tick(double dt) newY, it->first, it->second.getType()); - - break; } } } @@ -109,8 +105,6 @@ void PonderingSystem::tick(double dt) newY, it->first, it->second.getType()); - - break; } } } else if (newY > oldY) @@ -131,8 +125,6 @@ void PonderingSystem::tick(double dt) newY, it->first, it->second.getType()); - - break; } } } @@ -141,6 +133,31 @@ void PonderingSystem::tick(double dt) // Move transformable.setX(newX); transformable.setY(newY); + + // Perform cleanup for orientable entites + if (game_.getEntityManager().hasComponent(entity)) + { + auto& orientable = game_.getEntityManager(). + getComponent(entity); + + // Handle changes in groundedness + if (ponderable.isGrounded() != oldGrounded) + { + if (ponderable.isGrounded()) + { + game_.getSystemManager().getSystem().land(entity); + } else { + game_.getSystemManager(). + getSystem().startFalling(entity); + } + } + + // Complete dropping, if necessary + if (orientable.getDropState() == OrientableComponent::DropState::active) + { + orientable.setDropState(OrientableComponent::DropState::none); + } + } } } @@ -153,8 +170,7 @@ void PonderingSystem::initializeBody( if (type == PonderableComponent::Type::freefalling) { - ponderable.setAccelY(JUMP_GRAVITY(TILE_HEIGHT*3.5, 0.233)); - ponderable.setState(PonderableComponent::State::falling); + ponderable.setAccelY(NORMAL_GRAVITY); } } @@ -172,6 +188,8 @@ void PonderingSystem::processCollision( auto& transformable = game_.getEntityManager(). getComponent(entity); + bool touchedGround = false; + switch (type) { case MappableComponent::Boundary::Type::wall: @@ -204,13 +222,7 @@ void PonderingSystem::processCollision( case Direction::down: { - newY = axis - transformable.getH(); - ponderable.setVelocityY(0.0); - - if (ponderable.getState() == PonderableComponent::State::falling) - { - ponderable.setState(PonderableComponent::State::grounded); - } + touchedGround = true; break; } @@ -221,31 +233,19 @@ void PonderingSystem::processCollision( case MappableComponent::Boundary::Type::platform: { - if (game_.getEntityManager().hasComponent(entity)) + if (game_.getEntityManager().hasComponent(entity)) { - auto& droppable = game_.getEntityManager(). - getComponent(entity); + auto& orientable = game_.getEntityManager(). + getComponent(entity); - if (droppable.isDroppable()) + if (orientable.getDropState() != OrientableComponent::DropState::none) { - droppable.setDroppable(false); + orientable.setDropState(OrientableComponent::DropState::active); } else { - newY = axis - transformable.getH(); - ponderable.setVelocityY(0.0); - - if (ponderable.getState() == PonderableComponent::State::falling) - { - ponderable.setState(PonderableComponent::State::grounded); - } + touchedGround = true; } } else { - newY = axis - transformable.getH(); - ponderable.setVelocityY(0.0); - - if (ponderable.getState() == PonderableComponent::State::falling) - { - ponderable.setState(PonderableComponent::State::grounded); - } + touchedGround = true; } break; @@ -258,4 +258,11 @@ void PonderingSystem::processCollision( break; } } + + if (touchedGround) + { + newY = axis - transformable.getH(); + ponderable.setVelocityY(0.0); + ponderable.setGrounded(true); + } } -- cgit 1.4.1 From 224645d1071c14b4829dbb3ae35870868fcff85a Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Tue, 13 Feb 2018 23:00:10 -0500 Subject: Fixed inconsistent rendering failure The issue appears to have been caused by blending with unset alpha channels. Also included the re-ordered player character sprite image. The CMake file has been updated to include linking against some Apple libraries that are usually already included in GLFW3. refs #1 --- CMakeLists.txt | 11 ++++++++++- res/Starla.png | Bin 336 -> 3011 bytes shaders/bloom1.fragment | 11 ++++++----- shaders/bloom2.fragment | 26 ++++++++++++++------------ shaders/fill.fragment | 4 ++-- shaders/final.fragment | 4 ++-- shaders/ntsc.fragment | 4 ++-- src/game.cpp | 2 +- src/renderer.cpp | 34 +++++++++++++++++----------------- 9 files changed, 54 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b6ba2f..22bbc1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,13 +17,22 @@ find_package(portaudio REQUIRED) find_package(libsndfile REQUIRED) find_package(libxml2 REQUIRED) +IF(APPLE) + FIND_LIBRARY(COCOA_LIBRARY Cocoa) + FIND_LIBRARY(CV_LIBRARY CoreVideo) + FIND_LIBRARY(IO_LIBRARY IOKit) + MARK_AS_ADVANCED (COCOA_LIBRARY CV_LIBRARY IO_LIBRARY) + SET(EXTRA_LIBS ${COCOA_LIBRARY} ${CV_LIBRARY} ${IO_LIBRARY}) +ENDIF (APPLE) + set(ALL_LIBS - ${OPENGL_LIBRARIES} + ${OPENGL_gl_LIBRARY} ${GLEW_LIBRARIES} ${GLFW_LIBRARIES} ${PORTAUDIO_LIBRARIES} ${LIBSNDFILE_LIBRARY} ${LIBXML2_LIBRARIES} + ${EXTRA_LIBS} ) include_directories( diff --git a/res/Starla.png b/res/Starla.png index 7c98514..f5b41d7 100644 Binary files a/res/Starla.png and b/res/Starla.png differ diff --git a/shaders/bloom1.fragment b/shaders/bloom1.fragment index 0a89ea1..ed9e10d 100644 --- a/shaders/bloom1.fragment +++ b/shaders/bloom1.fragment @@ -2,15 +2,16 @@ in vec2 UV; -out vec3 color; +out vec4 color; uniform vec2 offset; uniform sampler2D inTex; void main() { - color = vec3(0.0); - color += (5.0/16.0) * texture(inTex, UV - offset).rgb; - color += (6.0/16.0) * texture(inTex, UV).rgb; - color += (5.0/16.0) * texture(inTex, UV + offset).rgb; + vec3 mval = vec3(0.0); + mval += (5.0/16.0) * texture(inTex, UV - offset).rgb; + mval += (6.0/16.0) * texture(inTex, UV).rgb; + mval += (5.0/16.0) * texture(inTex, UV + offset).rgb; + color = vec4(mval, 1.0); } diff --git a/shaders/bloom2.fragment b/shaders/bloom2.fragment index 4c50e86..6723c2c 100644 --- a/shaders/bloom2.fragment +++ b/shaders/bloom2.fragment @@ -2,7 +2,7 @@ in vec2 UV; -out vec3 color; +out vec4 color; uniform sampler2D clearTex; uniform sampler2D blurTex; @@ -15,19 +15,21 @@ float nrand(vec2 n) void main() { - color = vec3(0.0); - color += texture(clearTex, UV).rgb / 2.0; - color += texture(blurTex, UV).rgb; - color = max(vec3(0.0), color - 0.5); - color *= color; - + vec3 mval = vec3(0.0); + mval += texture(clearTex, UV).rgb / 2.0; + mval += texture(blurTex, UV).rgb; + mval = max(vec3(0.0), mval - 0.5); + mval *= mval; + float flicker = 0.5 + nrand(vec2(iGlobalTime)); flicker *= (flicker); //flicker = sqrt(flicker); //flicker = pow(flicker, 1.0/8.0); - //color *= flicker; - color *= mix(vec3(0.0), color, flicker); - - color += texture(clearTex, UV).rgb; - color = clamp(color, vec3(0.0), vec3(1.0)); + //mval *= flicker; + mval *= mix(vec3(0.0), mval, flicker); + + mval += texture(clearTex, UV).rgb; + mval = clamp(mval, vec3(0.0), vec3(1.0)); + + color = vec4(mval, 1.0); } diff --git a/shaders/fill.fragment b/shaders/fill.fragment index ab7d9c9..81443c4 100644 --- a/shaders/fill.fragment +++ b/shaders/fill.fragment @@ -1,10 +1,10 @@ #version 330 core -out vec3 color; +out vec4 color; uniform vec3 vecColor; void main() { - color = vecColor; + color = vec4(vecColor, 1.0); } diff --git a/shaders/final.fragment b/shaders/final.fragment index a3ee243..9a39597 100644 --- a/shaders/final.fragment +++ b/shaders/final.fragment @@ -5,7 +5,7 @@ in vec3 normIn; in vec3 camDirIn; in vec3 lightDirIn; -out vec3 color; +out vec4 color; uniform sampler2D rendertex; uniform sampler2D scanlinestex; @@ -71,5 +71,5 @@ void main() vec4 nearfinal = colorfres + colordiff + colorspec + emissive; //vec4 final = nearfinal * mix(vec4(1,1,1,1), vec4(0,0,0, 0), Tuning_Dimming); - color = nearfinal.rgb; + color = nearfinal; } diff --git a/shaders/ntsc.fragment b/shaders/ntsc.fragment index 56fb1c4..d6ae904 100644 --- a/shaders/ntsc.fragment +++ b/shaders/ntsc.fragment @@ -2,7 +2,7 @@ in vec2 UV; -out vec3 color; +out vec4 color; uniform sampler2D curFrameSampler; uniform sampler2D NTSCArtifactSampler; @@ -61,5 +61,5 @@ void main() Cur_Local = clamp(Cur_Local + (offset * Tuning_Sharp * mix(vec4(1,1,1,1), NTSCArtifact, Tuning_NTSC)), vec4(0,0,0,0), vec4(1,1,1,1)); Cur_Local = clamp(max(Cur_Local, Tuning_Persistence * (1.0 / (1.0 + (2.0 * Tuning_Bleed))) * (Prev_Local + ((Prev_Left + Prev_Right) * Tuning_Bleed))), vec4(0,0,0,0), vec4(1,1,1,1)); - color = Cur_Local.xyz; + color = vec4(Cur_Local.rgb, 1.0); } diff --git a/src/game.cpp b/src/game.cpp index 39bb3f1..1182689 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -40,7 +40,7 @@ Game::Game( int player = entityManager_.emplaceEntity(); - AnimationSet playerGraphics {"res/Starla2.bmp", 10, 12, 6}; + AnimationSet playerGraphics {"res/Starla.png", 10, 12, 6}; playerGraphics.emplaceAnimation("stillLeft", 3, 1, 1); playerGraphics.emplaceAnimation("stillRight", 0, 1, 1); playerGraphics.emplaceAnimation("walkingLeft", 4, 2, 10); diff --git a/src/renderer.cpp b/src/renderer.cpp index 3945e09..f840180 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -33,8 +33,6 @@ static GLuint bloom1Shader; static GLuint bloom2Shader; // The buffers for the NTSC rendering process -static GLuint renderedTex1; -static GLuint renderedTex2; static GLuint renderedTexBufs[2]; static int curBuf; static GLuint artifactsTex; @@ -148,6 +146,10 @@ void flipImageData(unsigned char* data, int width, int height, int comps) void loadMesh(const char* filename, std::vector& out_vertices, std::vector& out_uvs, std::vector& out_normals) { + out_vertices.clear(); + out_uvs.clear(); + out_normals.clear(); + FILE* file = fopen(filename, "r"); if (file == nullptr) { @@ -308,34 +310,33 @@ GLFWwindow* initRenderer() GLenum DrawBuffers2[1] = {GL_COLOR_ATTACHMENT1}; glDrawBuffers(1, DrawBuffers2); + glfwGetFramebufferSize(window, &buffer_width, &buffer_height); + glGenRenderbuffers(1, &bloom_depthbuffer); glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1024, 768); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, buffer_width, buffer_height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer); // Set up the NTSC rendering buffers - glGenTextures(1, &renderedTex1); - glBindTexture(GL_TEXTURE_2D, renderedTex1); + glGenTextures(2, renderedTexBufs); + glBindTexture(GL_TEXTURE_2D, renderedTexBufs[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - renderedTexBufs[0] = renderedTex1; - glGenTextures(1, &renderedTex2); - glBindTexture(GL_TEXTURE_2D, renderedTex2); + glBindTexture(GL_TEXTURE_2D, renderedTexBufs[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - renderedTexBufs[1] = renderedTex2; // Set up bloom rendering buffers glGenTextures(1, &preBloomTex); glBindTexture(GL_TEXTURE_2D, preBloomTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024, 768, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, buffer_width, buffer_height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -343,7 +344,7 @@ GLFWwindow* initRenderer() glGenTextures(1, &bloomPassTex1); glBindTexture(GL_TEXTURE_2D, bloomPassTex1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024/4, 768/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, buffer_width/4, buffer_height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -351,7 +352,7 @@ GLFWwindow* initRenderer() glGenTextures(1, &bloomPassTex2); glBindTexture(GL_TEXTURE_2D, bloomPassTex2); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024/4, 768/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, buffer_width/4, buffer_height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -370,15 +371,15 @@ GLFWwindow* initRenderer() glGenBuffers(1, &mesh_vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, mesh_vertices.size() * sizeof(glm::vec3), &mesh_vertices[0], GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, mesh_vertices.size() * sizeof(glm::vec3), mesh_vertices.data(), GL_STATIC_DRAW); glGenBuffers(1, &mesh_uvbuffer); glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer); - glBufferData(GL_ARRAY_BUFFER, mesh_uvs.size() * sizeof(glm::vec3), &mesh_uvs[0], GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, mesh_uvs.size() * sizeof(glm::vec2), mesh_uvs.data(), GL_STATIC_DRAW); glGenBuffers(1, &mesh_normalbuffer); glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer); - glBufferData(GL_ARRAY_BUFFER, mesh_normals.size() * sizeof(glm::vec3), &mesh_normals[0], GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, mesh_normals.size() * sizeof(glm::vec3), mesh_normals.data(), GL_STATIC_DRAW); // Load the vertices of a flat surface GLfloat g_quad_vertex_buffer_data[] = { @@ -452,8 +453,7 @@ void destroyRenderer() glDeleteProgram(bloom2Shader); // Delete the NTSC rendering buffers - glDeleteTextures(1, &renderedTex1); - glDeleteTextures(1, &renderedTex2); + glDeleteTextures(2, renderedTexBufs); glDeleteTextures(1, &artifactsTex); glDeleteTextures(1, &scanlinesTex); glDeleteTextures(1, &preBloomTex); -- cgit 1.4.1 From ed08b673c50b076042d8f0c49501372168142764 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 16 Feb 2018 16:04:32 -0500 Subject: Refactored renderer Renderer is basically now more C++'y, as it makes more use of classes (a lot of GL types have been wrapped), and the renderer itself is now a class. The monitor mesh is also now indexed. Tweaked the NTSC artifacting after inadvertently fixing a bug with the way the image was loaded. --- CMakeLists.txt | 6 +- shaders/final.fragment | 4 +- src/algorithms.h | 12 - src/animation.h | 2 +- src/components/controllable.h | 2 +- src/components/mappable.h | 2 +- src/entity_manager.h | 2 +- src/game.cpp | 19 +- src/game.h | 11 +- src/main.cpp | 17 +- src/renderer.cpp | 862 ------------------------------------------ src/renderer.h | 37 -- src/renderer/gl.h | 7 + src/renderer/mesh.cpp | 109 ++++++ src/renderer/mesh.h | 62 +++ src/renderer/renderer.cpp | 635 +++++++++++++++++++++++++++++++ src/renderer/renderer.h | 114 ++++++ src/renderer/shader.cpp | 84 ++++ src/renderer/shader.h | 58 +++ src/renderer/texture.cpp | 124 ++++++ src/renderer/texture.h | 52 +++ src/renderer/wrappers.h | 273 +++++++++++++ src/systems/animating.cpp | 3 +- src/systems/animating.h | 2 +- src/systems/mapping.cpp | 12 +- src/util.cpp | 30 ++ src/util.h | 41 ++ 27 files changed, 1631 insertions(+), 951 deletions(-) delete mode 100644 src/algorithms.h delete mode 100644 src/renderer.cpp delete mode 100644 src/renderer.h create mode 100644 src/renderer/gl.h create mode 100644 src/renderer/mesh.cpp create mode 100644 src/renderer/mesh.h create mode 100644 src/renderer/renderer.cpp create mode 100644 src/renderer/renderer.h create mode 100644 src/renderer/shader.cpp create mode 100644 src/renderer/shader.h create mode 100644 src/renderer/texture.cpp create mode 100644 src/renderer/texture.h create mode 100644 src/renderer/wrappers.h create mode 100644 src/util.cpp create mode 100644 src/util.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 22bbc1a..3e7bcb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,12 +49,16 @@ link_directories( add_executable(Aromatherapy src/main.cpp - src/renderer.cpp src/muxer.cpp src/entity_manager.cpp src/game.cpp src/animation.cpp src/world.cpp + src/util.cpp + src/renderer/renderer.cpp + src/renderer/mesh.cpp + src/renderer/shader.cpp + src/renderer/texture.cpp src/systems/controlling.cpp src/systems/pondering.cpp src/systems/animating.cpp diff --git a/shaders/final.fragment b/shaders/final.fragment index 9a39597..2e38f38 100644 --- a/shaders/final.fragment +++ b/shaders/final.fragment @@ -15,8 +15,8 @@ const float Tuning_Dimming = 0.0; const float Tuning_Satur = 1.13; const float Tuning_ReflScalar = 0.3; const float Tuning_Barrel = 0;//0.12; -const float Tuning_Scanline_Brightness = 0.5;//0.45; -const float Tuning_Scanline_Opacity = 0.75;//0.55; +const float Tuning_Scanline_Brightness = 0.55; +const float Tuning_Scanline_Opacity = 0.55; const float Tuning_Diff_Brightness = 0.75; const float Tuning_Spec_Brightness = 0.5;//0.35; const float Tuning_Spec_Power = 50.0; diff --git a/src/algorithms.h b/src/algorithms.h deleted file mode 100644 index 80e3e27..0000000 --- a/src/algorithms.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef ALGORITHMS_H_1DDC517E -#define ALGORITHMS_H_1DDC517E - -template< typename ContainerT, typename PredicateT > -void erase_if( ContainerT& items, const PredicateT& predicate ) { - for( auto it = items.begin(); it != items.end(); ) { - if( predicate(*it) ) it = items.erase(it); - else ++it; - } -}; - -#endif /* end of include guard: ALGORITHMS_H_1DDC517E */ diff --git a/src/animation.h b/src/animation.h index 50446d0..58df616 100644 --- a/src/animation.h +++ b/src/animation.h @@ -1,7 +1,7 @@ #ifndef ANIMATION_H_74EB0901 #define ANIMATION_H_74EB0901 -#include "renderer.h" +#include "renderer/texture.h" #include #include #include diff --git a/src/components/controllable.h b/src/components/controllable.h index fa78c8b..1b12985 100644 --- a/src/components/controllable.h +++ b/src/components/controllable.h @@ -2,7 +2,7 @@ #define CONTROLLABLE_H_4E0B85B4 #include "component.h" -#include "renderer.h" +#include "renderer/gl.h" class ControllableComponent : public Component { public: diff --git a/src/components/mappable.h b/src/components/mappable.h index 7530919..2dbab77 100644 --- a/src/components/mappable.h +++ b/src/components/mappable.h @@ -3,7 +3,7 @@ #include #include "component.h" -#include "renderer.h" +#include "renderer/texture.h" #include "map.h" class MappableComponent : public Component { diff --git a/src/entity_manager.h b/src/entity_manager.h index 7fd82fc..65fa6ca 100644 --- a/src/entity_manager.h +++ b/src/entity_manager.h @@ -7,7 +7,7 @@ #include #include #include "component.h" -#include "algorithms.h" +#include "util.h" class EntityManager { private: diff --git a/src/game.cpp b/src/game.cpp index 1182689..228ff23 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -10,12 +10,11 @@ #include "systems/mapping.h" #include "systems/orienting.h" #include "animation.h" -#include "renderer.h" #include "consts.h" void key_callback(GLFWwindow* window, int key, int, int action, int) { - Game& game = *((Game*) glfwGetWindowUserPointer(window)); + Game& game = *static_cast(glfwGetWindowUserPointer(window)); if ((action == GLFW_PRESS) && (key == GLFW_KEY_ESCAPE)) { @@ -27,10 +26,7 @@ void key_callback(GLFWwindow* window, int key, int, int action, int) game.systemManager_.input(key, action); } -Game::Game( - GLFWwindow* window) : - window_(window), - world_("res/maps.xml") +Game::Game() : world_("res/maps.xml") { systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); @@ -65,8 +61,8 @@ Game::Game( systemManager_.getSystem().loadMap(world_.getStartingMapId()); glfwSwapInterval(1); - glfwSetWindowUserPointer(window_, this); - glfwSetKeyCallback(window_, key_callback); + glfwSetWindowUserPointer(renderer_.getWindow().getHandle(), this); + glfwSetKeyCallback(renderer_.getWindow().getHandle(), key_callback); } void Game::execute() @@ -76,7 +72,8 @@ void Game::execute() double accumulator = 0.0; Texture texture(GAME_WIDTH, GAME_HEIGHT); - while (!(shouldQuit_ || glfwWindowShouldClose(window_))) + while (!(shouldQuit_ || + glfwWindowShouldClose(renderer_.getWindow().getHandle()))) { double currentTime = glfwGetTime(); double frameTime = currentTime - lastTime; @@ -93,8 +90,8 @@ void Game::execute() } // Render - texture.fill(texture.entirety(), 0, 0, 0); + renderer_.fill(texture, texture.entirety(), 0, 0, 0); systemManager_.render(texture); - texture.renderScreen(); + renderer_.renderScreen(texture); } } diff --git a/src/game.h b/src/game.h index 346d67e..43e08da 100644 --- a/src/game.h +++ b/src/game.h @@ -1,18 +1,23 @@ #ifndef GAME_H_1014DDC9 #define GAME_H_1014DDC9 -#include "renderer.h" #include "entity_manager.h" #include "system_manager.h" #include "world.h" +#include "renderer/renderer.h" class Game { public: - Game(GLFWwindow* window); + Game(); void execute(); + inline Renderer& getRenderer() + { + return renderer_; + } + inline EntityManager& getEntityManager() { return entityManager_; @@ -37,7 +42,7 @@ public: private: - GLFWwindow* const window_; + Renderer renderer_; EntityManager entityManager_; SystemManager systemManager_; World world_; diff --git a/src/main.cpp b/src/main.cpp index d51da7d..ddbc15f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,27 +1,14 @@ -#include -#include -#include -#include "renderer.h" #include "muxer.h" #include "game.h" int main() { - srand(time(NULL)); - - GLFWwindow* window = initRenderer(); - glfwSwapInterval(1); - initMuxer(); - // Put this in a block so game goes out of scope before we destroy the renderer - { - Game game {window}; - game.execute(); - } + Game game; + game.execute(); destroyMuxer(); - destroyRenderer(); return 0; } diff --git a/src/renderer.cpp b/src/renderer.cpp deleted file mode 100644 index f840180..0000000 --- a/src/renderer.cpp +++ /dev/null @@ -1,862 +0,0 @@ -#include "renderer.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "consts.h" - -// include stb_image -#define STB_IMAGE_IMPLEMENTATION -#define STBI_ONLY_PNG -#define STBI_ONLY_BMP -#include "stb_image.h" - -static bool rendererInitialized = false; - -static GLFWwindow* window; - -static GLuint generic_framebuffer; // The framebuffer -static GLuint bloom_framebuffer; -static GLuint bloom_depthbuffer; -static int buffer_width = 1024; -static int buffer_height = 768; - -static GLuint ntscShader; // The NTSC shader -static GLuint finalShader; // The passthrough shader -static GLuint blitShader; // The blitting shader -static GLuint fillShader; // The fill shader -static GLuint bloom1Shader; -static GLuint bloom2Shader; - -// The buffers for the NTSC rendering process -static GLuint renderedTexBufs[2]; -static int curBuf; -static GLuint artifactsTex; -static GLuint scanlinesTex; -static GLuint preBloomTex; -static GLuint bloomPassTex1; -static GLuint bloomPassTex2; - -// The VAO -static GLuint VertexArrayID; - -// A plane that fills the renderbuffer -static GLuint quad_vertexbuffer; - -// Buffers for the mesh -static GLuint mesh_vertexbuffer; -static GLuint mesh_uvbuffer; -static GLuint mesh_normalbuffer; -static int mesh_numvertices; - -GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path) -{ - // Create the shaders - GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); - GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); - - // Read the Vertex Shader code from the file - std::string VertexShaderCode; - std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); - if(VertexShaderStream.is_open()) - { - std::string Line = ""; - while(getline(VertexShaderStream, Line)) - VertexShaderCode += "\n" + Line; - VertexShaderStream.close(); - } - - // Read the Fragment Shader code from the file - std::string FragmentShaderCode; - std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); - if(FragmentShaderStream.is_open()){ - std::string Line = ""; - while(getline(FragmentShaderStream, Line)) - FragmentShaderCode += "\n" + Line; - FragmentShaderStream.close(); - } - - GLint Result = GL_FALSE; - int InfoLogLength; - - // Compile Vertex Shader - printf("Compiling shader : %s\n", vertex_file_path); - char const * VertexSourcePointer = VertexShaderCode.c_str(); - glShaderSource(VertexShaderID, 1, &VertexSourcePointer , nullptr); - glCompileShader(VertexShaderID); - - // Check Vertex Shader - glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); - glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); - std::vector VertexShaderErrorMessage(InfoLogLength); - glGetShaderInfoLog(VertexShaderID, InfoLogLength, nullptr, &VertexShaderErrorMessage[0]); - fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]); - - // Compile Fragment Shader - printf("Compiling shader : %s\n", fragment_file_path); - char const * FragmentSourcePointer = FragmentShaderCode.c_str(); - glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , nullptr); - glCompileShader(FragmentShaderID); - - // Check Fragment Shader - glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); - glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); - std::vector FragmentShaderErrorMessage(InfoLogLength); - glGetShaderInfoLog(FragmentShaderID, InfoLogLength, nullptr, &FragmentShaderErrorMessage[0]); - fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]); - - // Link the program - fprintf(stdout, "Linking program\n"); - GLuint ProgramID = glCreateProgram(); - glAttachShader(ProgramID, VertexShaderID); - glAttachShader(ProgramID, FragmentShaderID); - glLinkProgram(ProgramID); - - // Check the program - glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); - glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); - std::vector ProgramErrorMessage( glm::max(InfoLogLength, int(1)) ); - glGetProgramInfoLog(ProgramID, InfoLogLength, nullptr, &ProgramErrorMessage[0]); - fprintf(stdout, "%s\n", &ProgramErrorMessage[0]); - - glDeleteShader(VertexShaderID); - glDeleteShader(FragmentShaderID); - - return ProgramID; -} - -void flipImageData(unsigned char* data, int width, int height, int comps) -{ - unsigned char* data_copy = (unsigned char*) malloc(width*height*comps*sizeof(unsigned char)); - memcpy(data_copy, data, width*height*comps); - - int row_size = width * comps; - - for (int i=0;i& out_vertices, std::vector& out_uvs, std::vector& out_normals) -{ - out_vertices.clear(); - out_uvs.clear(); - out_normals.clear(); - - FILE* file = fopen(filename, "r"); - if (file == nullptr) - { - fprintf(stderr, "Could not open mesh file %s\n", filename); - exit(1); - } - - std::vector temp_vertices; - std::vector temp_uvs; - std::vector temp_normals; - - for (;;) - { - char lineHeader[256]; - int res = fscanf(file, "%s", lineHeader); - if (res == EOF) - { - break; - } - - if (!strncmp(lineHeader, "v", 2)) - { - glm::vec3 vertex; - fscanf(file, "%f %f %f\n", &vertex.x,&vertex.y,&vertex.z); - temp_vertices.push_back(vertex); - } else if (!strncmp(lineHeader, "vt", 3)) - { - glm::vec2 uv; - fscanf(file, "%f %f\n", &uv.x, &uv.y); - temp_uvs.push_back(uv); - } else if (!strncmp(lineHeader, "vn", 3)) - { - glm::vec3 normal; - fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z); - temp_normals.push_back(normal); - } else if (!strncmp(lineHeader, "f", 2)) - { - int vertexIDs[3], uvIDs[3], normalIDs[3]; - fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIDs[0], &uvIDs[0], &normalIDs[0], &vertexIDs[1], &uvIDs[1], &normalIDs[1], &vertexIDs[2], &uvIDs[2], &normalIDs[2]); - - for (int i=0; i<3; i++) - { - out_vertices.push_back(temp_vertices[vertexIDs[i] - 1]); - out_uvs.push_back(temp_uvs[uvIDs[i] - 1]); - out_normals.push_back(temp_normals[normalIDs[i] - 1]); - } - } - } -} - -void setFramebufferSize(GLFWwindow* w, int width, int height) -{ - buffer_width = width; - buffer_height = height; - - glDeleteFramebuffers(1, &bloom_framebuffer); - glDeleteRenderbuffers(1, &bloom_depthbuffer); - - glGenFramebuffers(1, &bloom_framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); - GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT1}; - glDrawBuffers(1, DrawBuffers); - - glGenRenderbuffers(1, &bloom_depthbuffer); - glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer); - - glDeleteTextures(1, &preBloomTex); - glDeleteTextures(1, &bloomPassTex1); - glDeleteTextures(1, &bloomPassTex2); - - glGenTextures(1, &preBloomTex); - glBindTexture(GL_TEXTURE_2D, preBloomTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenTextures(1, &bloomPassTex1); - glBindTexture(GL_TEXTURE_2D, bloomPassTex1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenTextures(1, &bloomPassTex2); - glBindTexture(GL_TEXTURE_2D, bloomPassTex2); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width/4, height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -} - -GLFWwindow* initRenderer() -{ - if (rendererInitialized) - { - fprintf(stderr, "Renderer already initialized\n"); - exit(-1); - } - - // Initialize GLFW - if (!glfwInit()) - { - fprintf(stderr, "Failed to initialize GLFW\n"); - exit(-1); - } - - glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want version 3.3 - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Mac requires this - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - - // Create a window - window = glfwCreateWindow(1024, 768, "Aromatherapy", nullptr, nullptr); - if (window == nullptr) - { - fprintf(stderr, "Failed to open GLFW window\n"); - glfwTerminate(); - exit(-1); - } - - glfwMakeContextCurrent(window); - glewExperimental = true; // Needed in core profile - if (glewInit() != GLEW_OK) - { - fprintf(stderr, "Failed to initialize GLEW\n"); - exit(-1); - } - - glfwSetFramebufferSizeCallback(window, &setFramebufferSize); - - // Set up vertex array object - glGenVertexArrays(1, &VertexArrayID); - glBindVertexArray(VertexArrayID); - - // Enable depth testing - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - // Enable blending - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - // Set up the framebuffer - glGenFramebuffers(1, &generic_framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; - glDrawBuffers(1, DrawBuffers); - - glGenFramebuffers(1, &bloom_framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); - GLenum DrawBuffers2[1] = {GL_COLOR_ATTACHMENT1}; - glDrawBuffers(1, DrawBuffers2); - - glfwGetFramebufferSize(window, &buffer_width, &buffer_height); - - glGenRenderbuffers(1, &bloom_depthbuffer); - glBindRenderbuffer(GL_RENDERBUFFER, bloom_depthbuffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, buffer_width, buffer_height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bloom_depthbuffer); - - // Set up the NTSC rendering buffers - glGenTextures(2, renderedTexBufs); - glBindTexture(GL_TEXTURE_2D, renderedTexBufs[0]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glBindTexture(GL_TEXTURE_2D, renderedTexBufs[1]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GAME_WIDTH, GAME_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // Set up bloom rendering buffers - glGenTextures(1, &preBloomTex); - glBindTexture(GL_TEXTURE_2D, preBloomTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, buffer_width, buffer_height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenTextures(1, &bloomPassTex1); - glBindTexture(GL_TEXTURE_2D, bloomPassTex1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, buffer_width/4, buffer_height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenTextures(1, &bloomPassTex2); - glBindTexture(GL_TEXTURE_2D, bloomPassTex2); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, buffer_width/4, buffer_height/4, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - curBuf = 0; - - // Load the mesh! - std::vector mesh_vertices; - std::vector mesh_uvs; - std::vector mesh_normals; - - loadMesh("res/monitor-old.obj", mesh_vertices, mesh_uvs, mesh_normals); - - mesh_numvertices = mesh_vertices.size(); - - glGenBuffers(1, &mesh_vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, mesh_vertices.size() * sizeof(glm::vec3), mesh_vertices.data(), GL_STATIC_DRAW); - - glGenBuffers(1, &mesh_uvbuffer); - glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer); - glBufferData(GL_ARRAY_BUFFER, mesh_uvs.size() * sizeof(glm::vec2), mesh_uvs.data(), GL_STATIC_DRAW); - - glGenBuffers(1, &mesh_normalbuffer); - glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer); - glBufferData(GL_ARRAY_BUFFER, mesh_normals.size() * sizeof(glm::vec3), mesh_normals.data(), GL_STATIC_DRAW); - - // Load the vertices of a flat surface - GLfloat g_quad_vertex_buffer_data[] = { - -1.0f, -1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, - }; - - glGenBuffers(1, &quad_vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW); - - glGenTextures(1, &artifactsTex); - glBindTexture(GL_TEXTURE_2D, artifactsTex); - int atdw, atdh; - unsigned char* artifactsTex_data = stbi_load("res/artifacts.bmp", &atdw, &atdh, 0, 3); - flipImageData(artifactsTex_data, atdw, atdh, 3); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, atdw, atdh, 0, GL_RGB, GL_UNSIGNED_BYTE, artifactsTex_data); - stbi_image_free(artifactsTex_data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); - glGenerateMipmap(GL_TEXTURE_2D); - - glGenTextures(1, &scanlinesTex); - glBindTexture(GL_TEXTURE_2D, scanlinesTex); - int stdw, stdh; - unsigned char* scanlinesTex_data = stbi_load("res/scanlines_333.bmp", &stdw, &stdh, 0, 3); - flipImageData(scanlinesTex_data, stdw, stdh, 3); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, atdw, atdh, 0, GL_RGB, GL_UNSIGNED_BYTE, scanlinesTex_data); - stbi_image_free(scanlinesTex_data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); - glGenerateMipmap(GL_TEXTURE_2D); - - // Load the shaders - ntscShader = LoadShaders("shaders/ntsc.vertex", "shaders/ntsc.fragment"); - finalShader = LoadShaders("shaders/final.vertex", "shaders/final.fragment"); - blitShader = LoadShaders("shaders/blit.vertex", "shaders/blit.fragment"); - fillShader = LoadShaders("shaders/fill.vertex", "shaders/fill.fragment"); - bloom1Shader = LoadShaders("shaders/bloom1.vertex", "shaders/bloom1.fragment"); - bloom2Shader = LoadShaders("shaders/bloom2.vertex", "shaders/bloom2.fragment"); - - rendererInitialized = true; - - return window; -} - -void destroyRenderer() -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - // Delete the plane buffer - glDeleteBuffers(1, &quad_vertexbuffer); - glDeleteBuffers(1, &mesh_vertexbuffer); - glDeleteBuffers(1, &mesh_uvbuffer); - glDeleteBuffers(1, &mesh_normalbuffer); - - // Delete the shaders - glDeleteProgram(ntscShader); - glDeleteProgram(finalShader); - glDeleteProgram(blitShader); - glDeleteProgram(fillShader); - glDeleteProgram(bloom1Shader); - glDeleteProgram(bloom2Shader); - - // Delete the NTSC rendering buffers - glDeleteTextures(2, renderedTexBufs); - glDeleteTextures(1, &artifactsTex); - glDeleteTextures(1, &scanlinesTex); - glDeleteTextures(1, &preBloomTex); - glDeleteTextures(1, &bloomPassTex1); - glDeleteTextures(1, &bloomPassTex2); - - // Delete the framebuffer - glDeleteRenderbuffers(1, &bloom_depthbuffer); - glDeleteFramebuffers(1, &bloom_framebuffer); - glDeleteFramebuffers(1, &generic_framebuffer); - - // Delete the VAO - glDeleteVertexArrays(1, &VertexArrayID); - - // Kill the window - glfwTerminate(); - - rendererInitialized = false; -} - -Texture::Texture(int width, int height) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - this->width = width; - this->height = height; - - glGenTextures(1, &texID); - glBindTexture(GL_TEXTURE_2D, texID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); -} - -Texture::Texture(const char* filename) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - glGenTextures(1, &texID); - glBindTexture(GL_TEXTURE_2D, texID); - unsigned char* data = stbi_load(filename, &width, &height, 0, 4); - flipImageData(data, width, height, 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - stbi_image_free(data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -} - -Texture::Texture(const Texture& tex) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - width = tex.width; - height = tex.height; - - unsigned char* data = (unsigned char*) malloc(4 * width * height); - glBindTexture(GL_TEXTURE_2D, tex.texID); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - - glGenTextures(1, &texID); - glBindTexture(GL_TEXTURE_2D, texID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - - free(data); -} - -Texture::Texture(Texture&& tex) : Texture(0, 0) -{ - swap(*this, tex); -} - -Texture::~Texture() -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - glDeleteTextures(1, &texID); -} - -Texture& Texture::operator= (Texture tex) -{ - swap(*this, tex); - - return *this; -} - -void swap(Texture& tex1, Texture& tex2) -{ - std::swap(tex1.width, tex2.width); - std::swap(tex1.height, tex2.height); - std::swap(tex1.texID, tex2.texID); -} - -void Texture::fill(Rectangle dstrect, int r, int g, int b) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - // Target the framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0); - - // Set up the vertex attributes - GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; - GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); - GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; - GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); - - GLfloat vertexbuffer_data[] = { - minx, miny, - maxx, miny, - maxx, maxy, - minx, miny, - minx, maxy, - maxx, maxy - }; - GLuint vertexbuffer; - glGenBuffers(1, &vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - - glViewport(0, 0, width, height); - glClear(GL_DEPTH_BUFFER_BIT); - glUseProgram(fillShader); - glUniform3f(glGetUniformLocation(fillShader, "vecColor"), r / 255.0, g / 255.0, b / 255.0); - - glDrawArrays(GL_TRIANGLES, 0, 6); - - glDisableVertexAttribArray(0); - glDeleteBuffers(1, &vertexbuffer); -} - -void Texture::blit(const Texture& srctex, Rectangle srcrect, Rectangle dstrect, double alpha) -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - alpha = glm::clamp(alpha, 0.0, 1.0); - - // Target the framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texID, 0); - - // Set up the vertex attributes - GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; - GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); - GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; - GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); - - GLfloat vertexbuffer_data[] = { - minx, miny, - maxx, miny, - minx, maxy, - maxx, maxy - }; - GLuint vertexbuffer; - glGenBuffers(1, &vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertexbuffer_data), vertexbuffer_data, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - - GLfloat minu = (GLfloat) srcrect.x / srctex.width; - GLfloat minv = 1 - ((GLfloat) srcrect.y / srctex.height); - GLfloat maxu = (GLfloat) (srcrect.x + srcrect.w) / srctex.width; - GLfloat maxv = 1 - ((GLfloat) (srcrect.y + srcrect.h) / srctex.height); - - GLfloat texcoordbuffer_data[] = { - minu, minv, - maxu, minv, - minu, maxv, - maxu, maxv - }; - GLuint texcoordbuffer; - glGenBuffers(1, &texcoordbuffer); - glBindBuffer(GL_ARRAY_BUFFER, texcoordbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(texcoordbuffer_data), texcoordbuffer_data, GL_STATIC_DRAW); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - - // Set up the shader - glUseProgram(blitShader); - glClear(GL_DEPTH_BUFFER_BIT); - glViewport(0, 0, width, height); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, srctex.texID); - glUniform1i(glGetUniformLocation(blitShader, "srctex"), 0); - glUniform1f(glGetUniformLocation(blitShader, "alpha"), alpha); - - // Blit! - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - // Unload everything - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(0); - glDeleteBuffers(1, &texcoordbuffer); - glDeleteBuffers(1, &vertexbuffer); -} - -void bloomPass1(GLuint srcTex, GLuint dstTex, bool horizontal, glm::vec2 srcRes, glm::vec2 dstRes) -{ - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dstTex, 0); - glViewport(0,0,dstRes.x,dstRes.y); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(bloom1Shader); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, srcTex); - glUniform1i(glGetUniformLocation(bloom1Shader, "inTex"), 0); - - glm::vec2 offset = glm::vec2(0.0); - if (horizontal) - { - offset.x = 1.2/srcRes.x; - } else { - offset.y = 1.2/srcRes.y; - } - - glUniform2f(glGetUniformLocation(bloom1Shader, "offset"), offset.x, offset.y); - - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - glDrawArrays(GL_TRIANGLES, 0, 6); - glDisableVertexAttribArray(0); -} - -void Texture::renderScreen() const -{ - if (!rendererInitialized) - { - fprintf(stderr, "Renderer not initialized\n"); - exit(-1); - } - - // First we're going to composite our frame with the previous frame - // We start by setting up the framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, generic_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexBufs[curBuf], 0); - - // Set up the shader - glViewport(0,0,GAME_WIDTH,GAME_HEIGHT); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(ntscShader); - - // Use the current frame texture, nearest neighbor and clamped to edge - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texID); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glUniform1i(glGetUniformLocation(ntscShader, "curFrameSampler"), 0); - - // Use the previous frame composite texture, nearest neighbor and clamped to edge - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, renderedTexBufs[(curBuf + 1) % 2]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glUniform1i(glGetUniformLocation(ntscShader, "prevFrameSampler"), 1); - - // Load the NTSC artifact texture - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, artifactsTex); - glUniform1i(glGetUniformLocation(ntscShader, "NTSCArtifactSampler"), 2); - glUniform1f(glGetUniformLocation(ntscShader, "NTSCLerp"), curBuf * 1.0); - - if ((rand() % 60) == 0) - { - // Change the 0.0 to a 1.0 or a 10.0 for a glitchy effect! - glUniform1f(glGetUniformLocation(ntscShader, "Tuning_NTSC"), 0.0); - } else { - glUniform1f(glGetUniformLocation(ntscShader, "Tuning_NTSC"), 0.0); - } - - // Render our composition - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - glDrawArrays(GL_TRIANGLES, 0, 6); - glDisableVertexAttribArray(0); - - // We're going to render the screen now - glBindFramebuffer(GL_FRAMEBUFFER, bloom_framebuffer); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, preBloomTex, 0); - glViewport(0,0,buffer_width,buffer_height); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(finalShader); - - // Use the composited frame texture, linearly filtered and filling in black for the border - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, renderedTexBufs[curBuf]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - float border_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); - glGenerateMipmap(GL_TEXTURE_2D); - glUniform1i(glGetUniformLocation(finalShader, "rendertex"), 0); - - // Use the scanlines texture - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, scanlinesTex); - glUniform1i(glGetUniformLocation(finalShader, "scanlinestex"), 1); - - // Initialize the MVP matrices - glm::mat4 p_matrix = glm::perspective(glm::radians(25.0f), (float) buffer_width / (float) buffer_height, 0.1f, 100.0f); - glm::mat4 v_matrix = glm::lookAt(glm::vec3(3.75,0,0), glm::vec3(0,0,0), glm::vec3(0,1,0)); - glm::mat4 m_matrix = glm::mat4(1.0); - glm::mat4 mvp_matrix = p_matrix * v_matrix * m_matrix; - - glUniformMatrix4fv(glGetUniformLocation(finalShader, "MVP"), 1, GL_FALSE, &mvp_matrix[0][0]); - glUniformMatrix4fv(glGetUniformLocation(finalShader, "worldMat"), 1, GL_FALSE, &m_matrix[0][0]); - glUniform2f(glGetUniformLocation(finalShader, "resolution"), buffer_width, buffer_height); - glUniform1f(glGetUniformLocation(finalShader, "iGlobalTime"), glfwGetTime()); - glUniform3f(glGetUniformLocation(finalShader, "frameColor"), 0.76f, 0.78f, 0.81f); - - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, mesh_vertexbuffer); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - - glEnableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, mesh_normalbuffer); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - - glEnableVertexAttribArray(2); - glBindBuffer(GL_ARRAY_BUFFER, mesh_uvbuffer); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); - - glDrawArrays(GL_TRIANGLES, 0, mesh_numvertices); - glDisableVertexAttribArray(2); - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(0); - - // First pass of bloom! - glm::vec2 buffer_size = glm::vec2(buffer_width, buffer_height); - bloomPass1(preBloomTex, bloomPassTex1, true, buffer_size, buffer_size / 4.0f); - bloomPass1(bloomPassTex1, bloomPassTex2, false, buffer_size / 4.0f, buffer_size / 4.0f); - - // Do the second pass of bloom and render to screen - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glViewport(0, 0, buffer_width, buffer_height); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(bloom2Shader); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, preBloomTex); - glUniform1i(glGetUniformLocation(bloom2Shader, "clearTex"), 0); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, bloomPassTex2); - glUniform1i(glGetUniformLocation(bloom2Shader, "blurTex"), 1); - - glUniform1f(glGetUniformLocation(bloom2Shader, "iGlobalTime"), glfwGetTime()); - - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); - glDrawArrays(GL_TRIANGLES, 0, 6); - glDisableVertexAttribArray(0); - - glfwSwapBuffers(window); - - curBuf = (curBuf + 1) % 2; -} - -Rectangle Texture::entirety() const -{ - return {0, 0, width, height}; -} diff --git a/src/renderer.h b/src/renderer.h deleted file mode 100644 index 6dccf7a..0000000 --- a/src/renderer.h +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include - -#ifndef RENDERER_H -#define RENDERER_H - -struct Rectangle { - int x; - int y; - int w; - int h; -}; - -class Texture { - public: - Texture(int width, int height); - Texture(const char* file); - Texture(const Texture& tex); - Texture(Texture&& tex); - ~Texture(); - Texture& operator= (Texture tex); - friend void swap(Texture& tex1, Texture& tex2); - void fill(Rectangle loc, int r, int g, int b); - void blit(const Texture& src, Rectangle srcrect, Rectangle dstrect, double alpha = 1.0); - void renderScreen() const; - Rectangle entirety() const; - - private: - GLuint texID; - int width; - int height; -}; - -GLFWwindow* initRenderer(); -void destroyRenderer(); - -#endif diff --git a/src/renderer/gl.h b/src/renderer/gl.h new file mode 100644 index 0000000..4e98c42 --- /dev/null +++ b/src/renderer/gl.h @@ -0,0 +1,7 @@ +#ifndef GL_H_3EE4A268 +#define GL_H_3EE4A268 + +#include +#include + +#endif /* end of include guard: GL_H_3EE4A268 */ diff --git a/src/renderer/mesh.cpp b/src/renderer/mesh.cpp new file mode 100644 index 0000000..b06b723 --- /dev/null +++ b/src/renderer/mesh.cpp @@ -0,0 +1,109 @@ +#include "mesh.h" +#include +#include +#include +#include +#include "util.h" + +Mesh::Mesh(std::string filename) +{ + std::ifstream meshfile(filename); + if (!meshfile.is_open()) + { + throw std::invalid_argument("Could not open mesh file"); + } + + std::vector tempVertices; + std::vector tempUvs; + std::vector tempNormals; + + std::vector outVertices; + std::vector outUvs; + std::vector outNormals; + std::map elementIds; + std::vector indices; + + while (meshfile) + { + std::string linetype; + meshfile >> linetype; + + if (linetype == "v") + { + glm::vec3 vertex; + meshfile >> vertex.x >> vertex.y >> vertex.z; + + tempVertices.push_back(std::move(vertex)); + } else if (linetype == "vt") + { + glm::vec2 uv; + meshfile >> uv.x >> uv.y; + + tempUvs.push_back(std::move(uv)); + } else if (linetype == "vn") + { + glm::vec3 normal; + meshfile >> normal.x >> normal.y >> normal.z; + + tempNormals.push_back(std::move(normal)); + } else if (linetype == "f") + { + element elements[3]; + + meshfile + >> elements[0].vertexId >> chlit('/') + >> elements[0].uvId >> chlit('/') + >> elements[0].normalId + >> elements[1].vertexId >> chlit('/') + >> elements[1].uvId >> chlit('/') + >> elements[1].normalId + >> elements[2].vertexId >> chlit('/') + >> elements[2].uvId >> chlit('/') + >> elements[2].normalId; + + for (size_t i = 0; i < 3; i++) + { + if (!elementIds.count(elements[i])) + { + elementIds[elements[i]] = outVertices.size(); + + outVertices.push_back(tempVertices[elements[i].vertexId - 1]); + outUvs.push_back(tempUvs[elements[i].uvId - 1]); + outNormals.push_back(tempNormals[elements[i].normalId - 1]); + } + + indices.push_back(elementIds[elements[i]]); + } + } + } + + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer_.getId()); + glBufferData( + GL_ARRAY_BUFFER, + outVertices.size() * sizeof(glm::vec3), + outVertices.data(), + GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, uvBuffer_.getId()); + glBufferData( + GL_ARRAY_BUFFER, + outUvs.size() * sizeof(glm::vec2), + outUvs.data(), + GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, normalBuffer_.getId()); + glBufferData( + GL_ARRAY_BUFFER, + outNormals.size() * sizeof(glm::vec3), + outNormals.data(), + GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer_.getId()); + glBufferData( + GL_ELEMENT_ARRAY_BUFFER, + indices.size() * sizeof(unsigned short), + indices.data(), + GL_STATIC_DRAW); + + indexCount_ = indices.size(); +} diff --git a/src/renderer/mesh.h b/src/renderer/mesh.h new file mode 100644 index 0000000..06bf65d --- /dev/null +++ b/src/renderer/mesh.h @@ -0,0 +1,62 @@ +#ifndef MESH_H_76B72E12 +#define MESH_H_76B72E12 + +#include +#include "gl.h" +#include "wrappers.h" + +class Mesh { +public: + + Mesh(std::string filename); + + Mesh(const Mesh& other) = delete; + Mesh& operator=(const Mesh& other) = delete; + + inline GLuint getVertexBufferId() const + { + return vertexBuffer_.getId(); + } + + inline GLuint getUvBufferId() const + { + return uvBuffer_.getId(); + } + + inline GLuint getNormalBufferId() const + { + return normalBuffer_.getId(); + } + + inline GLuint getIndexBufferId() const + { + return indexBuffer_.getId(); + } + + inline size_t getIndexCount() const + { + return indexCount_; + } + +private: + + struct element { + size_t vertexId; + size_t uvId; + size_t normalId; + + bool operator<(const element& other) const + { + return std::tie(vertexId, uvId, normalId) < + std::tie(other.vertexId, other.uvId, other.normalId); + } + }; + + GLBuffer vertexBuffer_; + GLBuffer uvBuffer_; + GLBuffer normalBuffer_; + GLBuffer indexBuffer_; + size_t indexCount_; +}; + +#endif /* end of include guard: MESH_H_76B72E12 */ diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp new file mode 100644 index 0000000..6eef2f3 --- /dev/null +++ b/src/renderer/renderer.cpp @@ -0,0 +1,635 @@ +#include "renderer.h" +#include "consts.h" +#include "game.h" +#include +#include "texture.h" + +// include stb_image +#define STB_IMAGE_IMPLEMENTATION +#define STBI_ONLY_PNG +#define STBI_ONLY_BMP +#include "stb_image.h" + +void setFramebufferSize(GLFWwindow* w, int width, int height) +{ + Game& game = *static_cast(glfwGetWindowUserPointer(w)); + Renderer& renderer = game.getRenderer(); + + renderer.width_ = width; + renderer.height_ = height; + + renderer.bloomFb_ = {}; + renderer.bloomDepth_ = {}; + renderer.preBloomTex_ = {}; + renderer.bloomPassTex1_ = {}; + renderer.bloomPassTex2_ = {}; + + renderer.initializeFramebuffers(); +} + +bool Renderer::singletonInitialized_ = false; + +Renderer::Window::Window() +{ + // Initialize GLFW + if (!glfwInit()) + { + throw std::runtime_error("Failed to initialize GLFW"); + } + + glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want version 3.3 + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Mac requires this + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + // Create a window + window_ = glfwCreateWindow(1024, 768, "Aromatherapy", nullptr, nullptr); + if (window_ == nullptr) + { + throw std::runtime_error("Failed to open GLFW window"); + } + + glfwMakeContextCurrent(window_); + + glewExperimental = true; // Needed in core profile + if (glewInit() != GLEW_OK) + { + throw std::runtime_error("Failed to initialize GLEW"); + } + + glfwSetFramebufferSizeCallback(window_, &setFramebufferSize); +} + +Renderer::Window::~Window() +{ + glfwTerminate(); +} + +Renderer::Renderer() : + monitor_("res/monitor-old.obj"), + ntscShader_("ntsc"), + finalShader_("final"), + blitShader_("blit"), + fillShader_("fill"), + bloom1Shader_("bloom1"), + bloom2Shader_("bloom2") +{ + if (singletonInitialized_) + { + throw std::logic_error("Singleton renderer already initialized"); + } + + singletonInitialized_ = true; + + // Set up vertex array object + glBindVertexArray(vao_.getId()); + + // Enable depth testing + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + + // Enable blending + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // Set up the rendering buffers and textures + glfwGetFramebufferSize(window_.getHandle(), &width_, &height_); + + initializeFramebuffers(); + + // Load the vertices of a flat surface + GLfloat g_quad_vertex_buffer_data[] = { + -1.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + }; + + glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId()); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(GLfloat) * 18, + g_quad_vertex_buffer_data, + GL_STATIC_DRAW); + + // Load NTSC artifacts + int atdw, atdh; + unsigned char* artifactsData = + stbi_load("res/artifacts.bmp", &atdw, &atdh, 0, 3); + + flipImageData(artifactsData, atdw, atdh, 3); + + glBindTexture(GL_TEXTURE_2D, artifactsTex_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + atdw, + atdh, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + artifactsData); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri( + GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, + GL_NEAREST_MIPMAP_NEAREST); + + glGenerateMipmap(GL_TEXTURE_2D); + stbi_image_free(artifactsData); + + // Load NTSC scanlines + unsigned char* scanlinesData = + stbi_load("res/scanlines_333.bmp", &atdw, &atdh, 0, 3); + + flipImageData(scanlinesData, atdw, atdh, 3); + + glBindTexture(GL_TEXTURE_2D, scanlinesTex_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + atdw, + atdh, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + scanlinesData); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri( + GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, + GL_NEAREST_MIPMAP_NEAREST); + + glGenerateMipmap(GL_TEXTURE_2D); + stbi_image_free(scanlinesData); +} + +void Renderer::initializeFramebuffers() +{ + // Set up the framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; + glDrawBuffers(1, DrawBuffers); + + // Set up the bloom framebuffer and depthbuffer + glBindFramebuffer(GL_FRAMEBUFFER, bloomFb_.getId()); + GLenum DrawBuffers2[1] = {GL_COLOR_ATTACHMENT1}; + glDrawBuffers(1, DrawBuffers2); + + glBindRenderbuffer(GL_RENDERBUFFER, bloomDepth_.getId()); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width_, height_); + glFramebufferRenderbuffer( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, + bloomDepth_.getId()); + + // Set up the NTSC rendering buffers + glBindTexture(GL_TEXTURE_2D, renderPages_[0].getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + GAME_WIDTH, + GAME_HEIGHT, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, renderPages_[1].getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + GAME_WIDTH, + GAME_HEIGHT, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // Set up bloom rendering buffers + glBindTexture(GL_TEXTURE_2D, preBloomTex_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + width_, + height_, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, bloomPassTex1_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + width_ / 4, + height_ / 4, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, bloomPassTex2_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + width_ / 4, + height_ / 4, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +Renderer::~Renderer() +{ + singletonInitialized_ = false; +} + +void Renderer::fill(Texture& tex, Rectangle dstrect, int r, int g, int b) +{ + // Target the framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex.getId(), 0); + + // Set up the vertex attributes + int width = tex.getWidth(); + int height = tex.getHeight(); + + GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; + GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); + GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; + GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); + + GLfloat vertexData[] = { + minx, miny, + maxx, miny, + maxx, maxy, + minx, miny, + minx, maxy, + maxx, maxy + }; + + GLBuffer vertexBuffer; + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.getId()); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(GLfloat) * 12, + vertexData, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + glViewport(0, 0, tex.getWidth(), tex.getHeight()); + glClear(GL_DEPTH_BUFFER_BIT); + + fillShader_.use(); + glUniform3f( + fillShader_.getUniformLocation("vecColor"), + r / 255.0, + g / 255.0, + b / 255.0); + + glDrawArrays(GL_TRIANGLES, 0, 6); + + glDisableVertexAttribArray(0); +} + +void Renderer::blit( + const Texture& src, + Texture& dst, + Rectangle srcrect, + Rectangle dstrect, + double alpha) +{ + alpha = glm::clamp(alpha, 0.0, 1.0); + + // Target the framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dst.getId(), 0); + + // Set up the vertex attributes + int width = dst.getWidth(); + int height = dst.getHeight(); + + GLfloat minx = (GLfloat) dstrect.x / width * 2.0 - 1.0; + GLfloat miny = -((GLfloat) dstrect.y / height * 2.0 - 1.0); + GLfloat maxx = (GLfloat) (dstrect.x + dstrect.w) / width * 2.0 - 1.0; + GLfloat maxy = -((GLfloat) (dstrect.y + dstrect.h) / height * 2.0 - 1.0); + + GLfloat vertexData[] = { + minx, miny, + maxx, miny, + minx, maxy, + maxx, maxy + }; + + GLBuffer vertexBuffer; + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.getId()); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(GLfloat) * 8, + vertexData, + GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + GLfloat minu = (GLfloat) srcrect.x / src.getWidth(); + GLfloat minv = 1 - ((GLfloat) srcrect.y / src.getHeight()); + GLfloat maxu = (GLfloat) (srcrect.x + srcrect.w) / src.getWidth(); + GLfloat maxv = 1 - ((GLfloat) (srcrect.y + srcrect.h) / src.getHeight()); + + GLfloat uvData[] = { + minu, minv, + maxu, minv, + minu, maxv, + maxu, maxv + }; + + GLBuffer uvBuffer; + glBindBuffer(GL_ARRAY_BUFFER, uvBuffer.getId()); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(GLfloat) * 8, + uvData, + GL_STATIC_DRAW); + + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + // Set up the shader + blitShader_.use(); + glClear(GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, dst.getWidth(), dst.getHeight()); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, src.getId()); + glUniform1i(blitShader_.getUniformLocation("srctex"), 0); + glUniform1f(blitShader_.getUniformLocation("alpha"), alpha); + + // Blit! + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + // Unload everything + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(0); +} + +void Renderer::bloomPass1( + const GLTexture& src, + GLTexture& dst, + bool horizontal, + glm::vec2 srcRes, + glm::vec2 dstRes) +{ + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dst.getId(), 0); + glViewport(0,0,dstRes.x,dstRes.y); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + bloom1Shader_.use(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, src.getId()); + glUniform1i(bloom1Shader_.getUniformLocation("inTex"), 0); + + glm::vec2 offset = glm::vec2(0.0); + if (horizontal) + { + offset.x = 1.2/srcRes.x; + } else { + offset.y = 1.2/srcRes.y; + } + + glUniform2f(bloom1Shader_.getUniformLocation("offset"), offset.x, offset.y); + + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId()); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + glDrawArrays(GL_TRIANGLES, 0, 6); + glDisableVertexAttribArray(0); +} + +void Renderer::renderScreen(const Texture& tex) +{ + // First we're going to composite our frame with the previous frame + // We start by setting up the framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, genericFb_.getId()); + glFramebufferTexture( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + renderPages_[curBuf_].getId(), + 0); + + // Set up the shader + glViewport(0,0,GAME_WIDTH,GAME_HEIGHT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + ntscShader_.use(); + + // Use the current frame texture, nearest neighbor and clamped to edge + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, tex.getId()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glUniform1i(ntscShader_.getUniformLocation("curFrameSampler"), 0); + + // Use the previous frame composite texture, nearest neighbor and clamped to + // edge + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, renderPages_[(curBuf_ + 1) % 2].getId()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glUniform1i(ntscShader_.getUniformLocation("prevFrameSampler"), 1); + + // Load the NTSC artifact texture + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, artifactsTex_.getId()); + glUniform1i(ntscShader_.getUniformLocation("NTSCArtifactSampler"), 2); + glUniform1f(ntscShader_.getUniformLocation("NTSCLerp"), curBuf_ * 1.0); + + // Change the 0.0 to a 1.0 or a 10.0 for a glitchy effect! + glUniform1f(ntscShader_.getUniformLocation("Tuning_NTSC"), 0.0); + + // Render our composition + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId()); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + glDrawArrays(GL_TRIANGLES, 0, 6); + glDisableVertexAttribArray(0); + + // We're going to render the screen now + glBindFramebuffer(GL_FRAMEBUFFER, bloomFb_.getId()); + glFramebufferTexture( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT1, + preBloomTex_.getId(), + 0); + + glViewport(0,0,width_,height_); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + finalShader_.use(); + + // Use the composited frame texture, linearly filtered and filling in black + // for the border + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, renderPages_[curBuf_].getId()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + + float borderColor[] = {0.0f, 0.0f, 0.0f, 1.0f}; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); + + glGenerateMipmap(GL_TEXTURE_2D); + glUniform1i(finalShader_.getUniformLocation("rendertex"), 0); + + // Use the scanlines texture + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, scanlinesTex_.getId()); + glUniform1i(finalShader_.getUniformLocation("scanlinestex"), 1); + + // Initialize the MVP matrices + glm::mat4 p_matrix = glm::perspective( + glm::radians(25.0f), + static_cast(width_) / static_cast(height_), + 0.1f, + 100.0f); + + glm::mat4 v_matrix = glm::lookAt( + glm::vec3(3.75,0,0), // Camera + glm::vec3(0,0,0), // Center + glm::vec3(0,1,0)); // Up + + glm::mat4 m_matrix = glm::mat4(1.0); + glm::mat4 mvp_matrix = p_matrix * v_matrix * m_matrix; + + glUniformMatrix4fv( + finalShader_.getUniformLocation("MVP"), + 1, + GL_FALSE, + &mvp_matrix[0][0]); + + glUniformMatrix4fv( + finalShader_.getUniformLocation("worldMat"), + 1, + GL_FALSE, + &m_matrix[0][0]); + + glUniform2f(finalShader_.getUniformLocation("resolution"), width_, height_); + glUniform1f(finalShader_.getUniformLocation("iGlobalTime"), glfwGetTime()); + + glUniform3f( + finalShader_.getUniformLocation("frameColor"), + 0.76f, + 0.78f, + 0.81f); + + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, monitor_.getVertexBufferId()); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, monitor_.getNormalBufferId()); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + + glEnableVertexAttribArray(2); + glBindBuffer(GL_ARRAY_BUFFER, monitor_.getUvBufferId()); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, monitor_.getIndexBufferId()); + glDrawElements( + GL_TRIANGLES, + monitor_.getIndexCount(), + GL_UNSIGNED_SHORT, + nullptr); + + glDisableVertexAttribArray(2); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(0); + + // First pass of bloom! + glm::vec2 bufferSize = glm::vec2(width_, height_); + + bloomPass1( + preBloomTex_, + bloomPassTex1_, + true, + bufferSize, + bufferSize / 4.0f); + + bloomPass1( + bloomPassTex1_, + bloomPassTex2_, + false, + bufferSize / 4.0f, + bufferSize / 4.0f); + + // Do the second pass of bloom and render to screen + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, width_, height_); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + bloom2Shader_.use(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, preBloomTex_.getId()); + glUniform1i(bloom2Shader_.getUniformLocation("clearTex"), 0); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, bloomPassTex2_.getId()); + glUniform1i(bloom2Shader_.getUniformLocation("blurTex"), 1); + + glUniform1f(bloom2Shader_.getUniformLocation("iGlobalTime"), glfwGetTime()); + + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, quadBuffer_.getId()); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + glDrawArrays(GL_TRIANGLES, 0, 6); + glDisableVertexAttribArray(0); + + glfwSwapBuffers(window_.getHandle()); + + curBuf_ = (curBuf_ + 1) % 2; +} diff --git a/src/renderer/renderer.h b/src/renderer/renderer.h new file mode 100644 index 0000000..0b10af5 --- /dev/null +++ b/src/renderer/renderer.h @@ -0,0 +1,114 @@ +#ifndef RENDERER_H +#define RENDERER_H + +#include "gl.h" +#include "wrappers.h" +#include "mesh.h" +#include "shader.h" +#include + +class Texture; +struct Rectangle; + +class Renderer { +public: + + class Window { + public: + + Window(); + + Window(const Window& other) = delete; + Window& operator=(const Window& other) = delete; + + ~Window(); + + inline GLFWwindow* getHandle() + { + return window_; + } + + private: + + GLFWwindow* window_; + }; + + static inline bool isSingletonInitialized() + { + return singletonInitialized_; + } + + Renderer(); + + Renderer(const Renderer& other) = delete; + Renderer& operator=(const Renderer& other) = delete; + + ~Renderer(); + + inline Window& getWindow() + { + return window_; + } + + void fill( + Texture& tex, + Rectangle loc, + int r, + int g, + int b); + + void blit( + const Texture& src, + Texture& dst, + Rectangle srcrect, + Rectangle dstrect, + double alpha = 1.0); + + void renderScreen(const Texture& tex); + +private: + + friend void setFramebufferSize(GLFWwindow* w, int width, int height); + + void initializeFramebuffers(); + + void bloomPass1( + const GLTexture& src, + GLTexture& dst, + bool horizontal, + glm::vec2 srcRes, + glm::vec2 dstRes); + + static bool singletonInitialized_; + + Window window_; + GLVertexArray vao_; + + GLFramebuffer genericFb_; + GLFramebuffer bloomFb_; + GLRenderbuffer bloomDepth_; + + GLTexture renderPages_[2]; + GLTexture preBloomTex_; + GLTexture bloomPassTex1_; + GLTexture bloomPassTex2_; + + Mesh monitor_; + GLBuffer quadBuffer_; + + GLTexture artifactsTex_; + GLTexture scanlinesTex_; + + Shader ntscShader_; + Shader finalShader_; + Shader blitShader_; + Shader fillShader_; + Shader bloom1Shader_; + Shader bloom2Shader_; + + size_t curBuf_ = 0; + int width_; + int height_; +}; + +#endif diff --git a/src/renderer/shader.cpp b/src/renderer/shader.cpp new file mode 100644 index 0000000..735fc22 --- /dev/null +++ b/src/renderer/shader.cpp @@ -0,0 +1,84 @@ +#include "shader.h" +#include +#include +#include "util.h" + +Shader::Shader(std::string name) +{ + GLShader vertexShader(GL_VERTEX_SHADER); + GLShader fragmentShader(GL_FRAGMENT_SHADER); + + std::ifstream vertexFile("shaders/" + name + ".vertex"); + std::ifstream fragmentFile("shaders/" + name + ".fragment"); + + std::string vertexCode(slurp(vertexFile)); + std::string fragmentCode(slurp(fragmentFile)); + + const char* vertexCodePtr = vertexCode.c_str(); + const char* fragmentCodePtr = fragmentCode.c_str(); + + glShaderSource(vertexShader.getId(), 1, &vertexCodePtr, nullptr); + glShaderSource(fragmentShader.getId(), 1, &fragmentCodePtr, nullptr); + + glCompileShader(vertexShader.getId()); + glCompileShader(fragmentShader.getId()); + +#ifdef DEBUG + GLint result = GL_FALSE; + int infoLogLength; + + glGetShaderiv(vertexShader.getId(), GL_COMPILE_STATUS, &result); + + if (result == GL_FALSE) + { + glGetShaderiv(vertexShader.getId(), GL_INFO_LOG_LENGTH, &infoLogLength); + + std::vector errMsg(infoLogLength); + glGetShaderInfoLog( + vertexShader.getId(), + infoLogLength, + nullptr, + errMsg.data()); + + throw std::gl_error("Could not compile shader", errMsg.data()); + } + + glGetShaderiv(fragmentShader.getId(), GL_COMPILE_STATUS, &result); + + if (result == GL_FALSE) + { + glGetShaderiv(fragmentShader.getId(), GL_INFO_LOG_LENGTH, &infoLogLength); + + std::vector errMsg(infoLogLength); + glGetShaderInfoLog( + fragmentShader.getId(), + infoLogLength, + nullptr, + errMsg.data()); + + throw std::gl_error("Could not compile shader", errMsg.data()); + } +#endif + + glAttachShader(program_.getId(), vertexShader.getId()); + glAttachShader(program_.getId(), fragmentShader.getId()); + glLinkProgram(program_.getId()); + +#ifdef DEBUG + glGetProgramiv(program_.getId(), GL_LINK_STATUS, &result); + + if (result == GL_FALSE) + { + glGetProgramiv(program_.getId(), GL_INFO_LOG_LENGTH, &infoLogLength); + + std::vector errMsg(infoLogLength); + glGetProgramInfoLog( + program_.getId(), + infoLogLength, + nullptr, + errMsg.data()); + + throw std::gl_error("Could not link shader program", errMsg.data()); + } +#endif +} diff --git a/src/renderer/shader.h b/src/renderer/shader.h new file mode 100644 index 0000000..d2c673c --- /dev/null +++ b/src/renderer/shader.h @@ -0,0 +1,58 @@ +#ifndef SHADER_H_25115B63 +#define SHADER_H_25115B63 + +#include +#include +#include "gl.h" +#include "wrappers.h" + +class gl_error : public std::logic_error { +public: + + gl_error( + const char* msg, + std::string info) : + std::logic_error(msg), + info_(std::move(info)) + { + } + + gl_error( + std::string& msg, + std::string info) : + std::logic_error(msg), + info_(std::move(info)) + { + } + + inline const std::string& getInfo() const + { + return info_; + } + +private: + + std::string info_; +}; + +class Shader { +public: + + Shader(std::string name); + + inline void use() + { + glUseProgram(program_.getId()); + } + + inline GLint getUniformLocation(const GLchar* name) + { + return glGetUniformLocation(program_.getId(), name); + } + +private: + + GLProgram program_; +}; + +#endif /* end of include guard: SHADER_H_25115B63 */ diff --git a/src/renderer/texture.cpp b/src/renderer/texture.cpp new file mode 100644 index 0000000..2728665 --- /dev/null +++ b/src/renderer/texture.cpp @@ -0,0 +1,124 @@ +#include "texture.h" +#include +#include "renderer.h" +#include "util.h" + +// include stb_image +#define STBI_ONLY_PNG +#define STBI_ONLY_BMP +#include "stb_image.h" + +Texture::Texture( + int width, + int height) : + width_(width), + height_(height) +{ + if (!Renderer::isSingletonInitialized()) + { + throw std::logic_error("Renderer needs to be initialized"); + } + + glBindTexture(GL_TEXTURE_2D, texture_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + width_, + height_, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); +} + +Texture::Texture(const char* filename) +{ + if (!Renderer::isSingletonInitialized()) + { + throw std::logic_error("Renderer needs to be initialized"); + } + + glBindTexture(GL_TEXTURE_2D, texture_.getId()); + unsigned char* data = stbi_load(filename, &width_, &height_, 0, 4); + flipImageData(data, width_, height_, 4); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + width_, + height_, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + data); + + stbi_image_free(data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + +Texture::Texture( + const Texture& tex) : + width_(tex.width_), + height_(tex.height_) +{ + if (!Renderer::isSingletonInitialized()) + { + throw std::logic_error("Renderer needs to be initialized"); + } + + unsigned char* data = new unsigned char[4 * width_ * height_]; + glBindTexture(GL_TEXTURE_2D, tex.getId()); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + + glBindTexture(GL_TEXTURE_2D, texture_.getId()); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + width_, + height_, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + data); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + + delete[] data; +} + +Texture::Texture(Texture&& tex) : Texture(0, 0) +{ + swap(*this, tex); +} + +Texture& Texture::operator= (Texture tex) +{ + swap(*this, tex); + + return *this; +} + +void swap(Texture& tex1, Texture& tex2) +{ + std::swap(tex1.width_, tex2.width_); + std::swap(tex1.height_, tex2.height_); + std::swap(tex1.texture_, tex2.texture_); +} + +Rectangle Texture::entirety() const +{ + return {0, 0, width_, height_}; +} diff --git a/src/renderer/texture.h b/src/renderer/texture.h new file mode 100644 index 0000000..3aa8773 --- /dev/null +++ b/src/renderer/texture.h @@ -0,0 +1,52 @@ +#ifndef TEXTURE_H_84EC6DF6 +#define TEXTURE_H_84EC6DF6 + +#include "wrappers.h" + +struct Rectangle { + int x; + int y; + int w; + int h; +}; + +class Texture { +public: + + Texture(int width, int height); + + Texture(const char* file); + + Texture(const Texture& tex); + + Texture(Texture&& tex); + + Texture& operator= (Texture tex); + + friend void swap(Texture& tex1, Texture& tex2); + + Rectangle entirety() const; + + inline GLuint getId() const + { + return texture_.getId(); + } + + inline int getWidth() const + { + return width_; + } + + inline int getHeight() const + { + return height_; + } + +private: + + GLTexture texture_; + int width_; + int height_; +}; + +#endif /* end of include guard: TEXTURE_H_84EC6DF6 */ diff --git a/src/renderer/wrappers.h b/src/renderer/wrappers.h new file mode 100644 index 0000000..c6edc11 --- /dev/null +++ b/src/renderer/wrappers.h @@ -0,0 +1,273 @@ +#ifndef WRAPPERS_H_1EE0965B +#define WRAPPERS_H_1EE0965B + +#include "gl.h" +#include + +class GLVertexArray { +public: + + GLVertexArray() + { + glGenVertexArrays(1, &id_); + } + + GLVertexArray(const GLVertexArray& other) = delete; + GLVertexArray& operator=(const GLVertexArray& other) = delete; + + GLVertexArray(GLVertexArray&& other) : GLVertexArray() + { + std::swap(id_, other.id_); + } + + GLVertexArray& operator=(GLVertexArray&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLVertexArray() + { + glDeleteVertexArrays(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLFramebuffer { +public: + + GLFramebuffer() + { + glGenFramebuffers(1, &id_); + } + + GLFramebuffer(const GLFramebuffer& other) = delete; + GLFramebuffer& operator=(const GLFramebuffer& other) = delete; + + GLFramebuffer(GLFramebuffer&& other) : GLFramebuffer() + { + std::swap(id_, other.id_); + } + + GLFramebuffer& operator=(GLFramebuffer&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLFramebuffer() + { + glDeleteFramebuffers(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLRenderbuffer { +public: + + GLRenderbuffer() + { + glGenRenderbuffers(1, &id_); + } + + GLRenderbuffer(const GLRenderbuffer& other) = delete; + GLRenderbuffer& operator=(const GLRenderbuffer& other) = delete; + + GLRenderbuffer(GLRenderbuffer&& other) : GLRenderbuffer() + { + std::swap(id_, other.id_); + } + + GLRenderbuffer& operator=(GLRenderbuffer&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLRenderbuffer() + { + glDeleteRenderbuffers(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLBuffer { +public: + + GLBuffer() + { + glGenBuffers(1, &id_); + } + + GLBuffer(const GLBuffer& other) = delete; + GLBuffer& operator=(const GLBuffer& other) = delete; + + GLBuffer(GLBuffer&& other) : GLBuffer() + { + std::swap(id_, other.id_); + } + + GLBuffer& operator=(GLBuffer&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLBuffer() + { + glDeleteBuffers(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLTexture { +public: + + GLTexture() + { + glGenTextures(1, &id_); + } + + GLTexture(const GLTexture& other) = delete; + GLTexture& operator=(const GLTexture& other) = delete; + + GLTexture(GLTexture&& other) : GLTexture() + { + std::swap(id_, other.id_); + } + + GLTexture& operator=(GLTexture&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLTexture() + { + glDeleteTextures(1, &id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLShader { +public: + + GLShader(GLenum type) + { + id_ = glCreateShader(type); + } + + GLShader(const GLShader& other) = delete; + GLShader& operator=(const GLShader& other) = delete; + + GLShader(GLShader&& other) : GLShader(GL_VERTEX_SHADER) + { + std::swap(id_, other.id_); + } + + GLShader& operator=(GLShader&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLShader() + { + glDeleteShader(id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +class GLProgram { +public: + + GLProgram() + { + id_ = glCreateProgram(); + } + + GLProgram(const GLProgram& other) = delete; + GLProgram& operator=(const GLProgram& other) = delete; + + GLProgram(GLProgram&& other) : GLProgram() + { + std::swap(id_, other.id_); + } + + GLProgram& operator=(GLProgram&& other) + { + std::swap(id_, other.id_); + + return *this; + } + + ~GLProgram() + { + glDeleteProgram(id_); + } + + inline GLuint getId() const + { + return id_; + } + +private: + + GLuint id_; +}; + +#endif /* end of include guard: WRAPPERS_H_1EE0965B */ diff --git a/src/systems/animating.cpp b/src/systems/animating.cpp index 91fe925..22224c9 100644 --- a/src/systems/animating.cpp +++ b/src/systems/animating.cpp @@ -51,8 +51,9 @@ void AnimatingSystem::render(Texture& texture) transform.getH()}; const AnimationSet& aset = sprite.getAnimationSet(); - texture.blit( + game_.getRenderer().blit( aset.getTexture(), + texture, aset.getFrameRect(sprite.getFrame()), dstrect); } diff --git a/src/systems/animating.h b/src/systems/animating.h index d6a89a5..548bff1 100644 --- a/src/systems/animating.h +++ b/src/systems/animating.h @@ -3,7 +3,7 @@ #include "system.h" #include -#include "renderer.h" +#include "renderer/texture.h" class AnimatingSystem : public System { public: diff --git a/src/systems/mapping.cpp b/src/systems/mapping.cpp index 5b63ded..120a27a 100644 --- a/src/systems/mapping.cpp +++ b/src/systems/mapping.cpp @@ -48,7 +48,11 @@ void MappingSystem::render(Texture& texture) TILE_WIDTH, TILE_HEIGHT}; - texture.blit(mappable.getTileset(), std::move(src), std::move(dst)); + game_.getRenderer().blit( + mappable.getTileset(), + texture, + std::move(src), + std::move(dst)); } } @@ -67,7 +71,11 @@ void MappingSystem::render(Texture& texture) TILE_WIDTH, TILE_HEIGHT}; - texture.blit(mappable.getFont(), std::move(src), std::move(dst)); + game_.getRenderer().blit( + mappable.getFont(), + texture, + std::move(src), + std::move(dst)); } } } diff --git a/src/util.cpp b/src/util.cpp new file mode 100644 index 0000000..f0c39fd --- /dev/null +++ b/src/util.cpp @@ -0,0 +1,30 @@ +#include "util.h" + +std::string slurp(std::ifstream& in) +{ + std::stringstream sstr; + sstr << in.rdbuf(); + return sstr.str(); +} + +void flipImageData( + unsigned char* data, + int width, + int height, + int comps) +{ + unsigned char* dataCopy = new unsigned char[width * height * comps]; + memcpy(dataCopy, data, width * height * comps); + + int rowSize = width * comps; + + for (int i = 0; i < height; i++) + { + memcpy( + data + (rowSize * i), + dataCopy + (rowSize * (height - i - 1)), + rowSize); + } + + delete[] dataCopy; +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..72cb0d3 --- /dev/null +++ b/src/util.h @@ -0,0 +1,41 @@ +#ifndef ALGORITHMS_H_1DDC517E +#define ALGORITHMS_H_1DDC517E + +#include +#include +#include + +template< typename ContainerT, typename PredicateT > +void erase_if( ContainerT& items, const PredicateT& predicate ) { + for( auto it = items.begin(); it != items.end(); ) { + if( predicate(*it) ) it = items.erase(it); + else ++it; + } +}; + +struct chlit +{ + chlit(char c) : c_(c) { } + char c_; +}; + +inline std::istream& operator>>(std::istream& is, chlit x) +{ + char c; + if (is >> c && c != x.c_) + { + is.setstate(std::iostream::failbit); + } + + return is; +} + +std::string slurp(std::ifstream& in); + +void flipImageData( + unsigned char* data, + int width, + int height, + int comps); + +#endif /* end of include guard: ALGORITHMS_H_1DDC517E */ -- cgit 1.4.1 From e16fb5be90c889c371cbb0ca2444735c2e12073c Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sun, 18 Feb 2018 12:35:45 -0500 Subject: Implemented map adjacency This brings along with it the ability to move to different maps, for which the PlayingSystem and PlayableComponent were introduced. The PlayingSystem is a general overseer system that handles big picture stuff like initializing the player and changing maps. The PlayableComponent represents the player. While the ControllableComponent is also likely to always only be on the player entity, the two are distinct by separation of concerns. This also required a refactoring of how collisions are processed, because of a bug where the player can move to a new map when horizontal collisions are checked, and vertical collisions are skipped, causing the player to clip through the ground because the normal force was never handled. --- CMakeLists.txt | 2 + src/collision.cpp | 97 +++++++++++++ src/collision.h | 81 +++++++++++ src/components/mappable.h | 10 +- src/components/playable.h | 15 ++ src/consts.h | 2 +- src/entity_manager.h | 10 ++ src/game.cpp | 27 +--- src/map.h | 70 +++++++++- src/systems/mapping.cpp | 28 ++++ src/systems/playing.cpp | 98 +++++++++++++ src/systems/playing.h | 21 +++ src/systems/pondering.cpp | 347 +++++++++++++++++++++++++++++++--------------- src/systems/pondering.h | 11 -- src/world.cpp | 58 +++++++- 15 files changed, 717 insertions(+), 160 deletions(-) create mode 100644 src/collision.cpp create mode 100644 src/collision.h create mode 100644 src/components/playable.h create mode 100644 src/systems/playing.cpp create mode 100644 src/systems/playing.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e7bcb8..155063e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,7 @@ add_executable(Aromatherapy src/animation.cpp src/world.cpp src/util.cpp + src/collision.cpp src/renderer/renderer.cpp src/renderer/mesh.cpp src/renderer/shader.cpp @@ -64,6 +65,7 @@ add_executable(Aromatherapy src/systems/animating.cpp src/systems/mapping.cpp src/systems/orienting.cpp + src/systems/playing.cpp ) set_property(TARGET Aromatherapy PROPERTY CXX_STANDARD 11) diff --git a/src/collision.cpp b/src/collision.cpp new file mode 100644 index 0000000..b747a90 --- /dev/null +++ b/src/collision.cpp @@ -0,0 +1,97 @@ +#include "collision.h" + +bool Collision::operator<(const Collision& other) const +{ + // Most important is the type of collision + if (type_ != other.type_) + { + return (static_cast(type_) > static_cast(other.type_)); + } + + // Next, categorize the collisions arbitrarily based on direction + if (dir_ != other.dir_) + { + return (static_cast(dir_) < static_cast(other.dir_)); + } + + // We want to process closer collisions first + if (axis_ != other.axis_) + { + switch (dir_) + { + case Direction::left: + case Direction::up: + { + return (axis_ < other.axis_); + } + + case Direction::right: + case Direction::down: + { + return (axis_ > other.axis_); + } + } + } + + // Order the remaining attributes arbitrarily + return std::tie(collider_, lower_, upper_) < + std::tie(other.collider_, other.lower_, other.upper_); +} + +bool Collision::isColliding( + double x, + double y, + int w, + int h) const +{ + int right = x + w; + int bottom = y + h; + + switch (dir_) + { + case Direction::left: + case Direction::right: + { + if (!((bottom > lower_) && (y < upper_))) + { + return false; + } + + break; + } + + case Direction::up: + case Direction::down: + { + if (!((right > lower_) && (x < upper_))) + { + return false; + } + + break; + } + } + + switch (dir_) + { + case Direction::left: + { + return (axis_ >= x); + } + + case Direction::right: + { + return (axis_ <= right); + } + + case Direction::up: + { + return (axis_ >= y); + } + + case Direction::down: + { + return (axis_ <= bottom); + } + } +} diff --git a/src/collision.h b/src/collision.h new file mode 100644 index 0000000..e5371f8 --- /dev/null +++ b/src/collision.h @@ -0,0 +1,81 @@ +#ifndef COLLISION_H_53D84877 +#define COLLISION_H_53D84877 + +#include "entity_manager.h" +#include "direction.h" + +class Collision { +public: + + using id_type = EntityManager::id_type; + + // Types are defined in descending priority order + enum class Type { + wall, + platform, + adjacency, + warp, + danger + }; + + Collision( + id_type collider, + Direction dir, + Type type, + int axis, + double lower, + double upper) : + collider_(collider), + dir_(dir), + type_(type), + axis_(axis), + lower_(lower), + upper_(upper) + { + } + + inline id_type getCollider() const + { + return collider_; + } + + inline Direction getDirection() const + { + return dir_; + } + + inline Type getType() const + { + return type_; + } + + inline int getAxis() const + { + return axis_; + } + + inline double getLower() const + { + return lower_; + } + + inline double getUpper() const + { + return upper_; + } + + bool operator<(const Collision& other) const; + + bool isColliding(double x, double y, int w, int h) const; + +private: + + id_type collider_; + Direction dir_; + Type type_; + int axis_; + double lower_; + double upper_; +}; + +#endif /* end of include guard: COLLISION_H_53D84877 */ diff --git a/src/components/mappable.h b/src/components/mappable.h index 2dbab77..633cdf4 100644 --- a/src/components/mappable.h +++ b/src/components/mappable.h @@ -4,6 +4,7 @@ #include #include "component.h" #include "renderer/texture.h" +#include "collision.h" #include "map.h" class MappableComponent : public Component { @@ -12,14 +13,7 @@ public: class Boundary { public: - enum class Type { - wall, - wrap, - teleport, - reverse, - platform, - danger - }; + using Type = Collision::Type; Boundary( double axis, diff --git a/src/components/playable.h b/src/components/playable.h new file mode 100644 index 0000000..a6e71b0 --- /dev/null +++ b/src/components/playable.h @@ -0,0 +1,15 @@ +#ifndef PLAYABLE_H_DDC566C3 +#define PLAYABLE_H_DDC566C3 + +#include "component.h" + +class PlayableComponent : public Component { +public: + + bool changingMap = false; + int newMapId = -1; + double newMapX = 0; + double newMapY = 0; +}; + +#endif /* end of include guard: PLAYABLE_H_DDC566C3 */ diff --git a/src/consts.h b/src/consts.h index 581018d..a065159 100644 --- a/src/consts.h +++ b/src/consts.h @@ -7,7 +7,7 @@ const int GAME_WIDTH = 320; const int GAME_HEIGHT = 200; const int MAP_WIDTH = GAME_WIDTH/TILE_WIDTH; const int MAP_HEIGHT = GAME_HEIGHT/TILE_HEIGHT - 1; -const int WALL_GAP = 6; +const int WALL_GAP = 5; const int TILESET_COLS = 8; const int FONT_COLS = 16; diff --git a/src/entity_manager.h b/src/entity_manager.h index 65fa6ca..1e8d31c 100644 --- a/src/entity_manager.h +++ b/src/entity_manager.h @@ -26,6 +26,7 @@ private: database_type entities; std::vector slotAvailable; + std::set allEntities; std::map, std::set> cachedComponents; id_type nextEntityID = 0; @@ -59,12 +60,14 @@ public: // If the database is saturated, add a new element for the new entity. entities.emplace_back(); slotAvailable.push_back(false); + allEntities.insert(nextEntityID); return nextEntityID++; } else { // If there is an available slot in the database, use it. id_type id = nextEntityID++; slotAvailable[id] = false; + allEntities.insert(id); // Fast forward the next available slot pointer to an available slot. while ((nextEntityID < entities.size()) && !slotAvailable[nextEntityID]) @@ -89,6 +92,8 @@ public: cache.second.erase(entity); } + allEntities.erase(entity); + // Destroy the data entities[entity].components.clear(); @@ -202,6 +207,11 @@ public: return getEntitiesWithComponentsHelper(componentTypes); } + + const std::set& getEntities() const + { + return allEntities; + } }; template <> diff --git a/src/game.cpp b/src/game.cpp index 228ff23..f245e7c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -9,6 +9,7 @@ #include "systems/animating.h" #include "systems/mapping.h" #include "systems/orienting.h" +#include "systems/playing.h" #include "animation.h" #include "consts.h" @@ -28,36 +29,14 @@ void key_callback(GLFWwindow* window, int key, int, int action, int) Game::Game() : world_("res/maps.xml") { + systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); - int player = entityManager_.emplaceEntity(); - - AnimationSet playerGraphics {"res/Starla.png", 10, 12, 6}; - playerGraphics.emplaceAnimation("stillLeft", 3, 1, 1); - playerGraphics.emplaceAnimation("stillRight", 0, 1, 1); - playerGraphics.emplaceAnimation("walkingLeft", 4, 2, 10); - playerGraphics.emplaceAnimation("walkingRight", 1, 2, 10); - - entityManager_.emplaceComponent( - player, - std::move(playerGraphics), - "stillLeft"); - - entityManager_.emplaceComponent( - player, - 203, 44, 10, 12); - - systemManager_.getSystem().initializeBody( - player, - PonderableComponent::Type::freefalling); - - entityManager_.emplaceComponent(player); - entityManager_.emplaceComponent(player); - + systemManager_.getSystem().initPlayer(); systemManager_.getSystem().loadMap(world_.getStartingMapId()); glfwSwapInterval(1); diff --git a/src/map.h b/src/map.h index 9177870..6fe1e62 100644 --- a/src/map.h +++ b/src/map.h @@ -10,13 +10,55 @@ class Map { public: + class Adjacent { + public: + + enum class Type { + wall, + wrap, + warp, + reverse + }; + + Adjacent( + Type type = Type::wall, + int mapId = -1) : + type_(type), + mapId_(mapId) + { + } + + inline Type getType() const + { + return type_; + } + + inline int getMapId() const + { + return mapId_; + } + + private: + + Type type_; + int mapId_; + }; + Map( int id, std::vector tiles, - std::string title) : + std::string title, + Adjacent leftAdjacent, + Adjacent rightAdjacent, + Adjacent upAdjacent, + Adjacent downAdjacent) : id_(id), tiles_(std::move(tiles)), - title_(std::move(title)) + title_(std::move(title)), + leftAdjacent_(std::move(leftAdjacent)), + rightAdjacent_(std::move(rightAdjacent)), + upAdjacent_(std::move(upAdjacent)), + downAdjacent_(std::move(downAdjacent)) { } @@ -35,11 +77,35 @@ public: return title_; } + inline const Adjacent& getLeftAdjacent() const + { + return leftAdjacent_; + } + + inline const Adjacent& getRightAdjacent() const + { + return rightAdjacent_; + } + + inline const Adjacent& getUpAdjacent() const + { + return upAdjacent_; + } + + inline const Adjacent& getDownAdjacent() const + { + return downAdjacent_; + } + private: int id_; std::vector tiles_; std::string title_; + Adjacent leftAdjacent_; + Adjacent rightAdjacent_; + Adjacent upAdjacent_; + Adjacent downAdjacent_; }; #endif /* end of include guard: MAP_H_74055FC0 */ diff --git a/src/systems/mapping.cpp b/src/systems/mapping.cpp index 120a27a..05167c1 100644 --- a/src/systems/mapping.cpp +++ b/src/systems/mapping.cpp @@ -93,6 +93,34 @@ void MappingSystem::loadMap(size_t mapId) const Map& map = game_.getWorld().getMap(mappable.getMapId()); + addBoundary( + mappable.getLeftBoundaries(), + -WALL_GAP, + 0, + MAP_HEIGHT * TILE_HEIGHT, + MappableComponent::Boundary::Type::adjacency); + + addBoundary( + mappable.getRightBoundaries(), + GAME_WIDTH + WALL_GAP, + 0, + MAP_HEIGHT * TILE_HEIGHT, + MappableComponent::Boundary::Type::adjacency); + + addBoundary( + mappable.getUpBoundaries(), + -WALL_GAP, + 0, + GAME_WIDTH, + MappableComponent::Boundary::Type::adjacency); + + addBoundary( + mappable.getDownBoundaries(), + MAP_HEIGHT * TILE_HEIGHT + WALL_GAP, + 0, + GAME_WIDTH, + MappableComponent::Boundary::Type::adjacency); + for (size_t i = 0; i < MAP_WIDTH * MAP_HEIGHT; i++) { size_t x = i % MAP_WIDTH; diff --git a/src/systems/playing.cpp b/src/systems/playing.cpp new file mode 100644 index 0000000..2c6a419 --- /dev/null +++ b/src/systems/playing.cpp @@ -0,0 +1,98 @@ +#include "playing.h" +#include "game.h" +#include "components/transformable.h" +#include "components/animatable.h" +#include "components/playable.h" +#include "components/controllable.h" +#include "components/orientable.h" +#include "systems/mapping.h" +#include "systems/pondering.h" +#include "animation.h" + +void PlayingSystem::tick(double) +{ + // Check if we need to change the map + auto players = game_.getEntityManager().getEntitiesWithComponents< + PlayableComponent>(); + + for (id_type player : players) + { + auto& playable = game_.getEntityManager(). + getComponent(player); + + if (playable.changingMap) + { + // Change the map! + auto entities = game_.getEntityManager().getEntities(); + + for (id_type entity : entities) + { + if (entity != player) + { + game_.getEntityManager().deleteEntity(entity); + } + } + + game_.getSystemManager().getSystem(). + loadMap(playable.newMapId); + + auto& transformable = game_.getEntityManager(). + getComponent(player); + + transformable.setX(playable.newMapX); + transformable.setY(playable.newMapY); + + playable.changingMap = false; + + break; + } + } +} + +void PlayingSystem::initPlayer() +{ + id_type player = game_.getEntityManager().emplaceEntity(); + + AnimationSet playerGraphics {"res/Starla.png", 10, 12, 6}; + playerGraphics.emplaceAnimation("stillLeft", 3, 1, 1); + playerGraphics.emplaceAnimation("stillRight", 0, 1, 1); + playerGraphics.emplaceAnimation("walkingLeft", 4, 2, 10); + playerGraphics.emplaceAnimation("walkingRight", 1, 2, 10); + + game_.getEntityManager().emplaceComponent( + player, + std::move(playerGraphics), + "stillLeft"); + + game_.getEntityManager().emplaceComponent( + player, + 203, 44, 10, 12); + + game_.getSystemManager().getSystem().initializeBody( + player, + PonderableComponent::Type::freefalling); + + game_.getEntityManager().emplaceComponent(player); + game_.getEntityManager().emplaceComponent(player); + game_.getEntityManager().emplaceComponent(player); +} + +void PlayingSystem::changeMap( + size_t mapId, + double x, + double y) +{ + auto players = game_.getEntityManager().getEntitiesWithComponents< + PlayableComponent>(); + + for (id_type player : players) + { + auto& playable = game_.getEntityManager(). + getComponent(player); + + playable.changingMap = true; + playable.newMapId = mapId; + playable.newMapX = x; + playable.newMapY = y; + } +} diff --git a/src/systems/playing.h b/src/systems/playing.h new file mode 100644 index 0000000..c98a464 --- /dev/null +++ b/src/systems/playing.h @@ -0,0 +1,21 @@ +#ifndef PLAYING_H_70A54F7D +#define PLAYING_H_70A54F7D + +#include "system.h" + +class PlayingSystem : public System { +public: + + PlayingSystem(Game& game) : System(game) + { + } + + void tick(double dt); + + void initPlayer(); + + void changeMap(size_t mapId, double x, double y); + +}; + +#endif /* end of include guard: PLAYING_H_70A54F7D */ diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 4a165b1..2490dc9 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -1,11 +1,14 @@ #include "pondering.h" +#include #include "game.h" #include "components/ponderable.h" #include "components/transformable.h" #include "components/orientable.h" #include "components/mappable.h" #include "systems/orienting.h" +#include "systems/playing.h" #include "consts.h" +#include "collision.h" void PonderingSystem::tick(double dt) { @@ -42,6 +45,9 @@ void PonderingSystem::tick(double dt) bool oldGrounded = ponderable.isGrounded(); ponderable.setGrounded(false); + std::priority_queue collisions; + + // Find collisions for (id_type mapEntity : maps) { auto& mappable = game_.getEntityManager(). @@ -57,13 +63,13 @@ void PonderingSystem::tick(double dt) && (oldY < it->second.getUpper())) { // We have a collision! - processCollision( - entity, + collisions.emplace( + mapEntity, Direction::left, - newX, - newY, + it->second.getType(), it->first, - it->second.getType()); + it->second.getLower(), + it->second.getUpper()); } } } else if (newX > oldX) @@ -77,13 +83,13 @@ void PonderingSystem::tick(double dt) && (oldY < it->second.getUpper())) { // We have a collision! - processCollision( - entity, + collisions.emplace( + mapEntity, Direction::right, - newX, - newY, + it->second.getType(), it->first, - it->second.getType()); + it->second.getLower(), + it->second.getUpper()); } } } @@ -98,13 +104,13 @@ void PonderingSystem::tick(double dt) && (oldX < it->second.getUpper())) { // We have a collision! - processCollision( - entity, + collisions.emplace( + mapEntity, Direction::up, - newX, - newY, + it->second.getType(), it->first, - it->second.getType()); + it->second.getLower(), + it->second.getUpper()); } } } else if (newY > oldY) @@ -118,13 +124,221 @@ void PonderingSystem::tick(double dt) && (oldX < it->second.getUpper())) { // We have a collision! - processCollision( - entity, + collisions.emplace( + mapEntity, Direction::down, - newX, - newY, + it->second.getType(), it->first, - it->second.getType()); + it->second.getLower(), + it->second.getUpper()); + } + } + } + } + + // Process collisions in order of priority + while (!collisions.empty()) + { + Collision collision = collisions.top(); + collisions.pop(); + + // Make sure that they are still colliding + if (!collision.isColliding( + newX, + newY, + transformable.getW(), + transformable.getH())) + { + continue; + } + + bool touchedWall = false; + bool stopProcessing = false; + + switch (collision.getType()) + { + case Collision::Type::wall: + { + touchedWall = true; + + break; + } + + case Collision::Type::platform: + { + if (game_.getEntityManager(). + hasComponent(entity)) + { + auto& orientable = game_.getEntityManager(). + getComponent(entity); + + if (orientable.getDropState() != + OrientableComponent::DropState::none) + { + orientable.setDropState(OrientableComponent::DropState::active); + } else { + touchedWall = true; + } + } else { + touchedWall = true; + } + + break; + } + + case Collision::Type::adjacency: + { + auto& mappable = game_.getEntityManager(). + getComponent(collision.getCollider()); + const Map& map = game_.getWorld().getMap(mappable.getMapId()); + auto& adj = [&] () -> const Map::Adjacent& { + switch (collision.getDirection()) + { + case Direction::left: return map.getLeftAdjacent(); + case Direction::right: return map.getRightAdjacent(); + case Direction::up: return map.getUpAdjacent(); + case Direction::down: return map.getDownAdjacent(); + } + }(); + + switch (adj.getType()) + { + case Map::Adjacent::Type::wall: + { + touchedWall = true; + + break; + } + + case Map::Adjacent::Type::wrap: + { + switch (collision.getDirection()) + { + case Direction::left: + { + newX = GAME_WIDTH + WALL_GAP - transformable.getW(); + + break; + } + + case Direction::right: + { + newX = -WALL_GAP; + + break; + } + + case Direction::up: + { + newY = MAP_HEIGHT * TILE_HEIGHT + WALL_GAP - + transformable.getH(); + + break; + } + + case Direction::down: + { + newY = -WALL_GAP; + + break; + } + } + } + + case Map::Adjacent::Type::warp: + { + double warpX = newX; + double warpY = newY; + + switch (collision.getDirection()) + { + case Direction::left: + { + warpX = GAME_WIDTH + WALL_GAP - transformable.getW(); + + break; + } + + case Direction::right: + { + warpX = -WALL_GAP; + + break; + } + + case Direction::up: + { + warpY = MAP_HEIGHT * TILE_HEIGHT - transformable.getH(); + + break; + } + + case Direction::down: + { + warpY = -WALL_GAP; + + break; + } + } + + game_.getSystemManager().getSystem(). + changeMap(adj.getMapId(), warpX, warpY); + + stopProcessing = true; + + break; + } + } + } + + default: + { + // Not yet implemented. + + break; + } + } + + if (stopProcessing) + { + break; + } + + if (touchedWall) + { + switch (collision.getDirection()) + { + case Direction::left: + { + newX = collision.getAxis(); + ponderable.setVelocityX(0.0); + + break; + } + + case Direction::right: + { + newX = collision.getAxis() - transformable.getW(); + ponderable.setVelocityX(0.0); + + break; + } + + case Direction::up: + { + newY = collision.getAxis(); + ponderable.setVelocityY(0.0); + + break; + } + + case Direction::down: + { + newY = collision.getAxis() - transformable.getH(); + ponderable.setVelocityY(0.0); + ponderable.setGrounded(true); + + break; } } } @@ -173,96 +387,3 @@ void PonderingSystem::initializeBody( ponderable.setAccelY(NORMAL_GRAVITY); } } - -void PonderingSystem::processCollision( - id_type entity, - Direction dir, - double& newX, - double& newY, - int axis, - MappableComponent::Boundary::Type type) -{ - auto& ponderable = game_.getEntityManager(). - getComponent(entity); - - auto& transformable = game_.getEntityManager(). - getComponent(entity); - - bool touchedGround = false; - - switch (type) - { - case MappableComponent::Boundary::Type::wall: - { - switch (dir) - { - case Direction::left: - { - newX = axis; - ponderable.setVelocityX(0.0); - - break; - } - - case Direction::right: - { - newX = axis - transformable.getW(); - ponderable.setVelocityX(0.0); - - break; - } - - case Direction::up: - { - newY = axis; - ponderable.setVelocityY(0.0); - - break; - } - - case Direction::down: - { - touchedGround = true; - - break; - } - } - - break; - } - - case MappableComponent::Boundary::Type::platform: - { - if (game_.getEntityManager().hasComponent(entity)) - { - auto& orientable = game_.getEntityManager(). - getComponent(entity); - - if (orientable.getDropState() != OrientableComponent::DropState::none) - { - orientable.setDropState(OrientableComponent::DropState::active); - } else { - touchedGround = true; - } - } else { - touchedGround = true; - } - - break; - } - - default: - { - // Not yet implemented. - - break; - } - } - - if (touchedGround) - { - newY = axis - transformable.getH(); - ponderable.setVelocityY(0.0); - ponderable.setGrounded(true); - } -} diff --git a/src/systems/pondering.h b/src/systems/pondering.h index a16622b..d70525b 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -2,7 +2,6 @@ #define PONDERING_H_F2530E0E #include "system.h" -#include "components/mappable.h" #include "components/ponderable.h" #include "direction.h" @@ -17,16 +16,6 @@ public: void initializeBody(id_type entity, PonderableComponent::Type type); -private: - - void processCollision( - id_type entity, - Direction dir, - double& newX, - double& newY, - int axis, - MappableComponent::Boundary::Type type); - }; #endif /* end of include guard: PONDERING_H_F2530E0E */ diff --git a/src/world.cpp b/src/world.cpp index 9b1e4f6..3b6bd41 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -63,6 +63,10 @@ World::World(std::string filename) xmlFree(key); std::vector mapTiles; + Map::Adjacent leftAdj; + Map::Adjacent rightAdj; + Map::Adjacent upAdj; + Map::Adjacent downAdj; for (xmlNodePtr mapNode = node->xmlChildrenNode; mapNode != nullptr; @@ -82,6 +86,54 @@ World::World(std::string filename) } xmlFree(key); + } else if (!xmlStrcmp( + mapNode->name, + reinterpret_cast("adjacent"))) + { + key = getProp(mapNode, "type"); + std::string adjTypeStr(reinterpret_cast(key)); + xmlFree(key); + + Map::Adjacent::Type adjType; + if (adjTypeStr == "wall") + { + adjType = Map::Adjacent::Type::wall; + } else if (adjTypeStr == "wrap") + { + adjType = Map::Adjacent::Type::wrap; + } else if (adjTypeStr == "warp") + { + adjType = Map::Adjacent::Type::warp; + } else if (adjTypeStr == "reverseWarp") + { + adjType = Map::Adjacent::Type::reverse; + } else { + throw std::logic_error("Invalid adjacency type"); + } + + key = getProp(mapNode, "map"); + int adjMapId = atoi(reinterpret_cast(key)); + xmlFree(key); + + key = getProp(mapNode, "dir"); + std::string adjDir(reinterpret_cast(key)); + xmlFree(key); + + if (adjDir == "left") + { + leftAdj = {adjType, adjMapId}; + } else if (adjDir == "right") + { + rightAdj = {adjType, adjMapId}; + } else if (adjDir == "up") + { + upAdj = {adjType, adjMapId}; + } else if (adjDir == "down") + { + downAdj = {adjType, adjMapId}; + } else { + throw std::logic_error("Invalid adjacency direction"); + } } } @@ -91,7 +143,11 @@ World::World(std::string filename) std::forward_as_tuple( mapId, std::move(mapTiles), - std::move(mapTitle))); + std::move(mapTitle), + leftAdj, + rightAdj, + upAdj, + downAdj)); } } -- cgit 1.4.1 From e4e2f2d2a7b6a282b9618aa0004d9453936f43c6 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sun, 18 Feb 2018 15:25:52 -0500 Subject: Added player death and event scheduling Also added ability to make sprites flicker, to freeze physics for an entity, and to freeze progression of a sprite's animation loop. --- CMakeLists.txt | 1 + res/maps.xml | 2 +- src/components/animatable.h | 33 +++++++++++++++++ src/components/playable.h | 9 +++++ src/components/ponderable.h | 22 ++++++++++++ src/components/schedulable.h | 21 +++++++++++ src/game.cpp | 2 ++ src/systems/animating.cpp | 19 ++++++++-- src/systems/controlling.cpp | 29 +++++++++++++++ src/systems/controlling.h | 5 +++ src/systems/mapping.cpp | 21 +++++++++++ src/systems/orienting.cpp | 18 ++++------ src/systems/playing.cpp | 85 +++++++++++++++++++++++++++++++++++++++++--- src/systems/playing.h | 9 ++++- src/systems/pondering.cpp | 16 +++++++++ src/systems/scheduling.cpp | 54 ++++++++++++++++++++++++++++ src/systems/scheduling.h | 22 ++++++++++++ 17 files changed, 348 insertions(+), 20 deletions(-) create mode 100644 src/components/schedulable.h create mode 100644 src/systems/scheduling.cpp create mode 100644 src/systems/scheduling.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 155063e..34246ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,7 @@ add_executable(Aromatherapy src/systems/mapping.cpp src/systems/orienting.cpp src/systems/playing.cpp + src/systems/scheduling.cpp ) set_property(TARGET Aromatherapy PROPERTY CXX_STANDARD 11) diff --git a/res/maps.xml b/res/maps.xml index 9d855a2..c561912 100644 --- a/res/maps.xml +++ b/res/maps.xml @@ -1,5 +1,5 @@ -00,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,20,0,0,0,0,0,0,0,18,9,8,10,8,11,8,10,10,8,11,8,9,10,21,0, +00,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,20,0,0,0,0,0,0,0,18,9,8,10,8,11,8,10,10,8,11,8,9,10,21,0, 0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,8,8,17,0,0,0,0,0,0,0,0,0,0,0,0,0,22,21, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,8,8,8,8,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12, 0,19,0,0,0,0,0,0,0,0,0,0,0,18,8,8,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12, diff --git a/src/components/animatable.h b/src/components/animatable.h index ed0133e..ec72be0 100644 --- a/src/components/animatable.h +++ b/src/components/animatable.h @@ -51,12 +51,45 @@ public: animation_ = std::move(animation); } + inline bool isFlickering() const + { + return flickering_; + } + + inline void setFlickering(bool v) + { + flickering_ = v; + } + + inline size_t getFlickerTimer() const + { + return flickerTimer_; + } + + inline void setFlickerTimer(size_t v) + { + flickerTimer_ = v; + } + + inline bool isFrozen() const + { + return frozen_; + } + + inline void setFrozen(bool v) + { + frozen_ = v; + } + private: AnimationSet animationSet_; std::string animation_; size_t frame_ = 0; size_t countdown_ = 0; + bool flickering_ = false; + size_t flickerTimer_ = 0; + bool frozen_ = false; }; #endif /* end of include guard: SPRITE_RENDERABLE_H_D3AACBBF */ diff --git a/src/components/playable.h b/src/components/playable.h index a6e71b0..86a7ee7 100644 --- a/src/components/playable.h +++ b/src/components/playable.h @@ -2,14 +2,23 @@ #define PLAYABLE_H_DDC566C3 #include "component.h" +#include class PlayableComponent : public Component { public: + using MapChangeCallback = std::function; + bool changingMap = false; int newMapId = -1; double newMapX = 0; double newMapY = 0; + MapChangeCallback newMapCallback; + + int checkpointMapId = -1; + double checkpointX = 0; + double checkpointY = 0; + }; #endif /* end of include guard: PLAYABLE_H_DDC566C3 */ diff --git a/src/components/ponderable.h b/src/components/ponderable.h index e21cbab..78af25f 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -70,6 +70,26 @@ public: grounded_ = v; } + inline bool isFrozen() const + { + return frozen_; + } + + inline void setFrozen(bool v) + { + frozen_ = v; + } + + inline bool isCollidable() const + { + return collidable_; + } + + inline void setCollidable(bool v) + { + collidable_ = v; + } + private: double velX_ = 0.0; @@ -78,6 +98,8 @@ private: double accelY_ = 0.0; Type type_ = Type::vacuumed; bool grounded_ = false; + bool frozen_ = false; + bool collidable_ = true; }; #endif /* end of include guard: TANGIBLE_H_746DB3EE */ diff --git a/src/components/schedulable.h b/src/components/schedulable.h new file mode 100644 index 0000000..a92bbba --- /dev/null +++ b/src/components/schedulable.h @@ -0,0 +1,21 @@ +#ifndef SCHEDULABLE_H_1DA3FA2A +#define SCHEDULABLE_H_1DA3FA2A + +#include "component.h" +#include +#include +#include +#include "entity_manager.h" + +class SchedulableComponent : public Component { +public: + + using id_type = EntityManager::id_type; + + using Callback = std::function; + using Action = std::tuple; + + std::list actions; +}; + +#endif /* end of include guard: SCHEDULABLE_H_1DA3FA2A */ diff --git a/src/game.cpp b/src/game.cpp index f245e7c..3da23a3 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -10,6 +10,7 @@ #include "systems/mapping.h" #include "systems/orienting.h" #include "systems/playing.h" +#include "systems/scheduling.h" #include "animation.h" #include "consts.h" @@ -30,6 +31,7 @@ void key_callback(GLFWwindow* window, int key, int, int action, int) Game::Game() : world_("res/maps.xml") { systemManager_.emplaceSystem(*this); + systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); diff --git a/src/systems/animating.cpp b/src/systems/animating.cpp index 22224c9..634af67 100644 --- a/src/systems/animating.cpp +++ b/src/systems/animating.cpp @@ -13,7 +13,10 @@ void AnimatingSystem::tick(double) auto& sprite = game_.getEntityManager(). getComponent(entity); - sprite.setCountdown(sprite.getCountdown() + 1); + if (!sprite.isFrozen()) + { + sprite.setCountdown(sprite.getCountdown() + 1); + } const Animation& anim = sprite.getAnimation(); if (sprite.getCountdown() >= anim.getDelay()) @@ -26,6 +29,11 @@ void AnimatingSystem::tick(double) sprite.setFrame(anim.getFirstFrame()); } } + + if (sprite.isFlickering()) + { + sprite.setFlickerTimer((sprite.getFlickerTimer() + 1) % 6); + } } } @@ -44,6 +52,12 @@ void AnimatingSystem::render(Texture& texture) auto& transform = game_.getEntityManager(). getComponent(entity); + double alpha = 1.0; + if (sprite.isFlickering() && (sprite.getFlickerTimer() < 3)) + { + alpha = 0.0; + } + Rectangle dstrect { static_cast(transform.getX()), static_cast(transform.getY()), @@ -55,7 +69,8 @@ void AnimatingSystem::render(Texture& texture) aset.getTexture(), texture, aset.getFrameRect(sprite.getFrame()), - dstrect); + dstrect, + alpha); } } diff --git a/src/systems/controlling.cpp b/src/systems/controlling.cpp index e1609bd..e65c09a 100644 --- a/src/systems/controlling.cpp +++ b/src/systems/controlling.cpp @@ -105,3 +105,32 @@ void ControllingSystem::input(int key, int action) { actions_.push(std::make_pair(key, action)); } + +void ControllingSystem::freeze(id_type entity) +{ + auto& controllable = game_.getEntityManager(). + getComponent(entity); + + controllable.setFrozen(true); +} + +void ControllingSystem::unfreeze(id_type entity) +{ + auto& controllable = game_.getEntityManager(). + getComponent(entity); + + if (controllable.isFrozen()) + { + controllable.setFrozen(false); + + auto& orienting = game_.getSystemManager().getSystem(); + + if (controllable.isHoldingLeft()) + { + orienting.moveLeft(entity); + } else if (controllable.isHoldingRight()) + { + orienting.moveRight(entity); + } + } +} diff --git a/src/systems/controlling.h b/src/systems/controlling.h index 01ed7a0..d6f0789 100644 --- a/src/systems/controlling.h +++ b/src/systems/controlling.h @@ -12,8 +12,13 @@ public: } void tick(double dt); + void input(int key, int action); + void freeze(id_type entity); + + void unfreeze(id_type entity); + private: std::queue> actions_; diff --git a/src/systems/mapping.cpp b/src/systems/mapping.cpp index 05167c1..a3a17ec 100644 --- a/src/systems/mapping.cpp +++ b/src/systems/mapping.cpp @@ -166,12 +166,33 @@ void MappingSystem::loadMap(size_t mapId) MappableComponent::Boundary::Type::wall); } else if (tile == 42) { + addBoundary( + mappable.getRightBoundaries(), + x * TILE_WIDTH, + y * TILE_HEIGHT, + (y+1) * TILE_HEIGHT, + MappableComponent::Boundary::Type::danger); + + addBoundary( + mappable.getLeftBoundaries(), + (x+1) * TILE_WIDTH, + y * TILE_HEIGHT, + (y+1) * TILE_HEIGHT, + MappableComponent::Boundary::Type::danger); + addBoundary( mappable.getDownBoundaries(), y * TILE_HEIGHT, x * TILE_WIDTH, (x+1) * TILE_WIDTH, MappableComponent::Boundary::Type::danger); + + addBoundary( + mappable.getUpBoundaries(), + (y+1) * TILE_HEIGHT, + x * TILE_WIDTH, + (x+1) * TILE_WIDTH, + MappableComponent::Boundary::Type::danger); } } } diff --git a/src/systems/orienting.cpp b/src/systems/orienting.cpp index 187bebc..2df8f87 100644 --- a/src/systems/orienting.cpp +++ b/src/systems/orienting.cpp @@ -93,24 +93,18 @@ void OrientingSystem::moveRight(id_type entity) void OrientingSystem::stopWalking(id_type entity) { - auto& ponderable = game_.getEntityManager(). - getComponent(entity); - auto& orientable = game_.getEntityManager(). getComponent(entity); orientable.setWalkState(OrientableComponent::WalkState::still); - if (ponderable.isGrounded()) - { - auto& animating = game_.getSystemManager().getSystem(); + auto& animating = game_.getSystemManager().getSystem(); - if (orientable.isFacingRight()) - { - animating.startAnimation(entity, "stillRight"); - } else { - animating.startAnimation(entity, "stillLeft"); - } + if (orientable.isFacingRight()) + { + animating.startAnimation(entity, "stillRight"); + } else { + animating.startAnimation(entity, "stillLeft"); } } diff --git a/src/systems/playing.cpp b/src/systems/playing.cpp index 2c6a419..40d9706 100644 --- a/src/systems/playing.cpp +++ b/src/systems/playing.cpp @@ -7,13 +7,18 @@ #include "components/orientable.h" #include "systems/mapping.h" #include "systems/pondering.h" +#include "systems/orienting.h" +#include "systems/scheduling.h" +#include "systems/controlling.h" #include "animation.h" +#include "muxer.h" void PlayingSystem::tick(double) { // Check if we need to change the map auto players = game_.getEntityManager().getEntitiesWithComponents< - PlayableComponent>(); + PlayableComponent, + TransformableComponent>(); for (id_type player : players) { @@ -44,6 +49,12 @@ void PlayingSystem::tick(double) playable.changingMap = false; + if (playable.newMapCallback) + { + playable.newMapCallback(); + playable.newMapCallback = nullptr; + } + break; } } @@ -66,7 +77,10 @@ void PlayingSystem::initPlayer() game_.getEntityManager().emplaceComponent( player, - 203, 44, 10, 12); + game_.getWorld().getStartingX(), + game_.getWorld().getStartingY(), + 10, + 12); game_.getSystemManager().getSystem().initializeBody( player, @@ -74,13 +88,20 @@ void PlayingSystem::initPlayer() game_.getEntityManager().emplaceComponent(player); game_.getEntityManager().emplaceComponent(player); - game_.getEntityManager().emplaceComponent(player); + + auto& playable = game_.getEntityManager(). + emplaceComponent(player); + + playable.checkpointMapId = game_.getWorld().getStartingMapId(); + playable.checkpointX = game_.getWorld().getStartingX(); + playable.checkpointY = game_.getWorld().getStartingY(); } void PlayingSystem::changeMap( size_t mapId, double x, - double y) + double y, + PlayableComponent::MapChangeCallback callback) { auto players = game_.getEntityManager().getEntitiesWithComponents< PlayableComponent>(); @@ -94,5 +115,61 @@ void PlayingSystem::changeMap( playable.newMapId = mapId; playable.newMapX = x; playable.newMapY = y; + playable.newMapCallback = std::move(callback); + } +} + +void PlayingSystem::die() +{ + playSound("res/Hit_Hurt5.wav", 0.25); + + auto players = game_.getEntityManager().getEntitiesWithComponents< + OrientableComponent, + ControllableComponent, + AnimatableComponent, + PonderableComponent, + PlayableComponent>(); + + for (id_type player : players) + { + auto& animatable = game_.getEntityManager(). + getComponent(player); + + auto& ponderable = game_.getEntityManager(). + getComponent(player); + + auto& controlling = game_.getSystemManager().getSystem(); + controlling.freeze(player); + + animatable.setFrozen(true); + animatable.setFlickering(true); + ponderable.setFrozen(true); + ponderable.setCollidable(false); + + auto& scheduling = game_.getSystemManager().getSystem(); + + scheduling.schedule(player, 0.75, [&] (id_type player) { + auto& playable = game_.getEntityManager(). + getComponent(player); + + changeMap( + playable.checkpointMapId, + playable.checkpointX, + playable.checkpointY, + [&, player] () { + animatable.setFrozen(false); + animatable.setFlickering(false); + ponderable.setFrozen(false); + ponderable.setCollidable(true); + + // Reset the walk state, and then potentially let the + // ControllingSystem set it again. + auto& orienting = game_.getSystemManager(). + getSystem(); + orienting.stopWalking(player); + + controlling.unfreeze(player); + }); + }); } } diff --git a/src/systems/playing.h b/src/systems/playing.h index c98a464..ff16808 100644 --- a/src/systems/playing.h +++ b/src/systems/playing.h @@ -2,6 +2,7 @@ #define PLAYING_H_70A54F7D #include "system.h" +#include "components/playable.h" class PlayingSystem : public System { public: @@ -14,7 +15,13 @@ public: void initPlayer(); - void changeMap(size_t mapId, double x, double y); + void changeMap( + size_t mapId, + double x, + double y, + PlayableComponent::MapChangeCallback callback = nullptr); + + void die(); }; diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 2490dc9..d3601ac 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -27,6 +27,11 @@ void PonderingSystem::tick(double dt) auto& ponderable = game_.getEntityManager(). getComponent(entity); + if (ponderable.isFrozen()) + { + continue; + } + // Accelerate ponderable.setVelocityX( ponderable.getVelocityX() + ponderable.getAccelX() * dt); @@ -289,6 +294,17 @@ void PonderingSystem::tick(double dt) break; } } + + break; + } + + case Collision::Type::danger: + { + game_.getSystemManager().getSystem().die(); + + stopProcessing = true; + + break; } default: diff --git a/src/systems/scheduling.cpp b/src/systems/scheduling.cpp new file mode 100644 index 0000000..220efae --- /dev/null +++ b/src/systems/scheduling.cpp @@ -0,0 +1,54 @@ +#include "scheduling.h" +#include "game.h" +#include "components/schedulable.h" +#include "util.h" + +void SchedulingSystem::tick(double dt) +{ + auto entities = game_.getEntityManager().getEntitiesWithComponents< + SchedulableComponent>(); + + for (id_type entity : entities) + { + auto& schedulable = game_.getEntityManager(). + getComponent(entity); + + for (auto& action : schedulable.actions) + { + std::get<0>(action) -= dt; + + if (std::get<0>(action) < 0) + { + std::get<1>(action)(entity); + } + } + + erase_if(schedulable.actions, + [] (const SchedulableComponent::Action& action) { + return (std::get<0>(action) < 0); + }); + + if (schedulable.actions.empty()) + { + game_.getEntityManager().removeComponent(entity); + } + } +} + +void SchedulingSystem::schedule( + id_type entity, + double length, + std::function action) +{ + if (!game_.getEntityManager().hasComponent(entity)) + { + game_.getEntityManager().emplaceComponent(entity); + } + + auto& schedulable = game_.getEntityManager(). + getComponent(entity); + + schedulable.actions.emplace_back( + length, + std::move(action)); +} diff --git a/src/systems/scheduling.h b/src/systems/scheduling.h new file mode 100644 index 0000000..7950d62 --- /dev/null +++ b/src/systems/scheduling.h @@ -0,0 +1,22 @@ +#ifndef SCHEDULING_H_7B02E3E3 +#define SCHEDULING_H_7B02E3E3 + +#include "system.h" + +class SchedulingSystem : public System { +public: + + SchedulingSystem(Game& game) : System(game) + { + } + + void tick(double dt); + + void schedule( + id_type entity, + double length, + std::function action); + +}; + +#endif /* end of include guard: SCHEDULING_H_7B02E3E3 */ -- cgit 1.4.1 From dbc486d5cc0fa6b7cdb690fb4591f292d33e9ecc Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Mon, 19 Feb 2018 10:45:04 -0500 Subject: Added freefalling terminal velocity --- src/consts.h | 1 + src/systems/pondering.cpp | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'src') diff --git a/src/consts.h b/src/consts.h index a065159..f3f777f 100644 --- a/src/consts.h +++ b/src/consts.h @@ -22,5 +22,6 @@ const double JUMP_GRAVITY = CALC_GRAVITY(TILE_HEIGHT*4.5, 0.3); const double JUMP_VELOCITY = CALC_VELOCITY(TILE_HEIGHT*4.5, 0.3); const double WALK_SPEED = 90; +const double TERMINAL_VELOCITY = 240; #endif diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index d3601ac..02d5cfc 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -39,6 +39,12 @@ void PonderingSystem::tick(double dt) ponderable.setVelocityY( ponderable.getVelocityY() + ponderable.getAccelY() * dt); + if ((ponderable.getType() == PonderableComponent::Type::freefalling) + && (ponderable.getVelocityY() > TERMINAL_VELOCITY)) + { + ponderable.setVelocityY(TERMINAL_VELOCITY); + } + const double oldX = transformable.getX(); const double oldY = transformable.getY(); const double oldRight = oldX + transformable.getW(); -- cgit 1.4.1 From f782b81ba10c9b7a1e221b16de0aaa7b6c521729 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Wed, 25 Apr 2018 17:00:07 -0400 Subject: EntityManager const-correctness --- src/entity_manager.cpp | 4 ++-- src/entity_manager.h | 29 +++++++++++++++++++---------- 2 files changed, 21 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/entity_manager.cpp b/src/entity_manager.cpp index f792e17..0aaaf8e 100644 --- a/src/entity_manager.cpp +++ b/src/entity_manager.cpp @@ -5,7 +5,7 @@ template <> std::set EntityManager::getEntitiesWithComponents<>( - std::set& componentTypes) + std::set& componentTypes) const { if (cachedComponents.count(componentTypes) == 1) { @@ -15,7 +15,7 @@ std::set EntityManager::getEntitiesWithComponents<>( std::set& cache = cachedComponents[componentTypes]; for (id_type entity = 0; entity < entities.size(); entity++) { - EntityData& data = entities[entity]; + const EntityData& data = entities[entity]; bool cacheEntity = true; for (auto& componentType : componentTypes) diff --git a/src/entity_manager.h b/src/entity_manager.h index 1e8d31c..b2ef0de 100644 --- a/src/entity_manager.h +++ b/src/entity_manager.h @@ -27,13 +27,15 @@ private: database_type entities; std::vector slotAvailable; std::set allEntities; - std::map, std::set> cachedComponents; + + mutable std::map, std::set> + cachedComponents; id_type nextEntityID = 0; template std::set getEntitiesWithComponentsHelper( - std::set& componentTypes) + std::set& componentTypes) const { componentTypes.insert(typeid(T)); @@ -42,7 +44,7 @@ private: template std::set getEntitiesWithComponents( - std::set& componentTypes) + std::set& componentTypes) const { return getEntitiesWithComponentsHelper(componentTypes); } @@ -168,14 +170,14 @@ public: } template - T& getComponent(id_type entity) + const T& getComponent(id_type entity) const { if ((entity >= entities.size()) || slotAvailable[entity]) { throw std::invalid_argument("Cannot get non-existent entity"); } - EntityData& data = entities[entity]; + const EntityData& data = entities[entity]; std::type_index componentType = typeid(T); if (!data.components.count(componentType)) @@ -183,25 +185,32 @@ public: throw std::invalid_argument("Cannot get non-existent component"); } - return *dynamic_cast(data.components[componentType].get()); + return *dynamic_cast(data.components.at(componentType).get()); } template - bool hasComponent(id_type entity) + T& getComponent(id_type entity) + { + return const_cast( + static_cast(*this).getComponent(entity)); + } + + template + bool hasComponent(id_type entity) const { if ((entity >= entities.size()) || slotAvailable[entity]) { throw std::invalid_argument("Cannot get non-existent entity"); } - EntityData& data = entities[entity]; + const EntityData& data = entities[entity]; std::type_index componentType = typeid(T); return data.components.count(componentType); } template - std::set getEntitiesWithComponents() + std::set getEntitiesWithComponents() const { std::set componentTypes; @@ -216,6 +225,6 @@ public: template <> std::set EntityManager::getEntitiesWithComponents<>( - std::set& componentTypes); + std::set& componentTypes) const; #endif /* end of include guard: ENTITY_MANAGER_H_C5832F11 */ -- cgit 1.4.1 From 8016a7146fec3f6f43ca05723441750e5aae3d4d Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sat, 28 Apr 2018 09:22:44 -0400 Subject: Restructured the way the world is loaded The World class was removed and replaced by the RealizingSystem and RealizableComponent. The realizable entity is intended to be a singleton and to represent the world. The Map class was also removed and integrated into the MappableComponent. These changes are to facilitate implementation of map objects without needing special intermediary objects (including the Map class). Now, map entities are created as soon as the world is created, and map object entities will be as well. They will simply be deactivated while the map is not active. Multiple players are now slightly better supported, which will be important in the future. This will likely become inefficient as the world becomes bigger, and some sort of sector-loading process will have to be designed. This also reduces the usefulness of EntityManager's entity-searching capabilities (which are not the most efficiently implemented currently anyway), and will likely in the future require some added functionality to better search subsets of entities. A lot of the components were also rewritten to use bare member variables instead of accessor methods, as they never had special functionality and just took up space. These components were also documented. --- CMakeLists.txt | 2 +- src/components/animatable.h | 146 +++++++++-------- src/components/mappable.h | 208 ++++++++++++------------ src/components/playable.h | 28 ++-- src/components/ponderable.h | 151 ++++++++---------- src/components/realizable.h | 67 ++++++++ src/components/transformable.h | 79 +++------ src/game.cpp | 6 +- src/game.h | 7 - src/map.h | 111 ------------- src/systems/animating.cpp | 93 ++++++----- src/systems/animating.h | 2 + src/systems/mapping.cpp | 127 +++++++-------- src/systems/mapping.h | 2 +- src/systems/orienting.cpp | 22 +-- src/systems/playing.cpp | 220 ++++++++++++------------- src/systems/playing.h | 9 +- src/systems/pondering.cpp | 354 +++++++++++++++++++++++------------------ src/systems/pondering.h | 2 + src/systems/realizing.cpp | 321 +++++++++++++++++++++++++++++++++++++ src/systems/realizing.h | 43 +++++ src/world.cpp | 155 ------------------ src/world.h | 41 ----- 23 files changed, 1155 insertions(+), 1041 deletions(-) create mode 100644 src/components/realizable.h delete mode 100644 src/map.h create mode 100644 src/systems/realizing.cpp create mode 100644 src/systems/realizing.h delete mode 100644 src/world.cpp delete mode 100644 src/world.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 34246ad..81365c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,6 @@ add_executable(Aromatherapy src/entity_manager.cpp src/game.cpp src/animation.cpp - src/world.cpp src/util.cpp src/collision.cpp src/renderer/renderer.cpp @@ -67,6 +66,7 @@ add_executable(Aromatherapy src/systems/orienting.cpp src/systems/playing.cpp src/systems/scheduling.cpp + src/systems/realizing.cpp ) set_property(TARGET Aromatherapy PROPERTY CXX_STANDARD 11) diff --git a/src/components/animatable.h b/src/components/animatable.h index ec72be0..1a678ba 100644 --- a/src/components/animatable.h +++ b/src/components/animatable.h @@ -8,88 +8,86 @@ class AnimatableComponent : public Component { public: + /** + * Constructor for initializing the animation set, because it is not default + * constructible. + */ AnimatableComponent( - AnimationSet animationSet, - std::string animation) : - animationSet_(std::move(animationSet)), - animation_(std::move(animation)) + AnimationSet animationSet) : + animationSet(std::move(animationSet)) { } - inline size_t getFrame() const - { - return frame_; - } - - inline void setFrame(size_t v) - { - frame_ = v; - } - - inline size_t getCountdown() const - { - return countdown_; - } - - inline void setCountdown(size_t v) - { - countdown_ = v; - } - - inline const AnimationSet& getAnimationSet() const - { - return animationSet_; - } - + /** + * The animation set that this entity will use -- an object describing the + * different animations that can be used to render the entity. + * + * @managed_by RealizingSystem + */ + AnimationSet animationSet; + + /** + * The name of the currently active animation. + * + * @managed_by AnimatingSystem + */ + std::string animation; + + /** + * For prototypes, the name of the original animation. + * + * @managed_by RealizingSystem + */ + std::string origAnimation; + + /** + * Helper method for accessing the currently active animation. + */ inline const Animation& getAnimation() const { - return animationSet_.getAnimation(animation_); + return animationSet.getAnimation(animation); } - inline void setAnimation(std::string animation) - { - animation_ = std::move(animation); - } - - inline bool isFlickering() const - { - return flickering_; - } - - inline void setFlickering(bool v) - { - flickering_ = v; - } - - inline size_t getFlickerTimer() const - { - return flickerTimer_; - } - - inline void setFlickerTimer(size_t v) - { - flickerTimer_ = v; - } - - inline bool isFrozen() const - { - return frozen_; - } - - inline void setFrozen(bool v) - { - frozen_ = v; - } - -private: - - AnimationSet animationSet_; - std::string animation_; - size_t frame_ = 0; - size_t countdown_ = 0; - bool flickering_ = false; - size_t flickerTimer_ = 0; - bool frozen_ = false; + /** + * The frame of animation that is currently being rendered. + * + * @managed_by AnimatingSystem + */ + size_t frame = 0; + + /** + * The amount of time (in game frames) before the animation is advanced. + * + * @managed_by AnimatingSystem + */ + size_t countdown = 0; + + /** + * This option allows to give the sprite a "flickering" effect (as in, it is + * not rendered in some frames). + */ + bool flickering = false; + + /** + * Used for the flickering effect. + * + * @managed_by AnimatingSystem + */ + size_t flickerTimer = 0; + + /** + * If enabled, this will prevent the sprite's animation from progressing (but + * will not affect things such as placement on screen and flickering). + */ + bool frozen = false; + + /** + * If this flag is disabled, the entity will be ignored by the animating + * system. + * + * @managed_by RealizingSystem + */ + bool active = false; }; #endif /* end of include guard: SPRITE_RENDERABLE_H_D3AACBBF */ diff --git a/src/components/mappable.h b/src/components/mappable.h index 633cdf4..6f3d38e 100644 --- a/src/components/mappable.h +++ b/src/components/mappable.h @@ -2,14 +2,47 @@ #define MAPPABLE_H_0B0316FB #include +#include +#include +#include #include "component.h" #include "renderer/texture.h" #include "collision.h" -#include "map.h" +#include "entity_manager.h" class MappableComponent : public Component { public: + using id_type = EntityManager::id_type; + + /** + * Helper type that stores information about map adjacency. + */ + class Adjacent { + public: + + enum class Type { + wall, + wrap, + warp, + reverse + }; + + Adjacent( + Type type = Type::wall, + size_t mapId = 0) : + type(type), + mapId(mapId) + { + } + + Type type; + size_t mapId; + }; + + /** + * Helper type that stores information about collision boundaries. + */ class Boundary { public: @@ -20,121 +53,100 @@ public: double lower, double upper, Type type) : - axis_(axis), - lower_(lower), - upper_(upper), - type_(type) - { - } - - inline double getAxis() const - { - return axis_; - } - - inline double getLower() const - { - return lower_; - } - - inline double getUpper() const - { - return upper_; - } - - inline Type getType() const + axis(axis), + lower(lower), + upper(upper), + type(type) { - return type_; } - private: - - double axis_; - double lower_; - double upper_; - Type type_; + double axis; + double lower; + double upper; + Type type; }; - MappableComponent( - Texture tileset, - Texture font) : - tileset_(std::move(tileset)), - font_(std::move(font)) - { - } - + /** + * Helper types for efficient storage and lookup of collision boundaries. + */ using asc_boundaries_type = std::multimap< double, - Boundary, + const Boundary, std::less>; using desc_boundaries_type = std::multimap< double, - Boundary, + const Boundary, std::greater>; - inline size_t getMapId() const - { - return mapId_; - } - - inline void setMapId(size_t v) - { - mapId_ = v; - } - - inline desc_boundaries_type& getLeftBoundaries() - { - return leftBoundaries_; - } - - inline asc_boundaries_type& getRightBoundaries() - { - return rightBoundaries_; - } - - inline desc_boundaries_type& getUpBoundaries() - { - return upBoundaries_; - } - - inline asc_boundaries_type& getDownBoundaries() - { - return downBoundaries_; - } - - inline const Texture& getTileset() const - { - return tileset_; - } - - inline void setTileset(Texture v) - { - tileset_ = std::move(v); - } - - inline const Texture& getFont() const - { - return font_; - } - - inline void setFont(Texture v) + /** + * Constructor for initializing the tileset and font attributes, as they are + * not default constructible. + */ + MappableComponent( + Texture tileset, + Texture font) : + tileset(std::move(tileset)), + font(std::move(font)) { - font_ = std::move(v); } -private: - - size_t mapId_ = -1; - - desc_boundaries_type leftBoundaries_; - asc_boundaries_type rightBoundaries_; - desc_boundaries_type upBoundaries_; - asc_boundaries_type downBoundaries_; - Texture tileset_; - Texture font_; + /** + * The ID of the map in the world definition that this entity represents. + * + * @managed_by RealizingSystem + */ + size_t mapId; + + /** + * The title of the map, which is displayed at the bottom of the screen. + */ + std::string title; + + /** + * The map data. + * + * @managed_by RealizingSystem + */ + std::vector tiles; + + /** + * These objects describe the behavior of the four edges of the map. + * + * @managed_by RealizingSystem + */ + Adjacent leftAdjacent; + Adjacent rightAdjacent; + Adjacent upAdjacent; + Adjacent downAdjacent; + + /** + * Collision boundaries, for detecting when a ponderable entity is colliding + * with the environment. + * + * @managed_by MappingSystem + */ + desc_boundaries_type leftBoundaries; + asc_boundaries_type rightBoundaries; + desc_boundaries_type upBoundaries; + asc_boundaries_type downBoundaries; + + /** + * The list of entities representing the objects owned by the map. + * + * @managed_by RealizingSystem + */ + std::list objects; + + /** + * The tilesets for the map and the map name. + * + * TODO: These probably do not belong here. + */ + Texture tileset; + Texture font; }; #endif /* end of include guard: MAPPABLE_H_0B0316FB */ diff --git a/src/components/playable.h b/src/components/playable.h index 86a7ee7..94d4326 100644 --- a/src/components/playable.h +++ b/src/components/playable.h @@ -2,22 +2,30 @@ #define PLAYABLE_H_DDC566C3 #include "component.h" -#include +#include "entity_manager.h" class PlayableComponent : public Component { public: - using MapChangeCallback = std::function; + using id_type = EntityManager::id_type; - bool changingMap = false; - int newMapId = -1; - double newMapX = 0; - double newMapY = 0; - MapChangeCallback newMapCallback; + /** + * The entity ID of the map that the player is on. + * + * @managed_by PlayingSystem + */ + id_type mapId; - int checkpointMapId = -1; - double checkpointX = 0; - double checkpointY = 0; + /** + * The map ID and coordinates of the location that the player will spawn after + * dying. Note that the map ID here is a world description map ID, not an + * entity ID. + * + * @managed_by PlayingSystem + */ + size_t checkpointMapId; + double checkpointX; + double checkpointY; }; diff --git a/src/components/ponderable.h b/src/components/ponderable.h index 78af25f..fd7e775 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -6,100 +6,73 @@ class PonderableComponent : public Component { public: + /** + * List of different types of physical bodies. + * + * vacuumed - Default. + * freefalling - The body will be treated as if there were a downward force + * of gravity being exerted onto it. The body will also exhibit + * terminal velocity (that is, its downward velocity will be + * capped at a constant value). + */ enum class Type { vacuumed, freefalling }; - PonderableComponent(Type type) : type_(type) - { - } - - inline Type getType() const - { - return type_; - } - - inline double getVelocityX() const - { - return velX_; - } - - inline void setVelocityX(double v) - { - velX_ = v; - } - - inline double getVelocityY() const - { - return velY_; - } - - inline void setVelocityY(double v) - { - velY_ = v; - } - - inline double getAccelX() const - { - return accelX_; - } - - inline void setAccelX(double v) - { - accelX_ = v; - } - - inline double getAccelY() const - { - return accelY_; - } - - inline void setAccelY(double v) - { - accelY_ = v; - } - - inline bool isGrounded() const - { - return grounded_; - } - - inline void setGrounded(bool v) - { - grounded_ = v; - } - - inline bool isFrozen() const - { - return frozen_; - } - - inline void setFrozen(bool v) - { - frozen_ = v; - } - - inline bool isCollidable() const - { - return collidable_; - } - - inline void setCollidable(bool v) - { - collidable_ = v; - } - -private: - - double velX_ = 0.0; - double velY_ = 0.0; - double accelX_ = 0.0; - double accelY_ = 0.0; - Type type_ = Type::vacuumed; - bool grounded_ = false; - bool frozen_ = false; - bool collidable_ = true; + /** + * Constructor for initializing the body type, which is a constant. + */ + PonderableComponent(Type type) : type(type) + { + } + + /** + * The velocity of the body. + */ + double velX = 0.0; + double velY = 0.0; + + /** + * The acceleration of the body. + */ + double accelX = 0.0; + double accelY = 0.0; + + /** + * The type of physical body that the entity is meant to assume. The body will + * be acted upon differently based on this. See the enumeration above for more + * details. + * + * @managed_by PonderingSystem + */ + const Type type; + + /** + * Whether or not a freefalling body is in contact with the ground. + * + * @managed_by PonderingSystem + */ + bool grounded = false; + + /** + * If enabled, this will prevent the body from moving. + */ + bool frozen = false; + + /** + * If disabled, collision detection for this body will not be performed and + * other bodies will ignore it. + */ + bool collidable = true; + + /** + * If this flag is disabled, the entity will be ignored by the pondering + * system. + * + * @managed_by RealizingSystem + */ + bool active = false; }; #endif /* end of include guard: TANGIBLE_H_746DB3EE */ diff --git a/src/components/realizable.h b/src/components/realizable.h new file mode 100644 index 0000000..f6a7eb4 --- /dev/null +++ b/src/components/realizable.h @@ -0,0 +1,67 @@ +#ifndef REALIZABLE_H_36D8D71E +#define REALIZABLE_H_36D8D71E + +#include "component.h" +#include +#include +#include "entity_manager.h" + +class RealizableComponent : public Component { +public: + + using id_type = EntityManager::id_type; + + /** + * Path to the XML file containing the world definition. + * + * @managed_by RealizingSystem + */ + std::string worldFile; + + /** + * Starting map and player location for a new game. + * + * @managed_by RealizingSystem + */ + int startingMapId; + int startingX; + int startingY; + + /** + * The set of map entities loaded by this entity. It is only intended for + * there to be one realizable entity, so this should contain all loaded maps. + * The realizable entity has ownership of the loaded maps. + * + * @managed_by RealizingSystem + */ + std::set maps; + + /** + * A lookup table that translates a map ID to the entity representing that + * loaded map. + * + * @managed_by RealizingSystem + */ + std::map entityByMapId; + + /** + * The entity ID of the currently active map. + * + * @managed_by RealizingSystem + */ + id_type activeMap; + + /** + * Whether or not a map has been activated yet. + * + * @managed_by RealizingSystem + */ + bool hasActiveMap = false; + + /** + * The entity ID of the currently active player. + */ + id_type activePlayer; +}; + +#endif /* end of include guard: REALIZABLE_H_36D8D71E */ diff --git a/src/components/transformable.h b/src/components/transformable.h index 6ed2637..3296e49 100644 --- a/src/components/transformable.h +++ b/src/components/transformable.h @@ -6,64 +6,27 @@ class TransformableComponent : public Component { public: - TransformableComponent( - double x, - double y, - int w, - int h) : - x_(x), - y_(y), - w_(w), - h_(h) - { - } - - inline double getX() const - { - return x_; - } - - inline void setX(double v) - { - x_ = v; - } - - inline double getY() const - { - return y_; - } - - inline void setY(double v) - { - y_ = v; - } - - inline int getW() const - { - return w_; - } - - inline void setW(int v) - { - w_ = v; - } - - inline int getH() const - { - return h_; - } - - inline void setH(int v) - { - h_ = v; - } - -private: - - double x_; - double y_; - int w_; - int h_; + /** + * The coordinates of the entity. + */ + double x; + double y; + + /** + * The size of the entity. + */ + int w; + int h; + + /** + * For prototypes, the original coordinates and size of the entity. + * + * @managed_by RealizingSystem + */ + double origX; + double origY; + int origW; + int origH; }; #endif /* end of include guard: LOCATABLE_H_39E526CA */ diff --git a/src/game.cpp b/src/game.cpp index 3da23a3..b7dd200 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -11,6 +11,7 @@ #include "systems/orienting.h" #include "systems/playing.h" #include "systems/scheduling.h" +#include "systems/realizing.h" #include "animation.h" #include "consts.h" @@ -28,8 +29,9 @@ void key_callback(GLFWwindow* window, int key, int, int action, int) game.systemManager_.input(key, action); } -Game::Game() : world_("res/maps.xml") +Game::Game() { + systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); @@ -38,8 +40,8 @@ Game::Game() : world_("res/maps.xml") systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); + systemManager_.getSystem().initSingleton("res/maps.xml"); systemManager_.getSystem().initPlayer(); - systemManager_.getSystem().loadMap(world_.getStartingMapId()); glfwSwapInterval(1); glfwSetWindowUserPointer(renderer_.getWindow().getHandle(), this); diff --git a/src/game.h b/src/game.h index 43e08da..92a67d9 100644 --- a/src/game.h +++ b/src/game.h @@ -3,7 +3,6 @@ #include "entity_manager.h" #include "system_manager.h" -#include "world.h" #include "renderer/renderer.h" class Game { @@ -28,11 +27,6 @@ public: return systemManager_; } - inline const World& getWorld() - { - return world_; - } - friend void key_callback( GLFWwindow* window, int key, @@ -45,7 +39,6 @@ private: Renderer renderer_; EntityManager entityManager_; SystemManager systemManager_; - World world_; bool shouldQuit_ = false; }; diff --git a/src/map.h b/src/map.h deleted file mode 100644 index 6fe1e62..0000000 --- a/src/map.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef MAP_H_74055FC0 -#define MAP_H_74055FC0 - -#include -#include -#include -#include -#include - -class Map { -public: - - class Adjacent { - public: - - enum class Type { - wall, - wrap, - warp, - reverse - }; - - Adjacent( - Type type = Type::wall, - int mapId = -1) : - type_(type), - mapId_(mapId) - { - } - - inline Type getType() const - { - return type_; - } - - inline int getMapId() const - { - return mapId_; - } - - private: - - Type type_; - int mapId_; - }; - - Map( - int id, - std::vector tiles, - std::string title, - Adjacent leftAdjacent, - Adjacent rightAdjacent, - Adjacent upAdjacent, - Adjacent downAdjacent) : - id_(id), - tiles_(std::move(tiles)), - title_(std::move(title)), - leftAdjacent_(std::move(leftAdjacent)), - rightAdjacent_(std::move(rightAdjacent)), - upAdjacent_(std::move(upAdjacent)), - downAdjacent_(std::move(downAdjacent)) - { - } - - inline size_t getId() const - { - return id_; - } - - inline const std::vector& getTiles() const - { - return tiles_; - } - - inline const std::string& getTitle() const - { - return title_; - } - - inline const Adjacent& getLeftAdjacent() const - { - return leftAdjacent_; - } - - inline const Adjacent& getRightAdjacent() const - { - return rightAdjacent_; - } - - inline const Adjacent& getUpAdjacent() const - { - return upAdjacent_; - } - - inline const Adjacent& getDownAdjacent() const - { - return downAdjacent_; - } - -private: - - int id_; - std::vector tiles_; - std::string title_; - Adjacent leftAdjacent_; - Adjacent rightAdjacent_; - Adjacent upAdjacent_; - Adjacent downAdjacent_; -}; - -#endif /* end of include guard: MAP_H_74055FC0 */ diff --git a/src/systems/animating.cpp b/src/systems/animating.cpp index 634af67..8543ba2 100644 --- a/src/systems/animating.cpp +++ b/src/systems/animating.cpp @@ -13,26 +13,29 @@ void AnimatingSystem::tick(double) auto& sprite = game_.getEntityManager(). getComponent(entity); - if (!sprite.isFrozen()) + if (sprite.active) { - sprite.setCountdown(sprite.getCountdown() + 1); - } - - const Animation& anim = sprite.getAnimation(); - if (sprite.getCountdown() >= anim.getDelay()) - { - sprite.setFrame(sprite.getFrame() + 1); - sprite.setCountdown(0); + if (!sprite.frozen) + { + sprite.countdown++; + } - if (sprite.getFrame() >= anim.getFirstFrame() + anim.getNumFrames()) + const Animation& anim = sprite.getAnimation(); + if (sprite.countdown >= anim.getDelay()) { - sprite.setFrame(anim.getFirstFrame()); + sprite.frame++; + sprite.countdown = 0; + + if (sprite.frame >= anim.getFirstFrame() + anim.getNumFrames()) + { + sprite.frame = anim.getFirstFrame(); + } } - } - if (sprite.isFlickering()) - { - sprite.setFlickerTimer((sprite.getFlickerTimer() + 1) % 6); + if (sprite.flickering) + { + sprite.flickerTimer = (sprite.flickerTimer + 1) % 6; + } } } } @@ -49,36 +52,52 @@ void AnimatingSystem::render(Texture& texture) auto& sprite = game_.getEntityManager(). getComponent(entity); - auto& transform = game_.getEntityManager(). - getComponent(entity); - - double alpha = 1.0; - if (sprite.isFlickering() && (sprite.getFlickerTimer() < 3)) + if (sprite.active) { - alpha = 0.0; - } + auto& transform = game_.getEntityManager(). + getComponent(entity); - Rectangle dstrect { - static_cast(transform.getX()), - static_cast(transform.getY()), - transform.getW(), - transform.getH()}; - - const AnimationSet& aset = sprite.getAnimationSet(); - game_.getRenderer().blit( - aset.getTexture(), - texture, - aset.getFrameRect(sprite.getFrame()), - dstrect, - alpha); + double alpha = 1.0; + if (sprite.flickering && (sprite.flickerTimer < 3)) + { + alpha = 0.0; + } + + Rectangle dstrect { + static_cast(transform.x), + static_cast(transform.y), + transform.w, + transform.h}; + + const AnimationSet& aset = sprite.animationSet; + game_.getRenderer().blit( + aset.getTexture(), + texture, + aset.getFrameRect(sprite.frame), + dstrect, + alpha); + } } } +void AnimatingSystem::initPrototype(id_type entity) +{ + auto& sprite = game_.getEntityManager(). + getComponent(entity); + + startAnimation(entity, sprite.origAnimation); + + sprite.countdown = 0; + sprite.flickering = false; + sprite.flickerTimer = 0; + sprite.frozen = false; +} + void AnimatingSystem::startAnimation(id_type entity, std::string animation) { auto& sprite = game_.getEntityManager(). getComponent(entity); - sprite.setAnimation(animation); - sprite.setFrame(sprite.getAnimation().getFirstFrame()); + sprite.animation = std::move(animation); + sprite.frame = sprite.getAnimation().getFirstFrame(); } diff --git a/src/systems/animating.h b/src/systems/animating.h index 548bff1..acc6191 100644 --- a/src/systems/animating.h +++ b/src/systems/animating.h @@ -16,6 +16,8 @@ public: void render(Texture& texture); + void initPrototype(id_type entity); + void startAnimation(id_type entity, std::string animation); }; diff --git a/src/systems/mapping.cpp b/src/systems/mapping.cpp index a3a17ec..af67aed 100644 --- a/src/systems/mapping.cpp +++ b/src/systems/mapping.cpp @@ -1,5 +1,7 @@ #include "mapping.h" #include "components/mappable.h" +#include "components/realizable.h" +#include "systems/realizing.h" #include "game.h" #include "consts.h" @@ -18,104 +20,95 @@ inline void addBoundary( void MappingSystem::render(Texture& texture) { - auto entities = game_.getEntityManager().getEntitiesWithComponents< - MappableComponent>(); + auto& realizable = game_.getEntityManager(). + getComponent( + game_.getSystemManager().getSystem().getSingleton()); - for (id_type entity : entities) - { - auto& mappable = game_.getEntityManager(). - getComponent(entity); + id_type map = realizable.activeMap; - const Map& map = game_.getWorld().getMap(mappable.getMapId()); + auto& mappable = game_.getEntityManager(). + getComponent(map); - for (int i = 0; i < MAP_WIDTH * MAP_HEIGHT; i++) - { - int x = i % MAP_WIDTH; - int y = i / MAP_WIDTH; - int tile = map.getTiles()[i]; - - if (tile > 0) - { - Rectangle dst { - x * TILE_WIDTH, - y * TILE_HEIGHT, - TILE_WIDTH, - TILE_HEIGHT}; - - Rectangle src { - (tile % TILESET_COLS) * TILE_WIDTH, - (tile / TILESET_COLS) * TILE_HEIGHT, - TILE_WIDTH, - TILE_HEIGHT}; - - game_.getRenderer().blit( - mappable.getTileset(), - texture, - std::move(src), - std::move(dst)); - } - } + for (int i = 0; i < MAP_WIDTH * MAP_HEIGHT; i++) + { + int x = i % MAP_WIDTH; + int y = i / MAP_WIDTH; + int tile = mappable.tiles[i]; - int startX = ((GAME_WIDTH / TILE_WIDTH) / 2) - (map.getTitle().size() / 2); - for (size_t i = 0; i < map.getTitle().size(); i++) + if (tile > 0) { - Rectangle src { - (map.getTitle()[i] % FONT_COLS) * TILE_WIDTH, - (map.getTitle()[i] / FONT_COLS) * TILE_HEIGHT, + Rectangle dst { + x * TILE_WIDTH, + y * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT}; - Rectangle dst { - (startX + static_cast(i)) * TILE_WIDTH, - 24 * TILE_HEIGHT, + Rectangle src { + (tile % TILESET_COLS) * TILE_WIDTH, + (tile / TILESET_COLS) * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT}; game_.getRenderer().blit( - mappable.getFont(), + mappable.tileset, texture, std::move(src), std::move(dst)); } } + + int startX = ((GAME_WIDTH / TILE_WIDTH) / 2) - (mappable.title.size() / 2); + + for (size_t i = 0; i < mappable.title.size(); i++) + { + Rectangle src { + (mappable.title[i] % FONT_COLS) * TILE_WIDTH, + (mappable.title[i] / FONT_COLS) * TILE_HEIGHT, + TILE_WIDTH, + TILE_HEIGHT}; + + Rectangle dst { + (startX + static_cast(i)) * TILE_WIDTH, + 24 * TILE_HEIGHT, + TILE_WIDTH, + TILE_HEIGHT}; + + game_.getRenderer().blit( + mappable.font, + texture, + std::move(src), + std::move(dst)); + } } -void MappingSystem::loadMap(size_t mapId) +void MappingSystem::generateBoundaries(id_type mapEntity) { - id_type mapEntity = game_.getEntityManager().emplaceEntity(); - auto& mappable = game_.getEntityManager(). - emplaceComponent(mapEntity, - Texture("res/tiles.png"), - Texture("res/font.bmp")); - - mappable.setMapId(mapId); - - const Map& map = game_.getWorld().getMap(mappable.getMapId()); + getComponent(mapEntity); addBoundary( - mappable.getLeftBoundaries(), + mappable.leftBoundaries, -WALL_GAP, 0, MAP_HEIGHT * TILE_HEIGHT, MappableComponent::Boundary::Type::adjacency); addBoundary( - mappable.getRightBoundaries(), + mappable.rightBoundaries, GAME_WIDTH + WALL_GAP, 0, MAP_HEIGHT * TILE_HEIGHT, MappableComponent::Boundary::Type::adjacency); addBoundary( - mappable.getUpBoundaries(), + mappable.upBoundaries, -WALL_GAP, 0, GAME_WIDTH, MappableComponent::Boundary::Type::adjacency); addBoundary( - mappable.getDownBoundaries(), + mappable.downBoundaries, MAP_HEIGHT * TILE_HEIGHT + WALL_GAP, 0, GAME_WIDTH, @@ -125,12 +118,12 @@ void MappingSystem::loadMap(size_t mapId) { size_t x = i % MAP_WIDTH; size_t y = i / MAP_WIDTH; - int tile = map.getTiles()[i]; + int tile = mappable.tiles[i]; if ((tile >= 5) && (tile <= 7)) { addBoundary( - mappable.getDownBoundaries(), + mappable.downBoundaries, y * TILE_HEIGHT, x * TILE_WIDTH, (x + 1) * TILE_WIDTH, @@ -138,28 +131,28 @@ void MappingSystem::loadMap(size_t mapId) } else if ((tile > 0) && (tile < 28)) { addBoundary( - mappable.getRightBoundaries(), + mappable.rightBoundaries, x * TILE_WIDTH, y * TILE_HEIGHT, (y+1) * TILE_HEIGHT, MappableComponent::Boundary::Type::wall); addBoundary( - mappable.getLeftBoundaries(), + mappable.leftBoundaries, (x+1) * TILE_WIDTH, y * TILE_HEIGHT, (y+1) * TILE_HEIGHT, MappableComponent::Boundary::Type::wall); addBoundary( - mappable.getDownBoundaries(), + mappable.downBoundaries, y * TILE_HEIGHT, x * TILE_WIDTH, (x+1) * TILE_WIDTH, MappableComponent::Boundary::Type::wall); addBoundary( - mappable.getUpBoundaries(), + mappable.upBoundaries, (y+1) * TILE_HEIGHT, x * TILE_WIDTH, (x+1) * TILE_WIDTH, @@ -167,28 +160,28 @@ void MappingSystem::loadMap(size_t mapId) } else if (tile == 42) { addBoundary( - mappable.getRightBoundaries(), + mappable.rightBoundaries, x * TILE_WIDTH, y * TILE_HEIGHT, (y+1) * TILE_HEIGHT, MappableComponent::Boundary::Type::danger); addBoundary( - mappable.getLeftBoundaries(), + mappable.leftBoundaries, (x+1) * TILE_WIDTH, y * TILE_HEIGHT, (y+1) * TILE_HEIGHT, MappableComponent::Boundary::Type::danger); addBoundary( - mappable.getDownBoundaries(), + mappable.downBoundaries, y * TILE_HEIGHT, x * TILE_WIDTH, (x+1) * TILE_WIDTH, MappableComponent::Boundary::Type::danger); addBoundary( - mappable.getUpBoundaries(), + mappable.upBoundaries, (y+1) * TILE_HEIGHT, x * TILE_WIDTH, (x+1) * TILE_WIDTH, diff --git a/src/systems/mapping.h b/src/systems/mapping.h index 53d054b..3c47419 100644 --- a/src/systems/mapping.h +++ b/src/systems/mapping.h @@ -12,7 +12,7 @@ public: void render(Texture& texture); - void loadMap(size_t mapId); + void generateBoundaries(id_type mapEntity); }; diff --git a/src/systems/orienting.cpp b/src/systems/orienting.cpp index 2df8f87..206ebf6 100644 --- a/src/systems/orienting.cpp +++ b/src/systems/orienting.cpp @@ -24,27 +24,27 @@ void OrientingSystem::tick(double) { case OrientableComponent::WalkState::still: { - ponderable.setVelocityX(0); + ponderable.velX = 0.0; break; } case OrientableComponent::WalkState::left: { - ponderable.setVelocityX(-WALK_SPEED); + ponderable.velX = -WALK_SPEED; break; } case OrientableComponent::WalkState::right: { - ponderable.setVelocityX(WALK_SPEED); + ponderable.velX = WALK_SPEED; break; } } - if (orientable.isJumping() && (ponderable.getVelocityY() > 0)) + if (orientable.isJumping() && (ponderable.velY > 0)) { orientable.setJumping(false); } @@ -63,7 +63,7 @@ void OrientingSystem::moveLeft(id_type entity) orientable.setWalkState(OrientableComponent::WalkState::left); auto& animating = game_.getSystemManager().getSystem(); - if (ponderable.isGrounded()) + if (ponderable.grounded) { animating.startAnimation(entity, "walkingLeft"); } else { @@ -83,7 +83,7 @@ void OrientingSystem::moveRight(id_type entity) orientable.setWalkState(OrientableComponent::WalkState::right); auto& animating = game_.getSystemManager().getSystem(); - if (ponderable.isGrounded()) + if (ponderable.grounded) { animating.startAnimation(entity, "walkingRight"); } else { @@ -113,7 +113,7 @@ void OrientingSystem::jump(id_type entity) auto& ponderable = game_.getEntityManager(). getComponent(entity); - if (ponderable.isGrounded()) + if (ponderable.grounded) { auto& orientable = game_.getEntityManager(). getComponent(entity); @@ -122,8 +122,8 @@ void OrientingSystem::jump(id_type entity) playSound("res/Randomize87.wav", 0.25); - ponderable.setVelocityY(JUMP_VELOCITY); - ponderable.setAccelY(JUMP_GRAVITY); + ponderable.velY = JUMP_VELOCITY; + ponderable.accelY = JUMP_GRAVITY; auto& animating = game_.getSystemManager().getSystem(); if (orientable.isFacingRight()) @@ -147,7 +147,7 @@ void OrientingSystem::stopJumping(id_type entity) auto& ponderable = game_.getEntityManager(). getComponent(entity); - ponderable.setAccelY(NORMAL_GRAVITY); + ponderable.accelY = NORMAL_GRAVITY; } } @@ -211,7 +211,7 @@ void OrientingSystem::drop(id_type entity) auto& ponderable = game_.getEntityManager(). getComponent(entity); - if (ponderable.isGrounded() + if (ponderable.grounded && (orientable.getDropState() == OrientableComponent::DropState::none)) { orientable.setDropState(OrientableComponent::DropState::ready); diff --git a/src/systems/playing.cpp b/src/systems/playing.cpp index 40d9706..b04f0cb 100644 --- a/src/systems/playing.cpp +++ b/src/systems/playing.cpp @@ -5,61 +5,17 @@ #include "components/playable.h" #include "components/controllable.h" #include "components/orientable.h" +#include "components/realizable.h" #include "systems/mapping.h" #include "systems/pondering.h" #include "systems/orienting.h" #include "systems/scheduling.h" #include "systems/controlling.h" +#include "systems/animating.h" +#include "systems/realizing.h" #include "animation.h" #include "muxer.h" -void PlayingSystem::tick(double) -{ - // Check if we need to change the map - auto players = game_.getEntityManager().getEntitiesWithComponents< - PlayableComponent, - TransformableComponent>(); - - for (id_type player : players) - { - auto& playable = game_.getEntityManager(). - getComponent(player); - - if (playable.changingMap) - { - // Change the map! - auto entities = game_.getEntityManager().getEntities(); - - for (id_type entity : entities) - { - if (entity != player) - { - game_.getEntityManager().deleteEntity(entity); - } - } - - game_.getSystemManager().getSystem(). - loadMap(playable.newMapId); - - auto& transformable = game_.getEntityManager(). - getComponent(player); - - transformable.setX(playable.newMapX); - transformable.setY(playable.newMapY); - - playable.changingMap = false; - - if (playable.newMapCallback) - { - playable.newMapCallback(); - playable.newMapCallback = nullptr; - } - - break; - } - } -} - void PlayingSystem::initPlayer() { id_type player = game_.getEntityManager().emplaceEntity(); @@ -72,15 +28,24 @@ void PlayingSystem::initPlayer() game_.getEntityManager().emplaceComponent( player, - std::move(playerGraphics), - "stillLeft"); + std::move(playerGraphics)); - game_.getEntityManager().emplaceComponent( + game_.getSystemManager().getSystem().startAnimation( player, - game_.getWorld().getStartingX(), - game_.getWorld().getStartingY(), - 10, - 12); + "stillLeft"); + + auto& realizing = game_.getSystemManager().getSystem(); + + auto& realizable = game_.getEntityManager(). + getComponent(realizing.getSingleton()); + + auto& transformable = game_.getEntityManager(). + emplaceComponent(player); + + transformable.x = realizable.startingX; + transformable.y = realizable.startingY; + transformable.w = 10; + transformable.h = 12; game_.getSystemManager().getSystem().initializeBody( player, @@ -92,84 +57,103 @@ void PlayingSystem::initPlayer() auto& playable = game_.getEntityManager(). emplaceComponent(player); - playable.checkpointMapId = game_.getWorld().getStartingMapId(); - playable.checkpointX = game_.getWorld().getStartingX(); - playable.checkpointY = game_.getWorld().getStartingY(); + playable.mapId = realizable.activeMap; + playable.checkpointMapId = realizable.startingMapId; + playable.checkpointX = realizable.startingX; + playable.checkpointY = realizable.startingY; + + realizing.enterActiveMap(player); + + realizable.activePlayer = player; } void PlayingSystem::changeMap( + id_type player, size_t mapId, double x, - double y, - PlayableComponent::MapChangeCallback callback) + double y) { - auto players = game_.getEntityManager().getEntitiesWithComponents< - PlayableComponent>(); + auto& playable = game_.getEntityManager(). + getComponent(player); - for (id_type player : players) + auto& transformable = game_.getEntityManager(). + getComponent(player); + + auto& animatable = game_.getEntityManager(). + getComponent(player); + + auto& ponderable = game_.getEntityManager(). + getComponent(player); + + auto& realizing = game_.getSystemManager().getSystem(); + + auto& realizable = game_.getEntityManager(). + getComponent(realizing.getSingleton()); + + id_type newMapEntity = realizable.entityByMapId[mapId]; + + if (playable.mapId != newMapEntity) { - auto& playable = game_.getEntityManager(). - getComponent(player); + if (playable.mapId == realizable.activeMap) + { + realizing.leaveActiveMap(player); + } else if (newMapEntity == realizable.activeMap) + { + realizing.enterActiveMap(player); + } - playable.changingMap = true; - playable.newMapId = mapId; - playable.newMapX = x; - playable.newMapY = y; - playable.newMapCallback = std::move(callback); + playable.mapId = newMapEntity; + } + + transformable.x = x; + transformable.y = y; + + if (realizable.activePlayer == player) + { + realizing.loadMap(newMapEntity); } } -void PlayingSystem::die() +void PlayingSystem::die(id_type player) { playSound("res/Hit_Hurt5.wav", 0.25); - auto players = game_.getEntityManager().getEntitiesWithComponents< - OrientableComponent, - ControllableComponent, - AnimatableComponent, - PonderableComponent, - PlayableComponent>(); + auto& animatable = game_.getEntityManager(). + getComponent(player); - for (id_type player : players) - { - auto& animatable = game_.getEntityManager(). - getComponent(player); - - auto& ponderable = game_.getEntityManager(). - getComponent(player); - - auto& controlling = game_.getSystemManager().getSystem(); - controlling.freeze(player); - - animatable.setFrozen(true); - animatable.setFlickering(true); - ponderable.setFrozen(true); - ponderable.setCollidable(false); - - auto& scheduling = game_.getSystemManager().getSystem(); - - scheduling.schedule(player, 0.75, [&] (id_type player) { - auto& playable = game_.getEntityManager(). - getComponent(player); - - changeMap( - playable.checkpointMapId, - playable.checkpointX, - playable.checkpointY, - [&, player] () { - animatable.setFrozen(false); - animatable.setFlickering(false); - ponderable.setFrozen(false); - ponderable.setCollidable(true); - - // Reset the walk state, and then potentially let the - // ControllingSystem set it again. - auto& orienting = game_.getSystemManager(). - getSystem(); - orienting.stopWalking(player); - - controlling.unfreeze(player); - }); - }); - } + auto& ponderable = game_.getEntityManager(). + getComponent(player); + + auto& controlling = game_.getSystemManager().getSystem(); + controlling.freeze(player); + + animatable.frozen = true; + animatable.flickering = true; + ponderable.frozen = true; + ponderable.collidable = false; + + auto& scheduling = game_.getSystemManager().getSystem(); + + scheduling.schedule(player, 0.75, [&] (id_type player) { + auto& playable = game_.getEntityManager(). + getComponent(player); + + changeMap( + player, + playable.checkpointMapId, + playable.checkpointX, + playable.checkpointY); + + animatable.frozen = false; + animatable.flickering = false; + ponderable.frozen = false; + ponderable.collidable = true; + + // Reset the walk state, and then potentially let the + // ControllingSystem set it again. + auto& orienting = game_.getSystemManager().getSystem(); + orienting.stopWalking(player); + + controlling.unfreeze(player); + }); } diff --git a/src/systems/playing.h b/src/systems/playing.h index ff16808..9ba403b 100644 --- a/src/systems/playing.h +++ b/src/systems/playing.h @@ -2,7 +2,6 @@ #define PLAYING_H_70A54F7D #include "system.h" -#include "components/playable.h" class PlayingSystem : public System { public: @@ -11,17 +10,15 @@ public: { } - void tick(double dt); - void initPlayer(); void changeMap( + id_type player, size_t mapId, double x, - double y, - PlayableComponent::MapChangeCallback callback = nullptr); + double y); - void die(); + void die(id_type player); }; diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 02d5cfc..4ae6176 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -5,149 +5,153 @@ #include "components/transformable.h" #include "components/orientable.h" #include "components/mappable.h" +#include "components/realizable.h" +#include "components/playable.h" #include "systems/orienting.h" #include "systems/playing.h" +#include "systems/realizing.h" #include "consts.h" #include "collision.h" void PonderingSystem::tick(double dt) { + auto& realizable = game_.getEntityManager(). + getComponent( + game_.getSystemManager().getSystem().getSingleton()); + + id_type mapEntity = realizable.activeMap; + + auto& mappable = game_.getEntityManager(). + getComponent(mapEntity); + auto entities = game_.getEntityManager().getEntitiesWithComponents< PonderableComponent, TransformableComponent>(); - auto maps = game_.getEntityManager().getEntitiesWithComponents< - MappableComponent>(); - for (id_type entity : entities) { - auto& transformable = game_.getEntityManager(). - getComponent(entity); - auto& ponderable = game_.getEntityManager(). getComponent(entity); - if (ponderable.isFrozen()) + if (!ponderable.active || ponderable.frozen) { continue; } - // Accelerate - ponderable.setVelocityX( - ponderable.getVelocityX() + ponderable.getAccelX() * dt); + auto& transformable = game_.getEntityManager(). + getComponent(entity); - ponderable.setVelocityY( - ponderable.getVelocityY() + ponderable.getAccelY() * dt); + // Accelerate + ponderable.velX += ponderable.accelX * dt; + ponderable.velY += ponderable.accelY * dt; - if ((ponderable.getType() == PonderableComponent::Type::freefalling) - && (ponderable.getVelocityY() > TERMINAL_VELOCITY)) + if ((ponderable.type == PonderableComponent::Type::freefalling) + && (ponderable.velY > TERMINAL_VELOCITY)) { - ponderable.setVelocityY(TERMINAL_VELOCITY); + ponderable.velY = TERMINAL_VELOCITY; } - const double oldX = transformable.getX(); - const double oldY = transformable.getY(); - const double oldRight = oldX + transformable.getW(); - const double oldBottom = oldY + transformable.getH(); + const double oldX = transformable.x; + const double oldY = transformable.y; + const double oldRight = oldX + transformable.w; + const double oldBottom = oldY + transformable.h; - double newX = oldX + ponderable.getVelocityX() * dt; - double newY = oldY + ponderable.getVelocityY() * dt; + double newX = oldX + ponderable.velX * dt; + double newY = oldY + ponderable.velY * dt; - bool oldGrounded = ponderable.isGrounded(); - ponderable.setGrounded(false); + bool oldGrounded = ponderable.grounded; + ponderable.grounded = false; std::priority_queue collisions; // Find collisions - for (id_type mapEntity : maps) + if (newX < oldX) { - auto& mappable = game_.getEntityManager(). - getComponent(mapEntity); - - if (newX < oldX) + for (auto it = mappable.leftBoundaries.lower_bound(oldX); + (it != std::end(mappable.leftBoundaries)) && (it->first >= newX); + it++) { - for (auto it = mappable.getLeftBoundaries().lower_bound(oldX); - (it != std::end(mappable.getLeftBoundaries())) && (it->first >= newX); - it++) + if ((oldBottom > it->second.lower) + && (oldY < it->second.upper)) { - if ((oldBottom > it->second.getLower()) - && (oldY < it->second.getUpper())) - { - // We have a collision! - collisions.emplace( - mapEntity, - Direction::left, - it->second.getType(), - it->first, - it->second.getLower(), - it->second.getUpper()); - } + // We have a collision! + collisions.emplace( + mapEntity, + Direction::left, + it->second.type, + it->first, + it->second.lower, + it->second.upper); } - } else if (newX > oldX) + } + } else if (newX > oldX) + { + for (auto it = mappable.rightBoundaries.lower_bound(oldRight); + (it != std::end(mappable.rightBoundaries)) + && (it->first <= (newX + transformable.w)); + it++) { - for (auto it = mappable.getRightBoundaries().lower_bound(oldRight); - (it != std::end(mappable.getRightBoundaries())) - && (it->first <= (newX + transformable.getW())); - it++) + if ((oldBottom > it->second.lower) + && (oldY < it->second.upper)) { - if ((oldBottom > it->second.getLower()) - && (oldY < it->second.getUpper())) - { - // We have a collision! - collisions.emplace( - mapEntity, - Direction::right, - it->second.getType(), - it->first, - it->second.getLower(), - it->second.getUpper()); - } + // We have a collision! + collisions.emplace( + mapEntity, + Direction::right, + it->second.type, + it->first, + it->second.lower, + it->second.upper); } } + } - if (newY < oldY) + if (newY < oldY) + { + for (auto it = mappable.upBoundaries.lower_bound(oldY); + (it != std::end(mappable.upBoundaries)) && (it->first >= newY); + it++) { - for (auto it = mappable.getUpBoundaries().lower_bound(oldY); - (it != std::end(mappable.getUpBoundaries())) && (it->first >= newY); - it++) + if ((oldRight > it->second.lower) + && (oldX < it->second.upper)) { - if ((oldRight > it->second.getLower()) - && (oldX < it->second.getUpper())) - { - // We have a collision! - collisions.emplace( - mapEntity, - Direction::up, - it->second.getType(), - it->first, - it->second.getLower(), - it->second.getUpper()); - } + // We have a collision! + collisions.emplace( + mapEntity, + Direction::up, + it->second.type, + it->first, + it->second.lower, + it->second.upper); } - } else if (newY > oldY) + } + } else if (newY > oldY) + { + for (auto it = mappable.downBoundaries.lower_bound(oldBottom); + (it != std::end(mappable.downBoundaries)) + && (it->first <= (newY + transformable.h)); + it++) { - for (auto it = mappable.getDownBoundaries().lower_bound(oldBottom); - (it != std::end(mappable.getDownBoundaries())) - && (it->first <= (newY + transformable.getH())); - it++) + if ((oldRight > it->second.lower) + && (oldX < it->second.upper)) { - if ((oldRight > it->second.getLower()) - && (oldX < it->second.getUpper())) - { - // We have a collision! - collisions.emplace( - mapEntity, - Direction::down, - it->second.getType(), - it->first, - it->second.getLower(), - it->second.getUpper()); - } + // We have a collision! + collisions.emplace( + mapEntity, + Direction::down, + it->second.type, + it->first, + it->second.lower, + it->second.upper); } } } // Process collisions in order of priority + bool adjacentlyWarping = false; + Direction adjWarpDir; + size_t adjWarpMapId; + while (!collisions.empty()) { Collision collision = collisions.top(); @@ -157,8 +161,8 @@ void PonderingSystem::tick(double dt) if (!collision.isColliding( newX, newY, - transformable.getW(), - transformable.getH())) + transformable.w, + transformable.h)) { continue; } @@ -201,33 +205,33 @@ void PonderingSystem::tick(double dt) { auto& mappable = game_.getEntityManager(). getComponent(collision.getCollider()); - const Map& map = game_.getWorld().getMap(mappable.getMapId()); - auto& adj = [&] () -> const Map::Adjacent& { + + auto& adj = [&] () -> const MappableComponent::Adjacent& { switch (collision.getDirection()) { - case Direction::left: return map.getLeftAdjacent(); - case Direction::right: return map.getRightAdjacent(); - case Direction::up: return map.getUpAdjacent(); - case Direction::down: return map.getDownAdjacent(); + case Direction::left: return mappable.leftAdjacent; + case Direction::right: return mappable.rightAdjacent; + case Direction::up: return mappable.upAdjacent; + case Direction::down: return mappable.downAdjacent; } }(); - switch (adj.getType()) + switch (adj.type) { - case Map::Adjacent::Type::wall: + case MappableComponent::Adjacent::Type::wall: { touchedWall = true; break; } - case Map::Adjacent::Type::wrap: + case MappableComponent::Adjacent::Type::wrap: { switch (collision.getDirection()) { case Direction::left: { - newX = GAME_WIDTH + WALL_GAP - transformable.getW(); + newX = GAME_WIDTH + WALL_GAP - transformable.w; break; } @@ -241,8 +245,7 @@ void PonderingSystem::tick(double dt) case Direction::up: { - newY = MAP_HEIGHT * TILE_HEIGHT + WALL_GAP - - transformable.getH(); + newY = MAP_HEIGHT * TILE_HEIGHT + WALL_GAP - transformable.h; break; } @@ -256,46 +259,22 @@ void PonderingSystem::tick(double dt) } } - case Map::Adjacent::Type::warp: + case MappableComponent::Adjacent::Type::warp: { - double warpX = newX; - double warpY = newY; - - switch (collision.getDirection()) + if (game_.getEntityManager(). + hasComponent(entity)) { - case Direction::left: - { - warpX = GAME_WIDTH + WALL_GAP - transformable.getW(); - - break; - } - - case Direction::right: - { - warpX = -WALL_GAP; - - break; - } - - case Direction::up: - { - warpY = MAP_HEIGHT * TILE_HEIGHT - transformable.getH(); - - break; - } - - case Direction::down: - { - warpY = -WALL_GAP; - - break; - } + adjacentlyWarping = true; + adjWarpDir = collision.getDirection(); + adjWarpMapId = adj.mapId; } - game_.getSystemManager().getSystem(). - changeMap(adj.getMapId(), warpX, warpY); + break; + } - stopProcessing = true; + case MappableComponent::Adjacent::Type::reverse: + { + // TODO: not yet implemented. break; } @@ -306,7 +285,13 @@ void PonderingSystem::tick(double dt) case Collision::Type::danger: { - game_.getSystemManager().getSystem().die(); + if (game_.getEntityManager(). + hasComponent(entity)) + { + game_.getSystemManager().getSystem().die(entity); + + adjacentlyWarping = false; + } stopProcessing = true; @@ -333,15 +318,15 @@ void PonderingSystem::tick(double dt) case Direction::left: { newX = collision.getAxis(); - ponderable.setVelocityX(0.0); + ponderable.velX = 0.0; break; } case Direction::right: { - newX = collision.getAxis() - transformable.getW(); - ponderable.setVelocityX(0.0); + newX = collision.getAxis() - transformable.w; + ponderable.velX = 0.0; break; } @@ -349,16 +334,16 @@ void PonderingSystem::tick(double dt) case Direction::up: { newY = collision.getAxis(); - ponderable.setVelocityY(0.0); + ponderable.velY = 0.0; break; } case Direction::down: { - newY = collision.getAxis() - transformable.getH(); - ponderable.setVelocityY(0.0); - ponderable.setGrounded(true); + newY = collision.getAxis() - transformable.h; + ponderable.velY = 0.0; + ponderable.grounded = true; break; } @@ -367,8 +352,8 @@ void PonderingSystem::tick(double dt) } // Move - transformable.setX(newX); - transformable.setY(newY); + transformable.x = newX; + transformable.y = newY; // Perform cleanup for orientable entites if (game_.getEntityManager().hasComponent(entity)) @@ -377,9 +362,9 @@ void PonderingSystem::tick(double dt) getComponent(entity); // Handle changes in groundedness - if (ponderable.isGrounded() != oldGrounded) + if (ponderable.grounded != oldGrounded) { - if (ponderable.isGrounded()) + if (ponderable.grounded) { game_.getSystemManager().getSystem().land(entity); } else { @@ -394,6 +379,51 @@ void PonderingSystem::tick(double dt) orientable.setDropState(OrientableComponent::DropState::none); } } + + // Move to an adjacent map, if necessary + if (adjacentlyWarping) + { + double warpX = newX; + double warpY = newY; + + switch (adjWarpDir) + { + case Direction::left: + { + warpX = GAME_WIDTH + WALL_GAP - transformable.w; + + break; + } + + case Direction::right: + { + warpX = -WALL_GAP; + + break; + } + + case Direction::up: + { + warpY = MAP_HEIGHT * TILE_HEIGHT - transformable.h; + + break; + } + + case Direction::down: + { + warpY = -WALL_GAP; + + break; + } + } + + game_.getSystemManager().getSystem(). + changeMap( + entity, + adjWarpMapId, + warpX, + warpY); + } } } @@ -406,6 +436,20 @@ void PonderingSystem::initializeBody( if (type == PonderableComponent::Type::freefalling) { - ponderable.setAccelY(NORMAL_GRAVITY); + ponderable.accelY = NORMAL_GRAVITY; } } + +void PonderingSystem::initPrototype(id_type prototype) +{ + auto& ponderable = game_.getEntityManager(). + getComponent(prototype); + + ponderable.velX = 0.0; + ponderable.velY = 0.0; + ponderable.accelX = 0.0; + ponderable.accelY = 0.0; + ponderable.grounded = false; + ponderable.frozen = false; + ponderable.collidable = true; +} diff --git a/src/systems/pondering.h b/src/systems/pondering.h index d70525b..58e6496 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -16,6 +16,8 @@ public: void initializeBody(id_type entity, PonderableComponent::Type type); + void initPrototype(id_type prototype); + }; #endif /* end of include guard: PONDERING_H_F2530E0E */ diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp new file mode 100644 index 0000000..09c38f3 --- /dev/null +++ b/src/systems/realizing.cpp @@ -0,0 +1,321 @@ +#include "realizing.h" +#include +#include +#include +#include "game.h" +#include "consts.h" +#include "components/realizable.h" +#include "components/mappable.h" +#include "components/animatable.h" +#include "components/playable.h" +#include "components/ponderable.h" +#include "components/transformable.h" +#include "systems/mapping.h" +#include "systems/animating.h" +#include "systems/pondering.h" + +inline xmlChar* getProp(xmlNodePtr node, const char* attr) +{ + xmlChar* key = xmlGetProp(node, reinterpret_cast(attr)); + if (key == nullptr) + { + throw std::invalid_argument("Error parsing world file"); + } + + return key; +} + +// TODO: neither the XML doc nor any of the emplaced entities are properly +// destroyed if this method throws an exception. +EntityManager::id_type RealizingSystem::initSingleton(std::string filename) +{ + id_type world = game_.getEntityManager().emplaceEntity(); + + auto& realizable = game_.getEntityManager(). + emplaceComponent(world); + + auto& mapping = game_.getSystemManager().getSystem(); + + xmlDocPtr doc = xmlParseFile(filename.c_str()); + if (doc == nullptr) + { + throw std::invalid_argument("Cannot find world file"); + } + + xmlNodePtr top = xmlDocGetRootElement(doc); + if (top == nullptr) + { + throw std::invalid_argument("Error parsing world file"); + } + + if (xmlStrcmp(top->name, reinterpret_cast("world"))) + { + throw std::invalid_argument("Error parsing world file"); + } + + xmlChar* key = nullptr; + + key = getProp(top, "startx"); + realizable.startingX = atoi(reinterpret_cast(key)); + xmlFree(key); + + key = getProp(top, "starty"); + realizable.startingY = atoi(reinterpret_cast(key)); + xmlFree(key); + + key = getProp(top, "startmap"); + realizable.startingMapId = atoi(reinterpret_cast(key)); + xmlFree(key); + + for (xmlNodePtr node = top->xmlChildrenNode; + node != nullptr; + node = node->next) + { + if (!xmlStrcmp(node->name, reinterpret_cast("map"))) + { + id_type map = game_.getEntityManager().emplaceEntity(); + + auto& mappable = game_.getEntityManager(). + emplaceComponent(map, + Texture("res/tiles.png"), + Texture("res/font.bmp")); + + key = getProp(node, "id"); + mappable.mapId = atoi(reinterpret_cast(key)); + xmlFree(key); + + key = getProp(node, "title"); + mappable.title = reinterpret_cast(key); + xmlFree(key); + + for (xmlNodePtr mapNode = node->xmlChildrenNode; + mapNode != nullptr; + mapNode = mapNode->next) + { + if (!xmlStrcmp( + mapNode->name, + reinterpret_cast("environment"))) + { + key = xmlNodeGetContent(mapNode); + if (key == nullptr) + { + throw std::invalid_argument("Error parsing world file"); + } + + mappable.tiles.clear(); + mappable.tiles.push_back(atoi(strtok( + reinterpret_cast(key), + ",\n"))); + + for (size_t i = 1; i < (MAP_WIDTH * MAP_HEIGHT); i++) + { + mappable.tiles.push_back(atoi(strtok(nullptr, ",\n"))); + } + + xmlFree(key); + } else if (!xmlStrcmp( + mapNode->name, + reinterpret_cast("adjacent"))) + { + key = getProp(mapNode, "type"); + std::string adjTypeStr(reinterpret_cast(key)); + xmlFree(key); + + MappableComponent::Adjacent::Type adjType; + if (adjTypeStr == "wall") + { + adjType = MappableComponent::Adjacent::Type::wall; + } else if (adjTypeStr == "wrap") + { + adjType = MappableComponent::Adjacent::Type::wrap; + } else if (adjTypeStr == "warp") + { + adjType = MappableComponent::Adjacent::Type::warp; + } else if (adjTypeStr == "reverseWarp") + { + adjType = MappableComponent::Adjacent::Type::reverse; + } else { + throw std::logic_error("Invalid adjacency type"); + } + + key = getProp(mapNode, "map"); + size_t adjMapId = atoi(reinterpret_cast(key)); + xmlFree(key); + + key = getProp(mapNode, "dir"); + std::string adjDir(reinterpret_cast(key)); + xmlFree(key); + + if (adjDir == "left") + { + mappable.leftAdjacent = {adjType, adjMapId}; + } else if (adjDir == "right") + { + mappable.rightAdjacent = {adjType, adjMapId}; + } else if (adjDir == "up") + { + mappable.upAdjacent = {adjType, adjMapId}; + } else if (adjDir == "down") + { + mappable.downAdjacent = {adjType, adjMapId}; + } else { + throw std::logic_error("Invalid adjacency direction"); + } + } + } + + mapping.generateBoundaries(map); + + realizable.maps.insert(map); + realizable.entityByMapId[mappable.mapId] = map; + } + } + + xmlFreeDoc(doc); + + loadMap(realizable.entityByMapId[realizable.startingMapId]); + + return world; +} + +EntityManager::id_type RealizingSystem::getSingleton() const +{ + std::set result = + game_.getEntityManager().getEntitiesWithComponents< + RealizableComponent>(); + + if (result.empty()) + { + throw std::logic_error("No realizable entity found"); + } else if (result.size() > 1) + { + throw std::logic_error("Multiple realizable entities found"); + } + + return *std::begin(result); +} + +void RealizingSystem::loadMap(id_type mapEntity) +{ + id_type world = getSingleton(); + + auto& realizable = game_.getEntityManager(). + getComponent(world); + + auto& animating = game_.getSystemManager().getSystem(); + auto& pondering = game_.getSystemManager().getSystem(); + + std::set players = + game_.getEntityManager().getEntitiesWithComponents< + PlayableComponent>(); + + if (realizable.hasActiveMap) + { + id_type oldMap = realizable.activeMap; + + auto& oldMappable = game_.getEntityManager(). + getComponent(oldMap); + + // Deactivate any map objects from the old map. + for (id_type prototype : oldMappable.objects) + { + leaveActiveMap(prototype); + } + + // Deactivate players that were on the old map. + for (id_type player : players) + { + auto& playable = game_.getEntityManager(). + getComponent(player); + + if (playable.mapId == oldMap) + { + leaveActiveMap(player); + } + } + } + + realizable.hasActiveMap = true; + realizable.activeMap = mapEntity; + + auto& mappable = game_.getEntityManager(). + getComponent(mapEntity); + + // Initialize the new map's objects. + for (id_type prototype : mappable.objects) + { + if (game_.getEntityManager(). + hasComponent(prototype)) + { + auto& transformable = game_.getEntityManager(). + getComponent(prototype); + + transformable.x = transformable.origX; + transformable.y = transformable.origY; + transformable.w = transformable.origW; + transformable.h = transformable.origH; + } + + if (game_.getEntityManager().hasComponent(prototype)) + { + animating.initPrototype(prototype); + } + + if (game_.getEntityManager().hasComponent(prototype)) + { + pondering.initPrototype(prototype); + } + + enterActiveMap(prototype); + } + + // Activate any players on the map. + for (id_type player : players) + { + auto& playable = game_.getEntityManager(). + getComponent(player); + + if (playable.mapId == mapEntity) + { + enterActiveMap(player); + } + } +} + +void RealizingSystem::enterActiveMap(id_type entity) +{ + if (game_.getEntityManager().hasComponent(entity)) + { + auto& animatable = game_.getEntityManager(). + getComponent(entity); + + animatable.active = true; + } + + if (game_.getEntityManager().hasComponent(entity)) + { + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + ponderable.active = true; + } +} + +void RealizingSystem::leaveActiveMap(id_type entity) +{ + if (game_.getEntityManager().hasComponent(entity)) + { + auto& animatable = game_.getEntityManager(). + getComponent(entity); + + animatable.active = false; + } + + if (game_.getEntityManager().hasComponent(entity)) + { + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + ponderable.active = false; + } +} diff --git a/src/systems/realizing.h b/src/systems/realizing.h new file mode 100644 index 0000000..c681892 --- /dev/null +++ b/src/systems/realizing.h @@ -0,0 +1,43 @@ +#ifndef REALIZING_H_6853748C +#define REALIZING_H_6853748C + +#include "system.h" + +class RealizingSystem : public System { +public: + + RealizingSystem(Game& game) : System(game) + { + } + + /** + * Creates the singleton realizable entity and initializes it with the + * provided world definition. + */ + id_type initSingleton(std::string filename); + + /** + * Helper method that returns the entity ID of the (assumed) singleton entity + * with a RealizableComponent. Throws an exception if the number of realizable + * entities is not exactly one. + */ + id_type getSingleton() const; + + /** + * Loads the given map. + */ + void loadMap(id_type mapEntity); + + /** + * Treats the given entity as part of the active map. + */ + void enterActiveMap(id_type entity); + + /** + * Stops treating the given entity as part of the active map. + */ + void leaveActiveMap(id_type entity); + +}; + +#endif /* end of include guard: REALIZING_H_6853748C */ diff --git a/src/world.cpp b/src/world.cpp deleted file mode 100644 index 3b6bd41..0000000 --- a/src/world.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include "world.h" -#include -#include -#include -#include "consts.h" - -inline xmlChar* getProp(xmlNodePtr node, const char* attr) -{ - xmlChar* key = xmlGetProp(node, reinterpret_cast(attr)); - if (key == nullptr) - { - throw std::invalid_argument("Error parsing world file"); - } - - return key; -} - -World::World(std::string filename) -{ - xmlDocPtr doc = xmlParseFile(filename.c_str()); - if (doc == nullptr) - { - throw std::invalid_argument("Cannot find world file"); - } - - xmlNodePtr top = xmlDocGetRootElement(doc); - if (top == nullptr) - { - throw std::invalid_argument("Error parsing world file"); - } - - if (xmlStrcmp(top->name, reinterpret_cast("world"))) - { - throw std::invalid_argument("Error parsing world file"); - } - - xmlChar* key = nullptr; - - key = getProp(top, "startx"); - startX_ = atoi(reinterpret_cast(key)); - xmlFree(key); - - key = getProp(top, "starty"); - startY_ = atoi(reinterpret_cast(key)); - xmlFree(key); - - key = getProp(top, "startmap"); - startMap_ = atoi(reinterpret_cast(key)); - xmlFree(key); - - for (xmlNodePtr node = top->xmlChildrenNode; - node != nullptr; - node = node->next) - { - if (!xmlStrcmp(node->name, reinterpret_cast("map"))) - { - key = getProp(node, "id"); - size_t mapId = atoi(reinterpret_cast(key)); - xmlFree(key); - - key = getProp(node, "title"); - std::string mapTitle(reinterpret_cast(key)); - xmlFree(key); - - std::vector mapTiles; - Map::Adjacent leftAdj; - Map::Adjacent rightAdj; - Map::Adjacent upAdj; - Map::Adjacent downAdj; - - for (xmlNodePtr mapNode = node->xmlChildrenNode; - mapNode != nullptr; - mapNode = mapNode->next) - { - if (!xmlStrcmp( - mapNode->name, - reinterpret_cast("environment"))) - { - key = xmlNodeGetContent(mapNode); - - mapTiles.clear(); - mapTiles.push_back(atoi(strtok(reinterpret_cast(key), ",\n"))); - for (size_t i = 1; i < (MAP_WIDTH * MAP_HEIGHT); i++) - { - mapTiles.push_back(atoi(strtok(nullptr, ",\n"))); - } - - xmlFree(key); - } else if (!xmlStrcmp( - mapNode->name, - reinterpret_cast("adjacent"))) - { - key = getProp(mapNode, "type"); - std::string adjTypeStr(reinterpret_cast(key)); - xmlFree(key); - - Map::Adjacent::Type adjType; - if (adjTypeStr == "wall") - { - adjType = Map::Adjacent::Type::wall; - } else if (adjTypeStr == "wrap") - { - adjType = Map::Adjacent::Type::wrap; - } else if (adjTypeStr == "warp") - { - adjType = Map::Adjacent::Type::warp; - } else if (adjTypeStr == "reverseWarp") - { - adjType = Map::Adjacent::Type::reverse; - } else { - throw std::logic_error("Invalid adjacency type"); - } - - key = getProp(mapNode, "map"); - int adjMapId = atoi(reinterpret_cast(key)); - xmlFree(key); - - key = getProp(mapNode, "dir"); - std::string adjDir(reinterpret_cast(key)); - xmlFree(key); - - if (adjDir == "left") - { - leftAdj = {adjType, adjMapId}; - } else if (adjDir == "right") - { - rightAdj = {adjType, adjMapId}; - } else if (adjDir == "up") - { - upAdj = {adjType, adjMapId}; - } else if (adjDir == "down") - { - downAdj = {adjType, adjMapId}; - } else { - throw std::logic_error("Invalid adjacency direction"); - } - } - } - - maps_.emplace( - std::piecewise_construct, - std::forward_as_tuple(mapId), - std::forward_as_tuple( - mapId, - std::move(mapTiles), - std::move(mapTitle), - leftAdj, - rightAdj, - upAdj, - downAdj)); - } - } - - xmlFreeDoc(doc); -} diff --git a/src/world.h b/src/world.h deleted file mode 100644 index b88adf4..0000000 --- a/src/world.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef WORLD_H_153C698B -#define WORLD_H_153C698B - -#include -#include -#include "map.h" - -class World { -public: - - explicit World(std::string filename); - - inline const Map& getMap(size_t id) const - { - return maps_.at(id); - } - - inline size_t getStartingMapId() const - { - return startMap_; - } - - inline int getStartingX() const - { - return startX_; - } - - inline int getStartingY() const - { - return startY_; - } - -private: - - std::map maps_; - size_t startMap_; - int startX_; - int startY_; -}; - -#endif /* end of include guard: WORLD_H_153C698B */ -- cgit 1.4.1 From d0f191b3b7419f846342ea5eba5a9bb69cf9bb14 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sat, 28 Apr 2018 13:52:47 -0400 Subject: Moved stb_image.h to a vendor folder --- CMakeLists.txt | 2 + src/renderer/renderer.cpp | 9 +- src/renderer/texture.cpp | 6 +- src/stb_image.h | 6326 --------------------------------------------- vendor/stb_image.cpp | 4 + vendor/stb_image.h | 6326 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 6335 insertions(+), 6338 deletions(-) delete mode 100644 src/stb_image.h create mode 100644 vendor/stb_image.cpp create mode 100644 vendor/stb_image.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 81365c9..49a0384 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,7 @@ include_directories( ${OPENGL_INCLUDE_DIRS} ${GLEW_INCLUDE_DIRS} src + vendor ) link_directories( @@ -67,6 +68,7 @@ add_executable(Aromatherapy src/systems/playing.cpp src/systems/scheduling.cpp src/systems/realizing.cpp + vendor/stb_image.cpp ) set_property(TARGET Aromatherapy PROPERTY CXX_STANDARD 11) diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index 6eef2f3..30ef787 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -1,15 +1,10 @@ #include "renderer.h" +#include +#include #include "consts.h" #include "game.h" -#include #include "texture.h" -// include stb_image -#define STB_IMAGE_IMPLEMENTATION -#define STBI_ONLY_PNG -#define STBI_ONLY_BMP -#include "stb_image.h" - void setFramebufferSize(GLFWwindow* w, int width, int height) { Game& game = *static_cast(glfwGetWindowUserPointer(w)); diff --git a/src/renderer/texture.cpp b/src/renderer/texture.cpp index 2728665..04d5cf4 100644 --- a/src/renderer/texture.cpp +++ b/src/renderer/texture.cpp @@ -1,13 +1,9 @@ #include "texture.h" #include +#include #include "renderer.h" #include "util.h" -// include stb_image -#define STBI_ONLY_PNG -#define STBI_ONLY_BMP -#include "stb_image.h" - Texture::Texture( int width, int height) : diff --git a/src/stb_image.h b/src/stb_image.h deleted file mode 100644 index cea66f5..0000000 --- a/src/stb_image.h +++ /dev/null @@ -1,6326 +0,0 @@ -/* stb_image - v2.02 - public domain image loader - http://nothings.org/stb_image.h - no warranty implied; use at your own risk - - Do this: - #define STB_IMAGE_IMPLEMENTATION - before you include this file in *one* C or C++ file to create the implementation. - - // i.e. it should look like this: - #include ... - #include ... - #include ... - #define STB_IMAGE_IMPLEMENTATION - #include "stb_image.h" - - You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. - And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free - - - QUICK NOTES: - Primarily of interest to game developers and other people who can - avoid problematic images and only need the trivial interface - - JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) - PNG 1/2/4/8-bit-per-channel (16 bpc not supported) - - TGA (not sure what subset, if a subset) - BMP non-1bpp, non-RLE - PSD (composited view only, no extra channels) - - GIF (*comp always reports as 4-channel) - HDR (radiance rgbE format) - PIC (Softimage PIC) - PNM (PPM and PGM binary only) - - - decode from memory or through FILE (define STBI_NO_STDIO to remove code) - - decode from arbitrary I/O callbacks - - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) - - Full documentation under "DOCUMENTATION" below. - - - Revision 2.00 release notes: - - - Progressive JPEG is now supported. - - - PPM and PGM binary formats are now supported, thanks to Ken Miller. - - - x86 platforms now make use of SSE2 SIMD instructions for - JPEG decoding, and ARM platforms can use NEON SIMD if requested. - This work was done by Fabian "ryg" Giesen. SSE2 is used by - default, but NEON must be enabled explicitly; see docs. - - With other JPEG optimizations included in this version, we see - 2x speedup on a JPEG on an x86 machine, and a 1.5x speedup - on a JPEG on an ARM machine, relative to previous versions of this - library. The same results will not obtain for all JPGs and for all - x86/ARM machines. (Note that progressive JPEGs are significantly - slower to decode than regular JPEGs.) This doesn't mean that this - is the fastest JPEG decoder in the land; rather, it brings it - closer to parity with standard libraries. If you want the fastest - decode, look elsewhere. (See "Philosophy" section of docs below.) - - See final bullet items below for more info on SIMD. - - - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing - the memory allocator. Unlike other STBI libraries, these macros don't - support a context parameter, so if you need to pass a context in to - the allocator, you'll have to store it in a global or a thread-local - variable. - - - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and - STBI_NO_LINEAR. - STBI_NO_HDR: suppress implementation of .hdr reader format - STBI_NO_LINEAR: suppress high-dynamic-range light-linear float API - - - You can suppress implementation of any of the decoders to reduce - your code footprint by #defining one or more of the following - symbols before creating the implementation. - - STBI_NO_JPEG - STBI_NO_PNG - STBI_NO_BMP - STBI_NO_PSD - STBI_NO_TGA - STBI_NO_GIF - STBI_NO_HDR - STBI_NO_PIC - STBI_NO_PNM (.ppm and .pgm) - - - You can request *only* certain decoders and suppress all other ones - (this will be more forward-compatible, as addition of new decoders - doesn't require you to disable them explicitly): - - STBI_ONLY_JPEG - STBI_ONLY_PNG - STBI_ONLY_BMP - STBI_ONLY_PSD - STBI_ONLY_TGA - STBI_ONLY_GIF - STBI_ONLY_HDR - STBI_ONLY_PIC - STBI_ONLY_PNM (.ppm and .pgm) - - Note that you can define multiples of these, and you will get all - of them ("only x" and "only y" is interpreted to mean "only x&y"). - - - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still - want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB - - - Compilation of all SIMD code can be suppressed with - #define STBI_NO_SIMD - It should not be necessary to disable SIMD unless you have issues - compiling (e.g. using an x86 compiler which doesn't support SSE - intrinsics or that doesn't support the method used to detect - SSE2 support at run-time), and even those can be reported as - bugs so I can refine the built-in compile-time checking to be - smarter. - - - The old STBI_SIMD system which allowed installing a user-defined - IDCT etc. has been removed. If you need this, don't upgrade. My - assumption is that almost nobody was doing this, and those who - were will find the built-in SIMD more satisfactory anyway. - - - RGB values computed for JPEG images are slightly different from - previous versions of stb_image. (This is due to using less - integer precision in SIMD.) The C code has been adjusted so - that the same RGB values will be computed regardless of whether - SIMD support is available, so your app should always produce - consistent results. But these results are slightly different from - previous versions. (Specifically, about 3% of available YCbCr values - will compute different RGB results from pre-1.49 versions by +-1; - most of the deviating values are one smaller in the G channel.) - - - If you must produce consistent results with previous versions of - stb_image, #define STBI_JPEG_OLD and you will get the same results - you used to; however, you will not get the SIMD speedups for - the YCbCr-to-RGB conversion step (although you should still see - significant JPEG speedup from the other changes). - - Please note that STBI_JPEG_OLD is a temporary feature; it will be - removed in future versions of the library. It is only intended for - near-term back-compatibility use. - - - Latest revision history: - 2.02 (2015-01-19) fix incorrect assert, fix warning - 2.01 (2015-01-17) fix various warnings - 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG - 2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD - progressive JPEG - PGM/PPM support - STBI_MALLOC,STBI_REALLOC,STBI_FREE - STBI_NO_*, STBI_ONLY_* - GIF bugfix - 1.48 (2014-12-14) fix incorrectly-named assert() - 1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted) - optimize PNG - fix bug in interlaced PNG with user-specified channel count - 1.46 (2014-08-26) fix broken tRNS chunk in non-paletted PNG - 1.45 (2014-08-16) workaround MSVC-ARM internal compiler error by wrapping malloc - - See end of file for full revision history. - - - ============================ Contributors ========================= - - Image formats Bug fixes & warning fixes - Sean Barrett (jpeg, png, bmp) Marc LeBlanc - Nicolas Schulz (hdr, psd) Christpher Lloyd - Jonathan Dummer (tga) Dave Moore - Jean-Marc Lienher (gif) Won Chun - Tom Seddon (pic) the Horde3D community - Thatcher Ulrich (psd) Janez Zemva - Ken Miller (pgm, ppm) Jonathan Blow - Laurent Gomila - Aruelien Pocheville - Extensions, features Ryamond Barbiero - Jetro Lauha (stbi_info) David Woo - Martin "SpartanJ" Golini (stbi_info) Martin Golini - James "moose2000" Brown (iPhone PNG) Roy Eltham - Ben "Disch" Wenger (io callbacks) Luke Graham - Omar Cornut (1/2/4-bit PNG) Thomas Ruf - John Bartholomew - Ken Hamada - Optimizations & bugfixes Cort Stratton - Fabian "ryg" Giesen Blazej Dariusz Roszkowski - Arseny Kapoulkine Thibault Reuille - Paul Du Bois - Guillaume George - If your name should be here but Jerry Jansson - isn't, let Sean know. Hayaki Saito - Johan Duparc - Ronny Chevalier - Michal Cichon - Tero Hanninen - Sergio Gonzalez - Cass Everitt - Engin Manap - -License: - This software is in the public domain. Where that dedication is not - recognized, you are granted a perpetual, irrevocable license to copy - and modify this file however you want. - -*/ - -#ifndef STBI_INCLUDE_STB_IMAGE_H -#define STBI_INCLUDE_STB_IMAGE_H - -// DOCUMENTATION -// -// Limitations: -// - no 16-bit-per-channel PNG -// - no 12-bit-per-channel JPEG -// - no JPEGs with arithmetic coding -// - no 1-bit BMP -// - GIF always returns *comp=4 -// -// Basic usage (see HDR discussion below for HDR usage): -// int x,y,n; -// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); -// // ... process data if not NULL ... -// // ... x = width, y = height, n = # 8-bit components per pixel ... -// // ... replace '0' with '1'..'4' to force that many components per pixel -// // ... but 'n' will always be the number that it would have been if you said 0 -// stbi_image_free(data) -// -// Standard parameters: -// int *x -- outputs image width in pixels -// int *y -- outputs image height in pixels -// int *comp -- outputs # of image components in image file -// int req_comp -- if non-zero, # of image components requested in result -// -// The return value from an image loader is an 'unsigned char *' which points -// to the pixel data, or NULL on an allocation failure or if the image is -// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, -// with each pixel consisting of N interleaved 8-bit components; the first -// pixel pointed to is top-left-most in the image. There is no padding between -// image scanlines or between pixels, regardless of format. The number of -// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. -// If req_comp is non-zero, *comp has the number of components that _would_ -// have been output otherwise. E.g. if you set req_comp to 4, you will always -// get RGBA output, but you can check *comp to see if it's trivially opaque -// because e.g. there were only 3 channels in the source image. -// -// An output image with N components has the following components interleaved -// in this order in each pixel: -// -// N=#comp components -// 1 grey -// 2 grey, alpha -// 3 red, green, blue -// 4 red, green, blue, alpha -// -// If image loading fails for any reason, the return value will be NULL, -// and *x, *y, *comp will be unchanged. The function stbi_failure_reason() -// can be queried for an extremely brief, end-user unfriendly explanation -// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid -// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly -// more user-friendly ones. -// -// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. -// -// =========================================================================== -// -// Philosophy -// -// stb libraries are designed with the following priorities: -// -// 1. easy to use -// 2. easy to maintain -// 3. good performance -// -// Sometimes I let "good performance" creep up in priority over "easy to maintain", -// and for best performance I may provide less-easy-to-use APIs that give higher -// performance, in addition to the easy to use ones. Nevertheless, it's important -// to keep in mind that from the standpoint of you, a client of this library, -// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all. -// -// Some secondary priorities arise directly from the first two, some of which -// make more explicit reasons why performance can't be emphasized. -// -// - Portable ("ease of use") -// - Small footprint ("easy to maintain") -// - No dependencies ("ease of use") -// -// =========================================================================== -// -// I/O callbacks -// -// I/O callbacks allow you to read from arbitrary sources, like packaged -// files or some other source. Data read from callbacks are processed -// through a small internal buffer (currently 128 bytes) to try to reduce -// overhead. -// -// The three functions you must define are "read" (reads some bytes of data), -// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). -// -// =========================================================================== -// -// SIMD support -// -// The JPEG decoder will try to automatically use SIMD kernels on x86 when -// supported by the compiler. For ARM Neon support, you must explicitly -// request it. -// -// (The old do-it-yourself SIMD API is no longer supported in the current -// code.) -// -// On x86, SSE2 will automatically be used when available based on a run-time -// test; if not, the generic C versions are used as a fall-back. On ARM targets, -// the typical path is to have separate builds for NEON and non-NEON devices -// (at least this is true for iOS and Android). Therefore, the NEON support is -// toggled by a build flag: define STBI_NEON to get NEON loops. -// -// The output of the JPEG decoder is slightly different from versions where -// SIMD support was introduced (that is, for versions before 1.49). The -// difference is only +-1 in the 8-bit RGB channels, and only on a small -// fraction of pixels. You can force the pre-1.49 behavior by defining -// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path -// and hence cost some performance. -// -// If for some reason you do not want to use any of SIMD code, or if -// you have issues compiling it, you can disable it entirely by -// defining STBI_NO_SIMD. -// -// =========================================================================== -// -// HDR image support (disable by defining STBI_NO_HDR) -// -// stb_image now supports loading HDR images in general, and currently -// the Radiance .HDR file format, although the support is provided -// generically. You can still load any file through the existing interface; -// if you attempt to load an HDR file, it will be automatically remapped to -// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; -// both of these constants can be reconfigured through this interface: -// -// stbi_hdr_to_ldr_gamma(2.2f); -// stbi_hdr_to_ldr_scale(1.0f); -// -// (note, do not use _inverse_ constants; stbi_image will invert them -// appropriately). -// -// Additionally, there is a new, parallel interface for loading files as -// (linear) floats to preserve the full dynamic range: -// -// float *data = stbi_loadf(filename, &x, &y, &n, 0); -// -// If you load LDR images through this interface, those images will -// be promoted to floating point values, run through the inverse of -// constants corresponding to the above: -// -// stbi_ldr_to_hdr_scale(1.0f); -// stbi_ldr_to_hdr_gamma(2.2f); -// -// Finally, given a filename (or an open file or memory block--see header -// file for details) containing image data, you can query for the "most -// appropriate" interface to use (that is, whether the image is HDR or -// not), using: -// -// stbi_is_hdr(char *filename); -// -// =========================================================================== -// -// iPhone PNG support: -// -// By default we convert iphone-formatted PNGs back to RGB, even though -// they are internally encoded differently. You can disable this conversion -// by by calling stbi_convert_iphone_png_to_rgb(0), in which case -// you will always just get the native iphone "format" through (which -// is BGR stored in RGB). -// -// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per -// pixel to remove any premultiplied alpha *only* if the image file explicitly -// says there's premultiplied data (currently only happens in iPhone images, -// and only if iPhone convert-to-rgb processing is on). -// - - -#ifndef STBI_NO_STDIO -#include -#endif // STBI_NO_STDIO - -#define STBI_VERSION 1 - -enum -{ - STBI_default = 0, // only used for req_comp - - STBI_grey = 1, - STBI_grey_alpha = 2, - STBI_rgb = 3, - STBI_rgb_alpha = 4 -}; - -typedef unsigned char stbi_uc; - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef STB_IMAGE_STATIC -#define STBIDEF static -#else -#define STBIDEF extern -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// PRIMARY API - works on images of any type -// - -// -// load image by filename, open file, or memory buffer -// - -typedef struct -{ - int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read - void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative - int (*eof) (void *user); // returns nonzero if we are at end of file/data -} stbi_io_callbacks; - -STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); -STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *comp, int req_comp); -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *comp, int req_comp); - -#ifndef STBI_NO_STDIO -STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); -// for stbi_load_from_file, file pointer is left pointing immediately after image -#endif - -#ifndef STBI_NO_LINEAR - STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); - STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); - STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); - - #ifndef STBI_NO_STDIO - STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); - #endif -#endif - -#ifndef STBI_NO_HDR - STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); - STBIDEF void stbi_hdr_to_ldr_scale(float scale); -#endif - -#ifndef STBI_NO_LINEAR - STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); - STBIDEF void stbi_ldr_to_hdr_scale(float scale); -#endif // STBI_NO_HDR - -// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); -#ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename); -STBIDEF int stbi_is_hdr_from_file(FILE *f); -#endif // STBI_NO_STDIO - - -// get a VERY brief reason for failure -// NOT THREADSAFE -STBIDEF const char *stbi_failure_reason (void); - -// free the loaded image -- this is just free() -STBIDEF void stbi_image_free (void *retval_from_stbi_load); - -// get image dimensions & components without fully decoding -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); - -#endif - - - -// for image formats that explicitly notate that they have premultiplied alpha, -// we just return the colors as stored in the file. set this flag to force -// unpremultiplication. results are undefined if the unpremultiply overflow. -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); - -// indicate whether we should process iphone images back to canonical format, -// or just pass them through "as-is" -STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); - - -// ZLIB client - used by PNG, available for other purposes - -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); -STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - -STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - - -#ifdef __cplusplus -} -#endif - -// -// -//// end header file ///////////////////////////////////////////////////// -#endif // STBI_INCLUDE_STB_IMAGE_H - -#ifdef STB_IMAGE_IMPLEMENTATION - -#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ - || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ - || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ - || defined(STBI_ONLY_ZLIB) - #ifndef STBI_ONLY_JPEG - #define STBI_NO_JPEG - #endif - #ifndef STBI_ONLY_PNG - #define STBI_NO_PNG - #endif - #ifndef STBI_ONLY_BMP - #define STBI_NO_BMP - #endif - #ifndef STBI_ONLY_PSD - #define STBI_NO_PSD - #endif - #ifndef STBI_ONLY_TGA - #define STBI_NO_TGA - #endif - #ifndef STBI_ONLY_GIF - #define STBI_NO_GIF - #endif - #ifndef STBI_ONLY_HDR - #define STBI_NO_HDR - #endif - #ifndef STBI_ONLY_PIC - #define STBI_NO_PIC - #endif - #ifndef STBI_ONLY_PNM - #define STBI_NO_PNM - #endif -#endif - -#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) -#define STBI_NO_ZLIB -#endif - - -#include -#include // ptrdiff_t on osx -#include -#include - -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -#include // ldexp -#endif - -#ifndef STBI_NO_STDIO -#include -#endif - -#ifndef STBI_ASSERT -#include -#define STBI_ASSERT(x) assert(x) -#endif - - -#ifndef _MSC_VER - #ifdef __cplusplus - #define stbi_inline inline - #else - #define stbi_inline - #endif -#else - #define stbi_inline __forceinline -#endif - - -#ifdef _MSC_VER -typedef unsigned short stbi__uint16; -typedef signed short stbi__int16; -typedef unsigned int stbi__uint32; -typedef signed int stbi__int32; -#else -#include -typedef uint16_t stbi__uint16; -typedef int16_t stbi__int16; -typedef uint32_t stbi__uint32; -typedef int32_t stbi__int32; -#endif - -// should produce compiler error if size is wrong -typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; - -#ifdef _MSC_VER -#define STBI_NOTUSED(v) (void)(v) -#else -#define STBI_NOTUSED(v) (void)sizeof(v) -#endif - -#ifdef _MSC_VER -#define STBI_HAS_LROTL -#endif - -#ifdef STBI_HAS_LROTL - #define stbi_lrot(x,y) _lrotl(x,y) -#else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) -#endif - -#if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC) -// ok -#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) -// ok -#else -#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC." -#endif - -#ifndef STBI_MALLOC -#define STBI_MALLOC(sz) malloc(sz) -#define STBI_REALLOC(p,sz) realloc(p,sz) -#define STBI_FREE(p) free(p) -#endif - -#if defined(__GNUC__) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) -// gcc doesn't support sse2 intrinsics unless you compile with -msse2, -// (but compiling with -msse2 allows the compiler to use SSE2 everywhere; -// this is just broken and gcc are jerks for not fixing it properly -// http://www.virtualdub.org/blog/pivot/entry.php?id=363 ) -#define STBI_NO_SIMD -#endif - -#if !defined(STBI_NO_SIMD) && (defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)) -#define STBI_SSE2 -#include - -#ifdef _MSC_VER - -#if _MSC_VER >= 1400 // not VC6 -#include // __cpuid -static int stbi__cpuid3(void) -{ - int info[4]; - __cpuid(info,1); - return info[3]; -} -#else -static int stbi__cpuid3(void) -{ - int res; - __asm { - mov eax,1 - cpuid - mov res,edx - } - return res; -} -#endif - -#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name - -static int stbi__sse2_available() -{ - int info3 = stbi__cpuid3(); - return ((info3 >> 26) & 1) != 0; -} -#else // assume GCC-style if not VC++ -#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) - -static int stbi__sse2_available() -{ -#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later - // GCC 4.8+ has a nice way to do this - return __builtin_cpu_supports("sse2"); -#else - // portable way to do this, preferably without using GCC inline ASM? - // just bail for now. - return 0; -#endif -} -#endif -#endif - -// ARM NEON -#if defined(STBI_NO_SIMD) && defined(STBI_NEON) -#undef STBI_NEON -#endif - -#ifdef STBI_NEON -#include -// assume GCC or Clang on ARM targets -#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) -#endif - -#ifndef STBI_SIMD_ALIGN -#define STBI_SIMD_ALIGN(type, name) type name -#endif - -/////////////////////////////////////////////// -// -// stbi__context struct and start_xxx functions - -// stbi__context structure is our basic context used by all images, so it -// contains all the IO context, plus some basic image information -typedef struct -{ - stbi__uint32 img_x, img_y; - int img_n, img_out_n; - - stbi_io_callbacks io; - void *io_user_data; - - int read_from_callbacks; - int buflen; - stbi_uc buffer_start[128]; - - stbi_uc *img_buffer, *img_buffer_end; - stbi_uc *img_buffer_original; -} stbi__context; - - -static void stbi__refill_buffer(stbi__context *s); - -// initialize a memory-decode context -static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) -{ - s->io.read = NULL; - s->read_from_callbacks = 0; - s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; - s->img_buffer_end = (stbi_uc *) buffer+len; -} - -// initialize a callback-based context -static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) -{ - s->io = *c; - s->io_user_data = user; - s->buflen = sizeof(s->buffer_start); - s->read_from_callbacks = 1; - s->img_buffer_original = s->buffer_start; - stbi__refill_buffer(s); -} - -#ifndef STBI_NO_STDIO - -static int stbi__stdio_read(void *user, char *data, int size) -{ - return (int) fread(data,1,size,(FILE*) user); -} - -static void stbi__stdio_skip(void *user, int n) -{ - fseek((FILE*) user, n, SEEK_CUR); -} - -static int stbi__stdio_eof(void *user) -{ - return feof((FILE*) user); -} - -static stbi_io_callbacks stbi__stdio_callbacks = -{ - stbi__stdio_read, - stbi__stdio_skip, - stbi__stdio_eof, -}; - -static void stbi__start_file(stbi__context *s, FILE *f) -{ - stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); -} - -//static void stop_file(stbi__context *s) { } - -#endif // !STBI_NO_STDIO - -static void stbi__rewind(stbi__context *s) -{ - // conceptually rewind SHOULD rewind to the beginning of the stream, - // but we just rewind to the beginning of the initial buffer, because - // we only use it after doing 'test', which only ever looks at at most 92 bytes - s->img_buffer = s->img_buffer_original; -} - -#ifndef STBI_NO_JPEG -static int stbi__jpeg_test(stbi__context *s); -static stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PNG -static int stbi__png_test(stbi__context *s); -static stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_BMP -static int stbi__bmp_test(stbi__context *s); -static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_TGA -static int stbi__tga_test(stbi__context *s); -static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s); -static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_HDR -static int stbi__hdr_test(stbi__context *s); -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PIC -static int stbi__pic_test(stbi__context *s); -static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_GIF -static int stbi__gif_test(stbi__context *s); -static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PNM -static int stbi__pnm_test(stbi__context *s); -static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -// this is not threadsafe -static const char *stbi__g_failure_reason; - -STBIDEF const char *stbi_failure_reason(void) -{ - return stbi__g_failure_reason; -} - -static int stbi__err(const char *str) -{ - stbi__g_failure_reason = str; - return 0; -} - -static void *stbi__malloc(size_t size) -{ - return STBI_MALLOC(size); -} - -// stbi__err - error -// stbi__errpf - error returning pointer to float -// stbi__errpuc - error returning pointer to unsigned char - -#ifdef STBI_NO_FAILURE_STRINGS - #define stbi__err(x,y) 0 -#elif defined(STBI_FAILURE_USERMSG) - #define stbi__err(x,y) stbi__err(y) -#else - #define stbi__err(x,y) stbi__err(x) -#endif - -#define stbi__errpf(x,y) ((float *) (stbi__err(x,y)?NULL:NULL)) -#define stbi__errpuc(x,y) ((unsigned char *) (stbi__err(x,y)?NULL:NULL)) - -STBIDEF void stbi_image_free(void *retval_from_stbi_load) -{ - STBI_FREE(retval_from_stbi_load); -} - -#ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); -#endif - -#ifndef STBI_NO_HDR -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); -#endif - -static unsigned char *stbi_load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_PNG - if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_BMP - if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_GIF - if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_PSD - if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_PIC - if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_PNM - if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp); - #endif - - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - float *hdr = stbi__hdr_load(s, x,y,comp,req_comp); - return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); - } - #endif - - #ifndef STBI_NO_TGA - // test tga last because it's a crappy test! - if (stbi__tga_test(s)) - return stbi__tga_load(s,x,y,comp,req_comp); - #endif - - return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); -} - -#ifndef STBI_NO_STDIO - -static FILE *stbi__fopen(char const *filename, char const *mode) -{ - FILE *f; -#if defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != fopen_s(&f, filename, mode)) - f=0; -#else - f = fopen(filename, mode); -#endif - return f; -} - - -STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - unsigned char *result; - if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; -} - -STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi_load_main(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; -} -#endif //!STBI_NO_STDIO - -STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi_load_main(&s,x,y,comp,req_comp); -} - -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi_load_main(&s,x,y,comp,req_comp); -} - -#ifndef STBI_NO_LINEAR -static float *stbi_loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *data; - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) - return stbi__hdr_load(s,x,y,comp,req_comp); - #endif - data = stbi_load_main(s, x, y, comp, req_comp); - if (data) - return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); - return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); -} - -STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi_loadf_main(&s,x,y,comp,req_comp); -} - -STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi_loadf_main(&s,x,y,comp,req_comp); -} - -#ifndef STBI_NO_STDIO -STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - float *result; - FILE *f = stbi__fopen(filename, "rb"); - if (!f) return stbi__errpf("can't fopen", "Unable to open file"); - result = stbi_loadf_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; -} - -STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_file(&s,f); - return stbi_loadf_main(&s,x,y,comp,req_comp); -} -#endif // !STBI_NO_STDIO - -#endif // !STBI_NO_LINEAR - -// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is -// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always -// reports false! - -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(buffer); - STBI_NOTUSED(len); - return 0; - #endif -} - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result=0; - if (f) { - result = stbi_is_hdr_from_file(f); - fclose(f); - } - return result; -} - -STBIDEF int stbi_is_hdr_from_file(FILE *f) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_file(&s,f); - return stbi__hdr_test(&s); - #else - return 0; - #endif -} -#endif // !STBI_NO_STDIO - -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__hdr_test(&s); - #else - return 0; - #endif -} - -static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; -static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; - -#ifndef STBI_NO_LINEAR -STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } -STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } -#endif - -STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } -STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } - - -////////////////////////////////////////////////////////////////////////////// -// -// Common code used by all image loaders -// - -enum -{ - STBI__SCAN_load=0, - STBI__SCAN_type, - STBI__SCAN_header -}; - -static void stbi__refill_buffer(stbi__context *s) -{ - int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); - if (n == 0) { - // at end of file, treat same as if from memory, but need to handle case - // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file - s->read_from_callbacks = 0; - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start+1; - *s->img_buffer = 0; - } else { - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start + n; - } -} - -stbi_inline static stbi_uc stbi__get8(stbi__context *s) -{ - if (s->img_buffer < s->img_buffer_end) - return *s->img_buffer++; - if (s->read_from_callbacks) { - stbi__refill_buffer(s); - return *s->img_buffer++; - } - return 0; -} - -stbi_inline static int stbi__at_eof(stbi__context *s) -{ - if (s->io.read) { - if (!(s->io.eof)(s->io_user_data)) return 0; - // if feof() is true, check if buffer = end - // special case: we've only got the special 0 character at the end - if (s->read_from_callbacks == 0) return 1; - } - - return s->img_buffer >= s->img_buffer_end; -} - -static void stbi__skip(stbi__context *s, int n) -{ - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - s->img_buffer = s->img_buffer_end; - (s->io.skip)(s->io_user_data, n - blen); - return; - } - } - s->img_buffer += n; -} - -static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) -{ - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - int res, count; - - memcpy(buffer, s->img_buffer, blen); - - count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); - res = (count == (n-blen)); - s->img_buffer = s->img_buffer_end; - return res; - } - } - - if (s->img_buffer+n <= s->img_buffer_end) { - memcpy(buffer, s->img_buffer, n); - s->img_buffer += n; - return 1; - } else - return 0; -} - -static int stbi__get16be(stbi__context *s) -{ - int z = stbi__get8(s); - return (z << 8) + stbi__get8(s); -} - -static stbi__uint32 stbi__get32be(stbi__context *s) -{ - stbi__uint32 z = stbi__get16be(s); - return (z << 16) + stbi__get16be(s); -} - -static int stbi__get16le(stbi__context *s) -{ - int z = stbi__get8(s); - return z + (stbi__get8(s) << 8); -} - -static stbi__uint32 stbi__get32le(stbi__context *s) -{ - stbi__uint32 z = stbi__get16le(s); - return z + (stbi__get16le(s) << 16); -} - -#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings - - -////////////////////////////////////////////////////////////////////////////// -// -// generic converter from built-in img_n to req_comp -// individual types do this automatically as much as possible (e.g. jpeg -// does all cases internally since it needs to colorspace convert anyway, -// and it never has alpha, so very few cases ). png can automatically -// interleave an alpha=255 channel, but falls back to this for other cases -// -// assume data buffer is malloced, so malloc a new one and free that one -// only failure mode is malloc failing - -static stbi_uc stbi__compute_y(int r, int g, int b) -{ - return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); -} - -static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - unsigned char *good; - - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - - good = (unsigned char *) stbi__malloc(req_comp * x * y); - if (good == NULL) { - STBI_FREE(data); - return stbi__errpuc("outofmem", "Out of memory"); - } - - for (j=0; j < (int) y; ++j) { - unsigned char *src = data + j * x * img_n ; - unsigned char *dest = good + j * x * req_comp; - - #define COMBO(a,b) ((a)*8+(b)) - #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (COMBO(img_n, req_comp)) { - CASE(1,2) dest[0]=src[0], dest[1]=255; break; - CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; - CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; - CASE(2,1) dest[0]=src[0]; break; - CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; - CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; - CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; - CASE(3,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; - CASE(3,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; break; - CASE(4,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; - CASE(4,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; - CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; - default: STBI_ASSERT(0); - } - #undef CASE - } - - STBI_FREE(data); - return good; -} - -#ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) -{ - int i,k,n; - float *output = (float *) stbi__malloc(x * y * comp * sizeof(float)); - if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); - } - if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; - } - STBI_FREE(data); - return output; -} -#endif - -#ifndef STBI_NO_HDR -#define stbi__float2int(x) ((int) (x)) -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) -{ - int i,k,n; - stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp); - if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - if (k < comp) { - float z = data[i*comp+k] * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - } - STBI_FREE(data); - return output; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// "baseline" JPEG/JFIF decoder -// -// simple implementation -// - doesn't support delayed output of y-dimension -// - simple interface (only one output format: 8-bit interleaved RGB) -// - doesn't try to recover corrupt jpegs -// - doesn't allow partial loading, loading multiple at once -// - still fast on x86 (copying globals into locals doesn't help x86) -// - allocates lots of intermediate memory (full size of all components) -// - non-interleaved case requires this anyway -// - allows good upsampling (see next) -// high-quality -// - upsampled channels are bilinearly interpolated, even across blocks -// - quality integer IDCT derived from IJG's 'slow' -// performance -// - fast huffman; reasonable integer IDCT -// - some SIMD kernels for common paths on targets with SSE2/NEON -// - uses a lot of intermediate memory, could cache poorly - -#ifndef STBI_NO_JPEG - -// huffman decoding acceleration -#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache - -typedef struct -{ - stbi_uc fast[1 << FAST_BITS]; - // weirdly, repacking this into AoS is a 10% speed loss, instead of a win - stbi__uint16 code[256]; - stbi_uc values[256]; - stbi_uc size[257]; - unsigned int maxcode[18]; - int delta[17]; // old 'firstsymbol' - old 'firstcode' -} stbi__huffman; - -typedef struct -{ - stbi__context *s; - stbi__huffman huff_dc[4]; - stbi__huffman huff_ac[4]; - stbi_uc dequant[4][64]; - stbi__int16 fast_ac[4][1 << FAST_BITS]; - -// sizes for components, interleaved MCUs - int img_h_max, img_v_max; - int img_mcu_x, img_mcu_y; - int img_mcu_w, img_mcu_h; - -// definition of jpeg image component - struct - { - int id; - int h,v; - int tq; - int hd,ha; - int dc_pred; - - int x,y,w2,h2; - stbi_uc *data; - void *raw_data, *raw_coeff; - stbi_uc *linebuf; - short *coeff; // progressive only - int coeff_w, coeff_h; // number of 8x8 coefficient blocks - } img_comp[4]; - - stbi__uint32 code_buffer; // jpeg entropy-coded buffer - int code_bits; // number of valid bits - unsigned char marker; // marker seen while filling entropy buffer - int nomore; // flag if we saw a marker so must stop - - int progressive; - int spec_start; - int spec_end; - int succ_high; - int succ_low; - int eob_run; - - int scan_n, order[4]; - int restart_interval, todo; - -// kernels - void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); - void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); - stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); -} stbi__jpeg; - -static int stbi__build_huffman(stbi__huffman *h, int *count) -{ - int i,j,k=0,code; - // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) - h->size[k++] = (stbi_uc) (i+1); - h->size[k] = 0; - - // compute actual symbols (from jpeg spec) - code = 0; - k = 0; - for(j=1; j <= 16; ++j) { - // compute delta to add to code to compute symbol id - h->delta[j] = k - code; - if (h->size[k] == j) { - while (h->size[k] == j) - h->code[k++] = (stbi__uint16) (code++); - if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG"); - } - // compute largest code + 1 for this size, preshifted as needed later - h->maxcode[j] = code << (16-j); - code <<= 1; - } - h->maxcode[j] = 0xffffffff; - - // build non-spec acceleration table; 255 is flag for not-accelerated - memset(h->fast, 255, 1 << FAST_BITS); - for (i=0; i < k; ++i) { - int s = h->size[i]; - if (s <= FAST_BITS) { - int c = h->code[i] << (FAST_BITS-s); - int m = 1 << (FAST_BITS-s); - for (j=0; j < m; ++j) { - h->fast[c+j] = (stbi_uc) i; - } - } - } - return 1; -} - -// build a table that decodes both magnitude and value of small ACs in -// one go. -static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) -{ - int i; - for (i=0; i < (1 << FAST_BITS); ++i) { - stbi_uc fast = h->fast[i]; - fast_ac[i] = 0; - if (fast < 255) { - int rs = h->values[fast]; - int run = (rs >> 4) & 15; - int magbits = rs & 15; - int len = h->size[fast]; - - if (magbits && len + magbits <= FAST_BITS) { - // magnitude code followed by receive_extend code - int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); - int m = 1 << (magbits - 1); - if (k < m) k += (-1 << magbits) + 1; - // if the result is small enough, we can fit it in fast_ac table - if (k >= -128 && k <= 127) - fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits)); - } - } - } -} - -static void stbi__grow_buffer_unsafe(stbi__jpeg *j) -{ - do { - int b = j->nomore ? 0 : stbi__get8(j->s); - if (b == 0xff) { - int c = stbi__get8(j->s); - if (c != 0) { - j->marker = (unsigned char) c; - j->nomore = 1; - return; - } - } - j->code_buffer |= b << (24 - j->code_bits); - j->code_bits += 8; - } while (j->code_bits <= 24); -} - -// (1 << n) - 1 -static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; - -// decode a jpeg huffman value from the bitstream -stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) -{ - unsigned int temp; - int c,k; - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - - // look at the top FAST_BITS and determine what symbol ID it is, - // if the code is <= FAST_BITS - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - k = h->fast[c]; - if (k < 255) { - int s = h->size[k]; - if (s > j->code_bits) - return -1; - j->code_buffer <<= s; - j->code_bits -= s; - return h->values[k]; - } - - // naive test is to shift the code_buffer down so k bits are - // valid, then test against maxcode. To speed this up, we've - // preshifted maxcode left so that it has (16-k) 0s at the - // end; in other words, regardless of the number of bits, it - // wants to be compared against something shifted to have 16; - // that way we don't need to shift inside the loop. - temp = j->code_buffer >> 16; - for (k=FAST_BITS+1 ; ; ++k) - if (temp < h->maxcode[k]) - break; - if (k == 17) { - // error! code not found - j->code_bits -= 16; - return -1; - } - - if (k > j->code_bits) - return -1; - - // convert the huffman code to the symbol id - c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; - STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); - - // convert the id to a symbol - j->code_bits -= k; - j->code_buffer <<= k; - return h->values[c]; -} - -// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); - - sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k + (stbi__jbias[n] & ~sgn); -} - -// get some unsigned bits -stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) -{ - unsigned int k; - if (j->code_bits < n) stbi__grow_buffer_unsafe(j); - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k; -} - -stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) -{ - unsigned int k; - if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); - k = j->code_buffer; - j->code_buffer <<= 1; - --j->code_bits; - return k & 0x80000000; -} - -// given a value that's at position X in the zigzag stream, -// where does it appear in the 8x8 matrix coded as row-major? -static stbi_uc stbi__jpeg_dezigzag[64+15] = -{ - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, - // let corrupt input sample past end - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63 -}; - -// decode one 64-entry block-- -static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant) -{ - int diff,dc,k; - int t; - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - - // 0 all the ac values now so we can do it 32-bits at a time - memset(data,0,64*sizeof(data[0])); - - diff = t ? stbi__extend_receive(j, t) : 0; - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc * dequant[0]); - - // decode AC components, see JPEG spec - k = 1; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) * dequant[zig]); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (rs != 0xf0) break; // end block - k += 16; - } else { - k += r; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); - } - } - } while (k < 64); - return 1; -} - -static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) -{ - int diff,dc; - int t; - if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - - if (j->succ_high == 0) { - // first scan for DC coefficient, must be first - memset(data,0,64*sizeof(data[0])); // 0 all the ac values now - t = stbi__jpeg_huff_decode(j, hdc); - diff = t ? stbi__extend_receive(j, t) : 0; - - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc << j->succ_low); - } else { - // refinement scan for DC coefficient - if (stbi__jpeg_get_bit(j)) - data[0] += (short) (1 << j->succ_low); - } - return 1; -} - -// @OPTIMIZE: store non-zigzagged during the decode passes, -// and only de-zigzag when dequantizing -static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) -{ - int k; - if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - - if (j->succ_high == 0) { - int shift = j->succ_low; - - if (j->eob_run) { - --j->eob_run; - return 1; - } - - k = j->spec_start; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) << shift); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r); - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - --j->eob_run; - break; - } - k += 16; - } else { - k += r; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) << shift); - } - } - } while (k <= j->spec_end); - } else { - // refinement scan for these AC coefficients - - short bit = (short) (1 << j->succ_low); - - if (j->eob_run) { - --j->eob_run; - for (k = j->spec_start; k <= j->spec_end; ++k) { - short *p = &data[stbi__jpeg_dezigzag[k]]; - if (*p != 0) - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } - } else { - k = j->spec_start; - do { - int r,s; - int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r) - 1; - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - r = 64; // force end of block - } else - r = 16; // r=15 is the code for 16 0s - } else { - if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); - // sign bit - if (stbi__jpeg_get_bit(j)) - s = bit; - else - s = -bit; - } - - // advance by r - while (k <= j->spec_end) { - short *p = &data[stbi__jpeg_dezigzag[k]]; - if (*p != 0) { - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - ++k; - } else { - if (r == 0) { - if (s) - data[stbi__jpeg_dezigzag[k++]] = (short) s; - break; - } - --r; - ++k; - } - } - } while (k <= j->spec_end); - } - } - return 1; -} - -// take a -128..127 value and stbi__clamp it and convert to 0..255 -stbi_inline static stbi_uc stbi__clamp(int x) -{ - // trick to use a single test to catch both cases - if ((unsigned int) x > 255) { - if (x < 0) return 0; - if (x > 255) return 255; - } - return (stbi_uc) x; -} - -#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) -#define stbi__fsh(x) ((x) << 12) - -// derived from jidctint -- DCT_ISLOW -#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ - int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ - p2 = s2; \ - p3 = s6; \ - p1 = (p2+p3) * stbi__f2f(0.5411961f); \ - t2 = p1 + p3*stbi__f2f(-1.847759065f); \ - t3 = p1 + p2*stbi__f2f( 0.765366865f); \ - p2 = s0; \ - p3 = s4; \ - t0 = stbi__fsh(p2+p3); \ - t1 = stbi__fsh(p2-p3); \ - x0 = t0+t3; \ - x3 = t0-t3; \ - x1 = t1+t2; \ - x2 = t1-t2; \ - t0 = s7; \ - t1 = s5; \ - t2 = s3; \ - t3 = s1; \ - p3 = t0+t2; \ - p4 = t1+t3; \ - p1 = t0+t3; \ - p2 = t1+t2; \ - p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ - t0 = t0*stbi__f2f( 0.298631336f); \ - t1 = t1*stbi__f2f( 2.053119869f); \ - t2 = t2*stbi__f2f( 3.072711026f); \ - t3 = t3*stbi__f2f( 1.501321110f); \ - p1 = p5 + p1*stbi__f2f(-0.899976223f); \ - p2 = p5 + p2*stbi__f2f(-2.562915447f); \ - p3 = p3*stbi__f2f(-1.961570560f); \ - p4 = p4*stbi__f2f(-0.390180644f); \ - t3 += p1+p4; \ - t2 += p2+p3; \ - t1 += p2+p4; \ - t0 += p1+p3; - -static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) -{ - int i,val[64],*v=val; - stbi_uc *o; - short *d = data; - - // columns - for (i=0; i < 8; ++i,++d, ++v) { - // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing - if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 - && d[40]==0 && d[48]==0 && d[56]==0) { - // no shortcut 0 seconds - // (1|2|3|4|5|6|7)==0 0 seconds - // all separate -0.047 seconds - // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds - int dcterm = d[0] << 2; - v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; - } else { - STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) - // constants scaled things up by 1<<12; let's bring them back - // down, but keep 2 extra bits of precision - x0 += 512; x1 += 512; x2 += 512; x3 += 512; - v[ 0] = (x0+t3) >> 10; - v[56] = (x0-t3) >> 10; - v[ 8] = (x1+t2) >> 10; - v[48] = (x1-t2) >> 10; - v[16] = (x2+t1) >> 10; - v[40] = (x2-t1) >> 10; - v[24] = (x3+t0) >> 10; - v[32] = (x3-t0) >> 10; - } - } - - for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { - // no fast case since the first 1D IDCT spread components out - STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) - // constants scaled things up by 1<<12, plus we had 1<<2 from first - // loop, plus horizontal and vertical each scale by sqrt(8) so together - // we've got an extra 1<<3, so 1<<17 total we need to remove. - // so we want to round that, which means adding 0.5 * 1<<17, - // aka 65536. Also, we'll end up with -128 to 127 that we want - // to encode as 0..255 by adding 128, so we'll add that before the shift - x0 += 65536 + (128<<17); - x1 += 65536 + (128<<17); - x2 += 65536 + (128<<17); - x3 += 65536 + (128<<17); - // tried computing the shifts into temps, or'ing the temps to see - // if any were out of range, but that was slower - o[0] = stbi__clamp((x0+t3) >> 17); - o[7] = stbi__clamp((x0-t3) >> 17); - o[1] = stbi__clamp((x1+t2) >> 17); - o[6] = stbi__clamp((x1-t2) >> 17); - o[2] = stbi__clamp((x2+t1) >> 17); - o[5] = stbi__clamp((x2-t1) >> 17); - o[3] = stbi__clamp((x3+t0) >> 17); - o[4] = stbi__clamp((x3-t0) >> 17); - } -} - -#ifdef STBI_SSE2 -// sse2 integer IDCT. not the fastest possible implementation but it -// produces bit-identical results to the generic C version so it's -// fully "transparent". -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - // This is constructed to match our regular (generic) integer IDCT exactly. - __m128i row0, row1, row2, row3, row4, row5, row6, row7; - __m128i tmp; - - // dot product constant: even elems=x, odd elems=y - #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) - - // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) - // out(1) = c1[even]*x + c1[odd]*y - #define dct_rot(out0,out1, x,y,c0,c1) \ - __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ - __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ - __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ - __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ - __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ - __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) - - // out = in << 12 (in 16-bit, out 32-bit) - #define dct_widen(out, in) \ - __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ - __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) - - // wide add - #define dct_wadd(out, a, b) \ - __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_add_epi32(a##_h, b##_h) - - // wide sub - #define dct_wsub(out, a, b) \ - __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) - - // butterfly a/b, add bias, then shift by "s" and pack - #define dct_bfly32o(out0, out1, a,b,bias,s) \ - { \ - __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ - __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ - dct_wadd(sum, abiased, b); \ - dct_wsub(dif, abiased, b); \ - out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ - out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ - } - - // 8-bit interleave step (for transposes) - #define dct_interleave8(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi8(a, b); \ - b = _mm_unpackhi_epi8(tmp, b) - - // 16-bit interleave step (for transposes) - #define dct_interleave16(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi16(a, b); \ - b = _mm_unpackhi_epi16(tmp, b) - - #define dct_pass(bias,shift) \ - { \ - /* even part */ \ - dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ - __m128i sum04 = _mm_add_epi16(row0, row4); \ - __m128i dif04 = _mm_sub_epi16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ - dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ - __m128i sum17 = _mm_add_epi16(row1, row7); \ - __m128i sum35 = _mm_add_epi16(row3, row5); \ - dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ - dct_wadd(x4, y0o, y4o); \ - dct_wadd(x5, y1o, y5o); \ - dct_wadd(x6, y2o, y5o); \ - dct_wadd(x7, y3o, y4o); \ - dct_bfly32o(row0,row7, x0,x7,bias,shift); \ - dct_bfly32o(row1,row6, x1,x6,bias,shift); \ - dct_bfly32o(row2,row5, x2,x5,bias,shift); \ - dct_bfly32o(row3,row4, x3,x4,bias,shift); \ - } - - __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); - __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); - __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); - __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); - __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); - __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); - __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); - __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); - - // rounding biases in column/row passes, see stbi__idct_block for explanation. - __m128i bias_0 = _mm_set1_epi32(512); - __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); - - // load - row0 = _mm_load_si128((const __m128i *) (data + 0*8)); - row1 = _mm_load_si128((const __m128i *) (data + 1*8)); - row2 = _mm_load_si128((const __m128i *) (data + 2*8)); - row3 = _mm_load_si128((const __m128i *) (data + 3*8)); - row4 = _mm_load_si128((const __m128i *) (data + 4*8)); - row5 = _mm_load_si128((const __m128i *) (data + 5*8)); - row6 = _mm_load_si128((const __m128i *) (data + 6*8)); - row7 = _mm_load_si128((const __m128i *) (data + 7*8)); - - // column pass - dct_pass(bias_0, 10); - - { - // 16bit 8x8 transpose pass 1 - dct_interleave16(row0, row4); - dct_interleave16(row1, row5); - dct_interleave16(row2, row6); - dct_interleave16(row3, row7); - - // transpose pass 2 - dct_interleave16(row0, row2); - dct_interleave16(row1, row3); - dct_interleave16(row4, row6); - dct_interleave16(row5, row7); - - // transpose pass 3 - dct_interleave16(row0, row1); - dct_interleave16(row2, row3); - dct_interleave16(row4, row5); - dct_interleave16(row6, row7); - } - - // row pass - dct_pass(bias_1, 17); - - { - // pack - __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 - __m128i p1 = _mm_packus_epi16(row2, row3); - __m128i p2 = _mm_packus_epi16(row4, row5); - __m128i p3 = _mm_packus_epi16(row6, row7); - - // 8bit 8x8 transpose pass 1 - dct_interleave8(p0, p2); // a0e0a1e1... - dct_interleave8(p1, p3); // c0g0c1g1... - - // transpose pass 2 - dct_interleave8(p0, p1); // a0c0e0g0... - dct_interleave8(p2, p3); // b0d0f0h0... - - // transpose pass 3 - dct_interleave8(p0, p2); // a0b0c0d0... - dct_interleave8(p1, p3); // a4b4c4d4... - - // store - _mm_storel_epi64((__m128i *) out, p0); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p2); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p1); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p3); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); - } - -#undef dct_const -#undef dct_rot -#undef dct_widen -#undef dct_wadd -#undef dct_wsub -#undef dct_bfly32o -#undef dct_interleave8 -#undef dct_interleave16 -#undef dct_pass -} - -#endif // STBI_SSE2 - -#ifdef STBI_NEON - -// NEON integer IDCT. should produce bit-identical -// results to the generic C version. -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; - - int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); - int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); - int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); - int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); - int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); - int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); - int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); - int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); - int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); - int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); - int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); - int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); - -#define dct_long_mul(out, inq, coeff) \ - int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) - -#define dct_long_mac(out, acc, inq, coeff) \ - int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) - -#define dct_widen(out, inq) \ - int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ - int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) - -// wide add -#define dct_wadd(out, a, b) \ - int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vaddq_s32(a##_h, b##_h) - -// wide sub -#define dct_wsub(out, a, b) \ - int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vsubq_s32(a##_h, b##_h) - -// butterfly a/b, then shift using "shiftop" by "s" and pack -#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ - { \ - dct_wadd(sum, a, b); \ - dct_wsub(dif, a, b); \ - out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ - out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ - } - -#define dct_pass(shiftop, shift) \ - { \ - /* even part */ \ - int16x8_t sum26 = vaddq_s16(row2, row6); \ - dct_long_mul(p1e, sum26, rot0_0); \ - dct_long_mac(t2e, p1e, row6, rot0_1); \ - dct_long_mac(t3e, p1e, row2, rot0_2); \ - int16x8_t sum04 = vaddq_s16(row0, row4); \ - int16x8_t dif04 = vsubq_s16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - int16x8_t sum15 = vaddq_s16(row1, row5); \ - int16x8_t sum17 = vaddq_s16(row1, row7); \ - int16x8_t sum35 = vaddq_s16(row3, row5); \ - int16x8_t sum37 = vaddq_s16(row3, row7); \ - int16x8_t sumodd = vaddq_s16(sum17, sum35); \ - dct_long_mul(p5o, sumodd, rot1_0); \ - dct_long_mac(p1o, p5o, sum17, rot1_1); \ - dct_long_mac(p2o, p5o, sum35, rot1_2); \ - dct_long_mul(p3o, sum37, rot2_0); \ - dct_long_mul(p4o, sum15, rot2_1); \ - dct_wadd(sump13o, p1o, p3o); \ - dct_wadd(sump24o, p2o, p4o); \ - dct_wadd(sump23o, p2o, p3o); \ - dct_wadd(sump14o, p1o, p4o); \ - dct_long_mac(x4, sump13o, row7, rot3_0); \ - dct_long_mac(x5, sump24o, row5, rot3_1); \ - dct_long_mac(x6, sump23o, row3, rot3_2); \ - dct_long_mac(x7, sump14o, row1, rot3_3); \ - dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ - dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ - dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ - dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ - } - - // load - row0 = vld1q_s16(data + 0*8); - row1 = vld1q_s16(data + 1*8); - row2 = vld1q_s16(data + 2*8); - row3 = vld1q_s16(data + 3*8); - row4 = vld1q_s16(data + 4*8); - row5 = vld1q_s16(data + 5*8); - row6 = vld1q_s16(data + 6*8); - row7 = vld1q_s16(data + 7*8); - - // add DC bias - row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); - - // column pass - dct_pass(vrshrn_n_s32, 10); - - // 16bit 8x8 transpose - { -// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. -// whether compilers actually get this is another story, sadly. -#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } -#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } - - // pass 1 - dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 - dct_trn16(row2, row3); - dct_trn16(row4, row5); - dct_trn16(row6, row7); - - // pass 2 - dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 - dct_trn32(row1, row3); - dct_trn32(row4, row6); - dct_trn32(row5, row7); - - // pass 3 - dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 - dct_trn64(row1, row5); - dct_trn64(row2, row6); - dct_trn64(row3, row7); - -#undef dct_trn16 -#undef dct_trn32 -#undef dct_trn64 - } - - // row pass - // vrshrn_n_s32 only supports shifts up to 16, we need - // 17. so do a non-rounding shift of 16 first then follow - // up with a rounding shift by 1. - dct_pass(vshrn_n_s32, 16); - - { - // pack and round - uint8x8_t p0 = vqrshrun_n_s16(row0, 1); - uint8x8_t p1 = vqrshrun_n_s16(row1, 1); - uint8x8_t p2 = vqrshrun_n_s16(row2, 1); - uint8x8_t p3 = vqrshrun_n_s16(row3, 1); - uint8x8_t p4 = vqrshrun_n_s16(row4, 1); - uint8x8_t p5 = vqrshrun_n_s16(row5, 1); - uint8x8_t p6 = vqrshrun_n_s16(row6, 1); - uint8x8_t p7 = vqrshrun_n_s16(row7, 1); - - // again, these can translate into one instruction, but often don't. -#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } -#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } - - // sadly can't use interleaved stores here since we only write - // 8 bytes to each scan line! - - // 8x8 8-bit transpose pass 1 - dct_trn8_8(p0, p1); - dct_trn8_8(p2, p3); - dct_trn8_8(p4, p5); - dct_trn8_8(p6, p7); - - // pass 2 - dct_trn8_16(p0, p2); - dct_trn8_16(p1, p3); - dct_trn8_16(p4, p6); - dct_trn8_16(p5, p7); - - // pass 3 - dct_trn8_32(p0, p4); - dct_trn8_32(p1, p5); - dct_trn8_32(p2, p6); - dct_trn8_32(p3, p7); - - // store - vst1_u8(out, p0); out += out_stride; - vst1_u8(out, p1); out += out_stride; - vst1_u8(out, p2); out += out_stride; - vst1_u8(out, p3); out += out_stride; - vst1_u8(out, p4); out += out_stride; - vst1_u8(out, p5); out += out_stride; - vst1_u8(out, p6); out += out_stride; - vst1_u8(out, p7); - -#undef dct_trn8_8 -#undef dct_trn8_16 -#undef dct_trn8_32 - } - -#undef dct_long_mul -#undef dct_long_mac -#undef dct_widen -#undef dct_wadd -#undef dct_wsub -#undef dct_bfly32o -#undef dct_pass -} - -#endif // STBI_NEON - -#define STBI__MARKER_none 0xff -// if there's a pending marker from the entropy stream, return that -// otherwise, fetch from the stream and get a marker. if there's no -// marker, return 0xff, which is never a valid marker value -static stbi_uc stbi__get_marker(stbi__jpeg *j) -{ - stbi_uc x; - if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } - x = stbi__get8(j->s); - if (x != 0xff) return STBI__MARKER_none; - while (x == 0xff) - x = stbi__get8(j->s); - return x; -} - -// in each scan, we'll have scan_n components, and the order -// of the components is specified by order[] -#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) - -// after a restart interval, stbi__jpeg_reset the entropy decoder and -// the dc prediction -static void stbi__jpeg_reset(stbi__jpeg *j) -{ - j->code_bits = 0; - j->code_buffer = 0; - j->nomore = 0; - j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; - j->marker = STBI__MARKER_none; - j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; - j->eob_run = 0; - // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, - // since we don't even allow 1<<30 pixels -} - -static int stbi__parse_entropy_coded_data(stbi__jpeg *z) -{ - stbi__jpeg_reset(z); - if (!z->progressive) { - if (z->scan_n == 1) { - int i,j; - STBI_SIMD_ALIGN(short, data[64]); - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - STBI_SIMD_ALIGN(short, data[64]); - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x)*8; - int y2 = (j*z->img_comp[n].v + y)*8; - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } else { - if (z->scan_n == 1) { - int i,j; - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - if (z->spec_start == 0) { - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } else { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) - return 0; - } - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x); - int y2 = (j*z->img_comp[n].v + y); - short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } -} - -static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant) -{ - int i; - for (i=0; i < 64; ++i) - data[i] *= dequant[i]; -} - -static void stbi__jpeg_finish(stbi__jpeg *z) -{ - if (z->progressive) { - // dequantize and idct the data - int i,j,n; - for (n=0; n < z->s->img_n; ++n) { - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - } - } - } - } -} - -static int stbi__process_marker(stbi__jpeg *z, int m) -{ - int L; - switch (m) { - case STBI__MARKER_none: // no marker found - return stbi__err("expected marker","Corrupt JPEG"); - - case 0xDD: // DRI - specify restart interval - if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); - z->restart_interval = stbi__get16be(z->s); - return 1; - - case 0xDB: // DQT - define quantization table - L = stbi__get16be(z->s)-2; - while (L > 0) { - int q = stbi__get8(z->s); - int p = q >> 4; - int t = q & 15,i; - if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG"); - if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); - for (i=0; i < 64; ++i) - z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s); - L -= 65; - } - return L==0; - - case 0xC4: // DHT - define huffman table - L = stbi__get16be(z->s)-2; - while (L > 0) { - stbi_uc *v; - int sizes[16],i,n=0; - int q = stbi__get8(z->s); - int tc = q >> 4; - int th = q & 15; - if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); - for (i=0; i < 16; ++i) { - sizes[i] = stbi__get8(z->s); - n += sizes[i]; - } - L -= 17; - if (tc == 0) { - if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; - v = z->huff_dc[th].values; - } else { - if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; - v = z->huff_ac[th].values; - } - for (i=0; i < n; ++i) - v[i] = stbi__get8(z->s); - if (tc != 0) - stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); - L -= n; - } - return L==0; - } - // check for comment block or APP blocks - if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { - stbi__skip(z->s, stbi__get16be(z->s)-2); - return 1; - } - return 0; -} - -// after we see SOS -static int stbi__process_scan_header(stbi__jpeg *z) -{ - int i; - int Ls = stbi__get16be(z->s); - z->scan_n = stbi__get8(z->s); - if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); - if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); - for (i=0; i < z->scan_n; ++i) { - int id = stbi__get8(z->s), which; - int q = stbi__get8(z->s); - for (which = 0; which < z->s->img_n; ++which) - if (z->img_comp[which].id == id) - break; - if (which == z->s->img_n) return 0; // no match - z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); - z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); - z->order[i] = which; - } - - { - int aa; - z->spec_start = stbi__get8(z->s); - z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 - aa = stbi__get8(z->s); - z->succ_high = (aa >> 4); - z->succ_low = (aa & 15); - if (z->progressive) { - if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) - return stbi__err("bad SOS", "Corrupt JPEG"); - } else { - if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); - if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); - z->spec_end = 63; - } - } - - return 1; -} - -static int stbi__process_frame_header(stbi__jpeg *z, int scan) -{ - stbi__context *s = z->s; - int Lf,p,i,q, h_max=1,v_max=1,c; - Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG - p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline - s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG - s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires - c = stbi__get8(s); - if (c != 3 && c != 1) return stbi__err("bad component count","Corrupt JPEG"); // JFIF requires - s->img_n = c; - for (i=0; i < c; ++i) { - z->img_comp[i].data = NULL; - z->img_comp[i].linebuf = NULL; - } - - if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); - - for (i=0; i < s->img_n; ++i) { - z->img_comp[i].id = stbi__get8(s); - if (z->img_comp[i].id != i+1) // JFIF requires - if (z->img_comp[i].id != i) // some version of jpegtran outputs non-JFIF-compliant files! - return stbi__err("bad component ID","Corrupt JPEG"); - q = stbi__get8(s); - z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); - z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); - z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); - } - - if (scan != STBI__SCAN_load) return 1; - - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - - for (i=0; i < s->img_n; ++i) { - if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; - if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; - } - - // compute interleaved mcu info - z->img_h_max = h_max; - z->img_v_max = v_max; - z->img_mcu_w = h_max * 8; - z->img_mcu_h = v_max * 8; - z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; - z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; - - for (i=0; i < s->img_n; ++i) { - // number of effective pixels (e.g. for non-interleaved MCU) - z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; - z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; - // to simplify generation, we'll allocate enough memory to decode - // the bogus oversized data from using interleaved MCUs and their - // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't - // discard the extra data until colorspace conversion - z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; - z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; - z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); - - if (z->img_comp[i].raw_data == NULL) { - for(--i; i >= 0; --i) { - STBI_FREE(z->img_comp[i].raw_data); - z->img_comp[i].data = NULL; - } - return stbi__err("outofmem", "Out of memory"); - } - // align blocks for idct using mmx/sse - z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); - z->img_comp[i].linebuf = NULL; - if (z->progressive) { - z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3; - z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3; - z->img_comp[i].raw_coeff = STBI_MALLOC(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15); - z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); - } else { - z->img_comp[i].coeff = 0; - z->img_comp[i].raw_coeff = 0; - } - } - - return 1; -} - -// use comparisons since in some cases we handle more than one case (e.g. SOF) -#define stbi__DNL(x) ((x) == 0xdc) -#define stbi__SOI(x) ((x) == 0xd8) -#define stbi__EOI(x) ((x) == 0xd9) -#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) -#define stbi__SOS(x) ((x) == 0xda) - -#define stbi__SOF_progressive(x) ((x) == 0xc2) - -static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) -{ - int m; - z->marker = STBI__MARKER_none; // initialize cached marker to empty - m = stbi__get_marker(z); - if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); - if (scan == STBI__SCAN_type) return 1; - m = stbi__get_marker(z); - while (!stbi__SOF(m)) { - if (!stbi__process_marker(z,m)) return 0; - m = stbi__get_marker(z); - while (m == STBI__MARKER_none) { - // some files have extra padding after their blocks, so ok, we'll scan - if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); - m = stbi__get_marker(z); - } - } - z->progressive = stbi__SOF_progressive(m); - if (!stbi__process_frame_header(z, scan)) return 0; - return 1; -} - -// decode image to YCbCr format -static int stbi__decode_jpeg_image(stbi__jpeg *j) -{ - int m; - j->restart_interval = 0; - if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; - m = stbi__get_marker(j); - while (!stbi__EOI(m)) { - if (stbi__SOS(m)) { - if (!stbi__process_scan_header(j)) return 0; - if (!stbi__parse_entropy_coded_data(j)) return 0; - if (j->marker == STBI__MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - if (x == 255) { - j->marker = stbi__get8(j->s); - break; - } else if (x != 0) { - return stbi__err("junk before marker", "Corrupt JPEG"); - } - } - // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 - } - } else { - if (!stbi__process_marker(j, m)) return 0; - } - m = stbi__get_marker(j); - } - if (j->progressive) - stbi__jpeg_finish(j); - return 1; -} - -// static jfif-centered resampling (across block boundaries) - -typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, - int w, int hs); - -#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) - -static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - STBI_NOTUSED(out); - STBI_NOTUSED(in_far); - STBI_NOTUSED(w); - STBI_NOTUSED(hs); - return in_near; -} - -static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples vertically for every one in input - int i; - STBI_NOTUSED(hs); - for (i=0; i < w; ++i) - out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); - return out; -} - -static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples horizontally for every one in input - int i; - stbi_uc *input = in_near; - - if (w == 1) { - // if only one sample, can't do any interpolation - out[0] = out[1] = input[0]; - return out; - } - - out[0] = input[0]; - out[1] = stbi__div4(input[0]*3 + input[1] + 2); - for (i=1; i < w-1; ++i) { - int n = 3*input[i]+2; - out[i*2+0] = stbi__div4(n+input[i-1]); - out[i*2+1] = stbi__div4(n+input[i+1]); - } - out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); - out[i*2+1] = input[w-1]; - - STBI_NOTUSED(in_far); - STBI_NOTUSED(hs); - - return out; -} - -#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) - -static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i,t0,t1; - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } - - t1 = 3*in_near[0] + in_far[0]; - out[0] = stbi__div4(t1+2); - for (i=1; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); - - STBI_NOTUSED(hs); - - return out; -} - -#if defined(STBI_SSE2) || defined(STBI_NEON) -static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i=0,t0,t1; - - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } - - t1 = 3*in_near[0] + in_far[0]; - // process groups of 8 pixels for as long as we can. - // note we can't handle the last pixel in a row in this loop - // because we need to handle the filter boundary conditions. - for (; i < ((w-1) & ~7); i += 8) { -#if defined(STBI_SSE2) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - __m128i zero = _mm_setzero_si128(); - __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); - __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); - __m128i farw = _mm_unpacklo_epi8(farb, zero); - __m128i nearw = _mm_unpacklo_epi8(nearb, zero); - __m128i diff = _mm_sub_epi16(farw, nearw); - __m128i nears = _mm_slli_epi16(nearw, 2); - __m128i curr = _mm_add_epi16(nears, diff); // current row - - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - __m128i prv0 = _mm_slli_si128(curr, 2); - __m128i nxt0 = _mm_srli_si128(curr, 2); - __m128i prev = _mm_insert_epi16(prv0, t1, 0); - __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); - - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - __m128i bias = _mm_set1_epi16(8); - __m128i curs = _mm_slli_epi16(curr, 2); - __m128i prvd = _mm_sub_epi16(prev, curr); - __m128i nxtd = _mm_sub_epi16(next, curr); - __m128i curb = _mm_add_epi16(curs, bias); - __m128i even = _mm_add_epi16(prvd, curb); - __m128i odd = _mm_add_epi16(nxtd, curb); - - // interleave even and odd pixels, then undo scaling. - __m128i int0 = _mm_unpacklo_epi16(even, odd); - __m128i int1 = _mm_unpackhi_epi16(even, odd); - __m128i de0 = _mm_srli_epi16(int0, 4); - __m128i de1 = _mm_srli_epi16(int1, 4); - - // pack and write output - __m128i outv = _mm_packus_epi16(de0, de1); - _mm_storeu_si128((__m128i *) (out + i*2), outv); -#elif defined(STBI_NEON) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - uint8x8_t farb = vld1_u8(in_far + i); - uint8x8_t nearb = vld1_u8(in_near + i); - int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); - int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); - int16x8_t curr = vaddq_s16(nears, diff); // current row - - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - int16x8_t prv0 = vextq_s16(curr, curr, 7); - int16x8_t nxt0 = vextq_s16(curr, curr, 1); - int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); - int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); - - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - int16x8_t curs = vshlq_n_s16(curr, 2); - int16x8_t prvd = vsubq_s16(prev, curr); - int16x8_t nxtd = vsubq_s16(next, curr); - int16x8_t even = vaddq_s16(curs, prvd); - int16x8_t odd = vaddq_s16(curs, nxtd); - - // undo scaling and round, then store with even/odd phases interleaved - uint8x8x2_t o; - o.val[0] = vqrshrun_n_s16(even, 4); - o.val[1] = vqrshrun_n_s16(odd, 4); - vst2_u8(out + i*2, o); -#endif - - // "previous" value for next iter - t1 = 3*in_near[i+7] + in_far[i+7]; - } - - t0 = t1; - t1 = 3*in_near[i] + in_far[i]; - out[i*2] = stbi__div16(3*t1 + t0 + 8); - - for (++i; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); - - STBI_NOTUSED(hs); - - return out; -} -#endif - -static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // resample with nearest-neighbor - int i,j; - STBI_NOTUSED(in_far); - for (i=0; i < w; ++i) - for (j=0; j < hs; ++j) - out[i*hs+j] = in_near[i]; - return out; -} - -#ifdef STBI_JPEG_OLD -// this is the same YCbCr-to-RGB calculation that stb_image has used -// historically before the algorithm changes in 1.49 -#define float2fixed(x) ((int) ((x) * 65536 + 0.5)) -static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 16) + 32768; // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr*float2fixed(1.40200f); - g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); - b = y_fixed + cb*float2fixed(1.77200f); - r >>= 16; - g >>= 16; - b >>= 16; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } -} -#else -// this is a reduced-precision calculation of YCbCr-to-RGB introduced -// to make sure the code produces the same results in both SIMD and scalar -#define float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) -static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* float2fixed(1.40200f); - g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } -} -#endif - -#if defined(STBI_SSE2) || defined(STBI_NEON) -static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) -{ - int i = 0; - -#ifdef STBI_SSE2 - // step == 3 is pretty ugly on the final interleave, and i'm not convinced - // it's useful in practice (you wouldn't use it for textures, for example). - // so just accelerate step == 4 case. - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - __m128i signflip = _mm_set1_epi8(-0x80); - __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); - __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); - __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); - __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); - __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); - __m128i xw = _mm_set1_epi16(255); // alpha channel - - for (; i+7 < count; i += 8) { - // load - __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); - __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); - __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); - __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 - __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 - - // unpack to short (and left-shift cr, cb by 8) - __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); - __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); - __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); - - // color transform - __m128i yws = _mm_srli_epi16(yw, 4); - __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); - __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); - __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); - __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); - __m128i rws = _mm_add_epi16(cr0, yws); - __m128i gwt = _mm_add_epi16(cb0, yws); - __m128i bws = _mm_add_epi16(yws, cb1); - __m128i gws = _mm_add_epi16(gwt, cr1); - - // descale - __m128i rw = _mm_srai_epi16(rws, 4); - __m128i bw = _mm_srai_epi16(bws, 4); - __m128i gw = _mm_srai_epi16(gws, 4); - - // back to byte, set up for transpose - __m128i brb = _mm_packus_epi16(rw, bw); - __m128i gxb = _mm_packus_epi16(gw, xw); - - // transpose to interleave channels - __m128i t0 = _mm_unpacklo_epi8(brb, gxb); - __m128i t1 = _mm_unpackhi_epi8(brb, gxb); - __m128i o0 = _mm_unpacklo_epi16(t0, t1); - __m128i o1 = _mm_unpackhi_epi16(t0, t1); - - // store - _mm_storeu_si128((__m128i *) (out + 0), o0); - _mm_storeu_si128((__m128i *) (out + 16), o1); - out += 32; - } - } -#endif - -#ifdef STBI_NEON - // in this version, step=3 support would be easy to add. but is there demand? - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - uint8x8_t signflip = vdup_n_u8(0x80); - int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); - int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); - int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); - int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); - - for (; i+7 < count; i += 8) { - // load - uint8x8_t y_bytes = vld1_u8(y + i); - uint8x8_t cr_bytes = vld1_u8(pcr + i); - uint8x8_t cb_bytes = vld1_u8(pcb + i); - int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); - int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); - - // expand to s16 - int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); - int16x8_t crw = vshll_n_s8(cr_biased, 7); - int16x8_t cbw = vshll_n_s8(cb_biased, 7); - - // color transform - int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); - int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); - int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); - int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); - int16x8_t rws = vaddq_s16(yws, cr0); - int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); - int16x8_t bws = vaddq_s16(yws, cb1); - - // undo scaling, round, convert to byte - uint8x8x4_t o; - o.val[0] = vqrshrun_n_s16(rws, 4); - o.val[1] = vqrshrun_n_s16(gws, 4); - o.val[2] = vqrshrun_n_s16(bws, 4); - o.val[3] = vdup_n_u8(255); - - // store, interleaving r/g/b/a - vst4_u8(out, o); - out += 8*4; - } - } -#endif - - for (; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* float2fixed(1.40200f); - g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } -} -#endif - -// set up the kernels -static void stbi__setup_jpeg(stbi__jpeg *j) -{ - j->idct_block_kernel = stbi__idct_block; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; - -#ifdef STBI_SSE2 - if (stbi__sse2_available()) { - j->idct_block_kernel = stbi__idct_simd; - #ifndef STBI_JPEG_OLD - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - #endif - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; - } -#endif - -#ifdef STBI_NEON - j->idct_block_kernel = stbi__idct_simd; - #ifndef STBI_JPEG_OLD - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - #endif - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; -#endif -} - -// clean up the temporary component buffers -static void stbi__cleanup_jpeg(stbi__jpeg *j) -{ - int i; - for (i=0; i < j->s->img_n; ++i) { - if (j->img_comp[i].raw_data) { - STBI_FREE(j->img_comp[i].raw_data); - j->img_comp[i].raw_data = NULL; - j->img_comp[i].data = NULL; - } - if (j->img_comp[i].raw_coeff) { - STBI_FREE(j->img_comp[i].raw_coeff); - j->img_comp[i].raw_coeff = 0; - j->img_comp[i].coeff = 0; - } - if (j->img_comp[i].linebuf) { - STBI_FREE(j->img_comp[i].linebuf); - j->img_comp[i].linebuf = NULL; - } - } -} - -typedef struct -{ - resample_row_func resample; - stbi_uc *line0,*line1; - int hs,vs; // expansion factor in each axis - int w_lores; // horizontal pixels pre-expansion - int ystep; // how far through vertical expansion we are - int ypos; // which pre-expansion row we're on -} stbi__resample; - -static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) -{ - int n, decode_n; - z->s->img_n = 0; // make stbi__cleanup_jpeg safe - - // validate req_comp - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - - // load a jpeg image from whichever source, but leave in YCbCr format - if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } - - // determine actual number of components to generate - n = req_comp ? req_comp : z->s->img_n; - - if (z->s->img_n == 3 && n < 3) - decode_n = 1; - else - decode_n = z->s->img_n; - - // resample and color-convert - { - int k; - unsigned int i,j; - stbi_uc *output; - stbi_uc *coutput[4]; - - stbi__resample res_comp[4]; - - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - - // allocate line buffer big enough for upsampling off the edges - // with upsample factor of 4 - z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); - if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } - - r->hs = z->img_h_max / z->img_comp[k].h; - r->vs = z->img_v_max / z->img_comp[k].v; - r->ystep = r->vs >> 1; - r->w_lores = (z->s->img_x + r->hs-1) / r->hs; - r->ypos = 0; - r->line0 = r->line1 = z->img_comp[k].data; - - if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; - else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; - else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; - else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; - else r->resample = stbi__resample_row_generic; - } - - // can't error after this so, this is safe - output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1); - if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } - - // now go ahead and resample - for (j=0; j < z->s->img_y; ++j) { - stbi_uc *out = output + n * z->s->img_x * j; - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - int y_bot = r->ystep >= (r->vs >> 1); - coutput[k] = r->resample(z->img_comp[k].linebuf, - y_bot ? r->line1 : r->line0, - y_bot ? r->line0 : r->line1, - r->w_lores, r->hs); - if (++r->ystep >= r->vs) { - r->ystep = 0; - r->line0 = r->line1; - if (++r->ypos < z->img_comp[k].y) - r->line1 += z->img_comp[k].w2; - } - } - if (n >= 3) { - stbi_uc *y = coutput[0]; - if (z->s->img_n == 3) { - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } else - for (i=0; i < z->s->img_x; ++i) { - out[0] = out[1] = out[2] = y[i]; - out[3] = 255; // not used if n==3 - out += n; - } - } else { - stbi_uc *y = coutput[0]; - if (n == 1) - for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; - else - for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; - } - } - stbi__cleanup_jpeg(z); - *out_x = z->s->img_x; - *out_y = z->s->img_y; - if (comp) *comp = z->s->img_n; // report original components, not output - return output; - } -} - -static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__jpeg j; - j.s = s; - stbi__setup_jpeg(&j); - return load_jpeg_image(&j, x,y,comp,req_comp); -} - -static int stbi__jpeg_test(stbi__context *s) -{ - int r; - stbi__jpeg j; - j.s = s; - stbi__setup_jpeg(&j); - r = stbi__decode_jpeg_header(&j, STBI__SCAN_type); - stbi__rewind(s); - return r; -} - -static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) -{ - if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { - stbi__rewind( j->s ); - return 0; - } - if (x) *x = j->s->img_x; - if (y) *y = j->s->img_y; - if (comp) *comp = j->s->img_n; - return 1; -} - -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__jpeg j; - j.s = s; - return stbi__jpeg_info_raw(&j, x, y, comp); -} -#endif - -// public domain zlib decode v0.2 Sean Barrett 2006-11-18 -// simple implementation -// - all input must be provided in an upfront buffer -// - all output is written to a single output buffer (can malloc/realloc) -// performance -// - fast huffman - -#ifndef STBI_NO_ZLIB - -// fast-way is faster to check than jpeg huffman, but slow way is slower -#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables -#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) - -// zlib-style huffman encoding -// (jpegs packs from left, zlib from right, so can't share code) -typedef struct -{ - stbi__uint16 fast[1 << STBI__ZFAST_BITS]; - stbi__uint16 firstcode[16]; - int maxcode[17]; - stbi__uint16 firstsymbol[16]; - stbi_uc size[288]; - stbi__uint16 value[288]; -} stbi__zhuffman; - -stbi_inline static int stbi__bitreverse16(int n) -{ - n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); - n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); - n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); - n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); - return n; -} - -stbi_inline static int stbi__bit_reverse(int v, int bits) -{ - STBI_ASSERT(bits <= 16); - // to bit reverse n bits, reverse 16 and shift - // e.g. 11 bits, bit reverse and shift away 5 - return stbi__bitreverse16(v) >> (16-bits); -} - -static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) -{ - int i,k=0; - int code, next_code[16], sizes[17]; - - // DEFLATE spec for generating codes - memset(sizes, 0, sizeof(sizes)); - memset(z->fast, 0, sizeof(z->fast)); - for (i=0; i < num; ++i) - ++sizes[sizelist[i]]; - sizes[0] = 0; - for (i=1; i < 16; ++i) - STBI_ASSERT(sizes[i] <= (1 << i)); - code = 0; - for (i=1; i < 16; ++i) { - next_code[i] = code; - z->firstcode[i] = (stbi__uint16) code; - z->firstsymbol[i] = (stbi__uint16) k; - code = (code + sizes[i]); - if (sizes[i]) - if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt JPEG"); - z->maxcode[i] = code << (16-i); // preshift for inner loop - code <<= 1; - k += sizes[i]; - } - z->maxcode[16] = 0x10000; // sentinel - for (i=0; i < num; ++i) { - int s = sizelist[i]; - if (s) { - int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; - stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); - z->size [c] = (stbi_uc ) s; - z->value[c] = (stbi__uint16) i; - if (s <= STBI__ZFAST_BITS) { - int k = stbi__bit_reverse(next_code[s],s); - while (k < (1 << STBI__ZFAST_BITS)) { - z->fast[k] = fastv; - k += (1 << s); - } - } - ++next_code[s]; - } - } - return 1; -} - -// zlib-from-memory implementation for PNG reading -// because PNG allows splitting the zlib stream arbitrarily, -// and it's annoying structurally to have PNG call ZLIB call PNG, -// we require PNG read all the IDATs and combine them into a single -// memory buffer - -typedef struct -{ - stbi_uc *zbuffer, *zbuffer_end; - int num_bits; - stbi__uint32 code_buffer; - - char *zout; - char *zout_start; - char *zout_end; - int z_expandable; - - stbi__zhuffman z_length, z_distance; -} stbi__zbuf; - -stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) -{ - if (z->zbuffer >= z->zbuffer_end) return 0; - return *z->zbuffer++; -} - -static void stbi__fill_bits(stbi__zbuf *z) -{ - do { - STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); - z->code_buffer |= stbi__zget8(z) << z->num_bits; - z->num_bits += 8; - } while (z->num_bits <= 24); -} - -stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) -{ - unsigned int k; - if (z->num_bits < n) stbi__fill_bits(z); - k = z->code_buffer & ((1 << n) - 1); - z->code_buffer >>= n; - z->num_bits -= n; - return k; -} - -static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s,k; - // not resolved by fast table, so compute it the slow way - // use jpeg approach, which requires MSbits at top - k = stbi__bit_reverse(a->code_buffer, 16); - for (s=STBI__ZFAST_BITS+1; ; ++s) - if (k < z->maxcode[s]) - break; - if (s == 16) return -1; // invalid code! - // code size is s, so: - b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - STBI_ASSERT(z->size[b] == s); - a->code_buffer >>= s; - a->num_bits -= s; - return z->value[b]; -} - -stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s; - if (a->num_bits < 16) stbi__fill_bits(a); - b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; - if (b) { - s = b >> 9; - a->code_buffer >>= s; - a->num_bits -= s; - return b & 511; - } - return stbi__zhuffman_decode_slowpath(a, z); -} - -static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes -{ - char *q; - int cur, limit; - z->zout = zout; - if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); - cur = (int) (z->zout - z->zout_start); - limit = (int) (z->zout_end - z->zout_start); - while (cur + n > limit) - limit *= 2; - q = (char *) STBI_REALLOC(z->zout_start, limit); - if (q == NULL) return stbi__err("outofmem", "Out of memory"); - z->zout_start = q; - z->zout = q + cur; - z->zout_end = q + limit; - return 1; -} - -static int stbi__zlength_base[31] = { - 3,4,5,6,7,8,9,10,11,13, - 15,17,19,23,27,31,35,43,51,59, - 67,83,99,115,131,163,195,227,258,0,0 }; - -static int stbi__zlength_extra[31]= -{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - -static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, -257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - -static int stbi__zdist_extra[32] = -{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -static int stbi__parse_huffman_block(stbi__zbuf *a) -{ - char *zout = a->zout; - for(;;) { - int z = stbi__zhuffman_decode(a, &a->z_length); - if (z < 256) { - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes - if (zout >= a->zout_end) { - if (!stbi__zexpand(a, zout, 1)) return 0; - zout = a->zout; - } - *zout++ = (char) z; - } else { - stbi_uc *p; - int len,dist; - if (z == 256) { - a->zout = zout; - return 1; - } - z -= 257; - len = stbi__zlength_base[z]; - if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); - z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); - dist = stbi__zdist_base[z]; - if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); - if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); - if (zout + len > a->zout_end) { - if (!stbi__zexpand(a, zout, len)) return 0; - zout = a->zout; - } - p = (stbi_uc *) (zout - dist); - if (dist == 1) { // run of one byte; common in images. - stbi_uc v = *p; - do *zout++ = v; while (--len); - } else { - do *zout++ = *p++; while (--len); - } - } - } -} - -static int stbi__compute_huffman_codes(stbi__zbuf *a) -{ - static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - stbi__zhuffman z_codelength; - stbi_uc lencodes[286+32+137];//padding for maximum single op - stbi_uc codelength_sizes[19]; - int i,n; - - int hlit = stbi__zreceive(a,5) + 257; - int hdist = stbi__zreceive(a,5) + 1; - int hclen = stbi__zreceive(a,4) + 4; - - memset(codelength_sizes, 0, sizeof(codelength_sizes)); - for (i=0; i < hclen; ++i) { - int s = stbi__zreceive(a,3); - codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; - } - if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; - - n = 0; - while (n < hlit + hdist) { - int c = stbi__zhuffman_decode(a, &z_codelength); - STBI_ASSERT(c >= 0 && c < 19); - if (c < 16) - lencodes[n++] = (stbi_uc) c; - else if (c == 16) { - c = stbi__zreceive(a,2)+3; - memset(lencodes+n, lencodes[n-1], c); - n += c; - } else if (c == 17) { - c = stbi__zreceive(a,3)+3; - memset(lencodes+n, 0, c); - n += c; - } else { - STBI_ASSERT(c == 18); - c = stbi__zreceive(a,7)+11; - memset(lencodes+n, 0, c); - n += c; - } - } - if (n != hlit+hdist) return stbi__err("bad codelengths","Corrupt PNG"); - if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; - return 1; -} - -static int stbi__parse_uncomperssed_block(stbi__zbuf *a) -{ - stbi_uc header[4]; - int len,nlen,k; - if (a->num_bits & 7) - stbi__zreceive(a, a->num_bits & 7); // discard - // drain the bit-packed data into header - k = 0; - while (a->num_bits > 0) { - header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check - a->code_buffer >>= 8; - a->num_bits -= 8; - } - STBI_ASSERT(a->num_bits == 0); - // now fill header the normal way - while (k < 4) - header[k++] = stbi__zget8(a); - len = header[1] * 256 + header[0]; - nlen = header[3] * 256 + header[2]; - if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); - if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); - if (a->zout + len > a->zout_end) - if (!stbi__zexpand(a, a->zout, len)) return 0; - memcpy(a->zout, a->zbuffer, len); - a->zbuffer += len; - a->zout += len; - return 1; -} - -static int stbi__parse_zlib_header(stbi__zbuf *a) -{ - int cmf = stbi__zget8(a); - int cm = cmf & 15; - /* int cinfo = cmf >> 4; */ - int flg = stbi__zget8(a); - if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec - if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png - if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png - // window = 1 << (8 + cinfo)... but who cares, we fully buffer output - return 1; -} - -// @TODO: should statically initialize these for optimal thread safety -static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32]; -static void stbi__init_zdefaults(void) -{ - int i; // use <= to match clearly with spec - for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; - for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; - for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; - for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; - - for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; -} - -static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) -{ - int final, type; - if (parse_header) - if (!stbi__parse_zlib_header(a)) return 0; - a->num_bits = 0; - a->code_buffer = 0; - do { - final = stbi__zreceive(a,1); - type = stbi__zreceive(a,2); - if (type == 0) { - if (!stbi__parse_uncomperssed_block(a)) return 0; - } else if (type == 3) { - return 0; - } else { - if (type == 1) { - // use fixed code lengths - if (!stbi__zdefault_distance[31]) stbi__init_zdefaults(); - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; - } else { - if (!stbi__compute_huffman_codes(a)) return 0; - } - if (!stbi__parse_huffman_block(a)) return 0; - } - } while (!final); - return 1; -} - -static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) -{ - a->zout_start = obuf; - a->zout = obuf; - a->zout_end = obuf + olen; - a->z_expandable = exp; - - return stbi__parse_zlib(a, parse_header); -} - -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) -{ - return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); -} - -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) - return (int) (a.zout - a.zout_start); - else - return -1; -} - -STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(16384); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer+len; - if (stbi__do_zlib(&a, p, 16384, 1, 0)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) - return (int) (a.zout - a.zout_start); - else - return -1; -} -#endif - -// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 -// simple implementation -// - only 8-bit samples -// - no CRC checking -// - allocates lots of intermediate memory -// - avoids problem of streaming data between subsystems -// - avoids explicit window management -// performance -// - uses stb_zlib, a PD zlib implementation with fast huffman decoding - -#ifndef STBI_NO_PNG -typedef struct -{ - stbi__uint32 length; - stbi__uint32 type; -} stbi__pngchunk; - -static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) -{ - stbi__pngchunk c; - c.length = stbi__get32be(s); - c.type = stbi__get32be(s); - return c; -} - -static int stbi__check_png_header(stbi__context *s) -{ - static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; - int i; - for (i=0; i < 8; ++i) - if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); - return 1; -} - -typedef struct -{ - stbi__context *s; - stbi_uc *idata, *expanded, *out; -} stbi__png; - - -enum { - STBI__F_none=0, - STBI__F_sub=1, - STBI__F_up=2, - STBI__F_avg=3, - STBI__F_paeth=4, - // synthetic filters used for first scanline to avoid needing a dummy row of 0s - STBI__F_avg_first, - STBI__F_paeth_first -}; - -static stbi_uc first_row_filter[5] = -{ - STBI__F_none, - STBI__F_sub, - STBI__F_none, - STBI__F_avg_first, - STBI__F_paeth_first -}; - -static int stbi__paeth(int a, int b, int c) -{ - int p = a + b - c; - int pa = abs(p-a); - int pb = abs(p-b); - int pc = abs(p-c); - if (pa <= pb && pa <= pc) return a; - if (pb <= pc) return b; - return c; -} - -static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; - -// create the png data from post-deflated data -static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) -{ - stbi__context *s = a->s; - stbi__uint32 i,j,stride = x*out_n; - stbi__uint32 img_len, img_width_bytes; - int k; - int img_n = s->img_n; // copy it into a local for later - - STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc(x * y * out_n); // extra bytes to write off the end into - if (!a->out) return stbi__err("outofmem", "Out of memory"); - - img_width_bytes = (((img_n * x * depth) + 7) >> 3); - img_len = (img_width_bytes + 1) * y; - if (s->img_x == x && s->img_y == y) { - if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); - } else { // interlaced: - if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); - } - - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *prior = cur - stride; - int filter = *raw++; - int filter_bytes = img_n; - int width = x; - if (filter > 4) - return stbi__err("invalid filter","Corrupt PNG"); - - if (depth < 8) { - STBI_ASSERT(img_width_bytes <= x); - cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place - filter_bytes = 1; - width = img_width_bytes; - } - - // if first row, use special filter that doesn't sample previous row - if (j == 0) filter = first_row_filter[filter]; - - // handle first byte explicitly - for (k=0; k < filter_bytes; ++k) { - switch (filter) { - case STBI__F_none : cur[k] = raw[k]; break; - case STBI__F_sub : cur[k] = raw[k]; break; - case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; - case STBI__F_avg_first : cur[k] = raw[k]; break; - case STBI__F_paeth_first: cur[k] = raw[k]; break; - } - } - - if (depth == 8) { - if (img_n != out_n) - cur[img_n] = 255; // first pixel - raw += img_n; - cur += out_n; - prior += out_n; - } else { - raw += 1; - cur += 1; - prior += 1; - } - - // this is a little gross, so that we don't switch per-pixel or per-component - if (depth < 8 || img_n == out_n) { - int nk = (width - 1)*img_n; - #define CASE(f) \ - case f: \ - for (k=0; k < nk; ++k) - switch (filter) { - // "none" filter turns into a memcpy here; make that explicit. - case STBI__F_none: memcpy(cur, raw, nk); break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); break; - CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); break; - } - #undef CASE - raw += nk; - } else { - STBI_ASSERT(img_n+1 == out_n); - #define CASE(f) \ - case f: \ - for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ - for (k=0; k < img_n; ++k) - switch (filter) { - CASE(STBI__F_none) cur[k] = raw[k]; break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-out_n]); break; - CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-out_n])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-out_n] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],0,0)); break; - } - #undef CASE - } - } - - // we make a separate pass to expand bits to pixels; for performance, - // this could run two scanlines behind the above code, so it won't - // intefere with filtering but will still be in the cache. - if (depth < 8) { - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; - // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit - // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop - stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range - - // note that the final byte might overshoot and write more data than desired. - // we can allocate enough data that this never writes out of memory, but it - // could also overwrite the next scanline. can it overwrite non-empty data - // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. - // so we need to explicitly clamp the final ones - - if (depth == 4) { - for (k=x*img_n; k >= 2; k-=2, ++in) { - *cur++ = scale * ((*in >> 4) ); - *cur++ = scale * ((*in ) & 0x0f); - } - if (k > 0) *cur++ = scale * ((*in >> 4) ); - } else if (depth == 2) { - for (k=x*img_n; k >= 4; k-=4, ++in) { - *cur++ = scale * ((*in >> 6) ); - *cur++ = scale * ((*in >> 4) & 0x03); - *cur++ = scale * ((*in >> 2) & 0x03); - *cur++ = scale * ((*in ) & 0x03); - } - if (k > 0) *cur++ = scale * ((*in >> 6) ); - if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); - if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); - } else if (depth == 1) { - for (k=x*img_n; k >= 8; k-=8, ++in) { - *cur++ = scale * ((*in >> 7) ); - *cur++ = scale * ((*in >> 6) & 0x01); - *cur++ = scale * ((*in >> 5) & 0x01); - *cur++ = scale * ((*in >> 4) & 0x01); - *cur++ = scale * ((*in >> 3) & 0x01); - *cur++ = scale * ((*in >> 2) & 0x01); - *cur++ = scale * ((*in >> 1) & 0x01); - *cur++ = scale * ((*in ) & 0x01); - } - if (k > 0) *cur++ = scale * ((*in >> 7) ); - if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); - if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); - if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); - if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); - if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); - if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); - } - if (img_n != out_n) { - // insert alpha = 255 - stbi_uc *cur = a->out + stride*j; - int i; - if (img_n == 1) { - for (i=x-1; i >= 0; --i) { - cur[i*2+1] = 255; - cur[i*2+0] = cur[i]; - } - } else { - STBI_ASSERT(img_n == 3); - for (i=x-1; i >= 0; --i) { - cur[i*4+3] = 255; - cur[i*4+2] = cur[i*3+2]; - cur[i*4+1] = cur[i*3+1]; - cur[i*4+0] = cur[i*3+0]; - } - } - } - } - } - - return 1; -} - -static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) -{ - stbi_uc *final; - int p; - if (!interlaced) - return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); - - // de-interlacing - final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n); - for (p=0; p < 7; ++p) { - int xorig[] = { 0,4,0,2,0,1,0 }; - int yorig[] = { 0,0,4,0,2,0,1 }; - int xspc[] = { 8,8,4,4,2,2,1 }; - int yspc[] = { 8,8,8,4,4,2,2 }; - int i,j,x,y; - // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 - x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; - y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; - if (x && y) { - stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; - if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { - STBI_FREE(final); - return 0; - } - for (j=0; j < y; ++j) { - for (i=0; i < x; ++i) { - int out_y = j*yspc[p]+yorig[p]; - int out_x = i*xspc[p]+xorig[p]; - memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n, - a->out + (j*x+i)*out_n, out_n); - } - } - STBI_FREE(a->out); - image_data += img_len; - image_data_len -= img_len; - } - } - a->out = final; - - return 1; -} - -static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; - - // compute color-based transparency, assuming we've - // already got 255 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); - - if (out_n == 2) { - for (i=0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 255); - p += 2; - } - } else { - for (i=0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; -} - -static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) -{ - stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; - stbi_uc *p, *temp_out, *orig = a->out; - - p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n); - if (p == NULL) return stbi__err("outofmem", "Out of memory"); - - // between here and free(out) below, exitting would leak - temp_out = p; - - if (pal_img_n == 3) { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p += 3; - } - } else { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p[3] = palette[n+3]; - p += 4; - } - } - STBI_FREE(a->out); - a->out = temp_out; - - STBI_NOTUSED(len); - - return 1; -} - -static int stbi__unpremultiply_on_load = 0; -static int stbi__de_iphone_flag = 0; - -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) -{ - stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; -} - -STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag = flag_true_if_should_convert; -} - -static void stbi__de_iphone(stbi__png *z) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; - - if (s->img_out_n == 3) { // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 3; - } - } else { - STBI_ASSERT(s->img_out_n == 4); - if (stbi__unpremultiply_on_load) { - // convert bgr to rgb and unpremultiply - for (i=0; i < pixel_count; ++i) { - stbi_uc a = p[3]; - stbi_uc t = p[0]; - if (a) { - p[0] = p[2] * 255 / a; - p[1] = p[1] * 255 / a; - p[2] = t * 255 / a; - } else { - p[0] = p[2]; - p[2] = t; - } - p += 4; - } - } else { - // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 4; - } - } - } -} - -#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) - -static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) -{ - stbi_uc palette[1024], pal_img_n=0; - stbi_uc has_trans=0, tc[3]; - stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, color=0, depth=0, is_iphone=0; - stbi__context *s = z->s; - - z->expanded = NULL; - z->idata = NULL; - z->out = NULL; - - if (!stbi__check_png_header(s)) return 0; - - if (scan == STBI__SCAN_type) return 1; - - for (;;) { - stbi__pngchunk c = stbi__get_chunk_header(s); - switch (c.type) { - case STBI__PNG_TYPE('C','g','B','I'): - is_iphone = 1; - stbi__skip(s, c.length); - break; - case STBI__PNG_TYPE('I','H','D','R'): { - int comp,filter; - if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); - first = 0; - if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - depth = stbi__get8(s); if (depth != 1 && depth != 2 && depth != 4 && depth != 8) return stbi__err("1/2/4/8-bit only","PNG not supported: 1/2/4/8-bit only"); - color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); - comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); - filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); - interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); - if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); - if (!pal_img_n) { - s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; - } else { - // if paletted, then pal_n is our final components, and - // img_n is # components to decompress/filter. - s->img_n = 1; - if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS - } - break; - } - - case STBI__PNG_TYPE('P','L','T','E'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); - pal_len = c.length / 3; - if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); - for (i=0; i < pal_len; ++i) { - palette[i*4+0] = stbi__get8(s); - palette[i*4+1] = stbi__get8(s); - palette[i*4+2] = stbi__get8(s); - palette[i*4+3] = 255; - } - break; - } - - case STBI__PNG_TYPE('t','R','N','S'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); - if (pal_img_n) { - if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } - if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); - if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); - pal_img_n = 4; - for (i=0; i < c.length; ++i) - palette[i*4+3] = stbi__get8(s); - } else { - if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); - if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); - has_trans = 1; - for (k=0; k < s->img_n; ++k) - tc[k] = (stbi_uc) (stbi__get16be(s) & 255) * stbi__depth_scale_table[depth]; // non 8-bit images will be larger - } - break; - } - - case STBI__PNG_TYPE('I','D','A','T'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } - if (ioff + c.length > idata_limit) { - stbi_uc *p; - if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; - while (ioff + c.length > idata_limit) - idata_limit *= 2; - p = (stbi_uc *) STBI_REALLOC(z->idata, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); - z->idata = p; - } - if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); - ioff += c.length; - break; - } - - case STBI__PNG_TYPE('I','E','N','D'): { - stbi__uint32 raw_len, bpl; - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (scan != STBI__SCAN_load) return 1; - if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); - // initial guess for decoded data size to avoid unnecessary reallocs - bpl = (s->img_x * depth + 7) / 8; // bytes per line, per component - raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; - z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); - if (z->expanded == NULL) return 0; // zlib should set error - STBI_FREE(z->idata); z->idata = NULL; - if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) - s->img_out_n = s->img_n+1; - else - s->img_out_n = s->img_n; - if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, color, interlace)) return 0; - if (has_trans) - if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; - if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) - stbi__de_iphone(z); - if (pal_img_n) { - // pal_img_n == 3 or 4 - s->img_n = pal_img_n; // record the actual colors we had - s->img_out_n = pal_img_n; - if (req_comp >= 3) s->img_out_n = req_comp; - if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) - return 0; - } - STBI_FREE(z->expanded); z->expanded = NULL; - return 1; - } - - default: - // if critical, fail - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if ((c.type & (1 << 29)) == 0) { - #ifndef STBI_NO_FAILURE_STRINGS - // not threadsafe - static char invalid_chunk[] = "XXXX PNG chunk not known"; - invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); - invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); - invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); - invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); - #endif - return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); - } - stbi__skip(s, c.length); - break; - } - // end of PNG chunk, read and skip CRC - stbi__get32be(s); - } -} - -static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp) -{ - unsigned char *result=NULL; - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - result = p->out; - p->out = NULL; - if (req_comp && req_comp != p->s->img_out_n) { - result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - p->s->img_out_n = req_comp; - if (result == NULL) return result; - } - *x = p->s->img_x; - *y = p->s->img_y; - if (n) *n = p->s->img_out_n; - } - STBI_FREE(p->out); p->out = NULL; - STBI_FREE(p->expanded); p->expanded = NULL; - STBI_FREE(p->idata); p->idata = NULL; - - return result; -} - -static unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__png p; - p.s = s; - return stbi__do_png(&p, x,y,comp,req_comp); -} - -static int stbi__png_test(stbi__context *s) -{ - int r; - r = stbi__check_png_header(s); - stbi__rewind(s); - return r; -} - -static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) -{ - if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { - stbi__rewind( p->s ); - return 0; - } - if (x) *x = p->s->img_x; - if (y) *y = p->s->img_y; - if (comp) *comp = p->s->img_n; - return 1; -} - -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__png p; - p.s = s; - return stbi__png_info_raw(&p, x, y, comp); -} -#endif - -// Microsoft/Windows BMP image - -#ifndef STBI_NO_BMP -static int stbi__bmp_test_raw(stbi__context *s) -{ - int r; - int sz; - if (stbi__get8(s) != 'B') return 0; - if (stbi__get8(s) != 'M') return 0; - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - stbi__get32le(s); // discard data offset - sz = stbi__get32le(s); - r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); - return r; -} - -static int stbi__bmp_test(stbi__context *s) -{ - int r = stbi__bmp_test_raw(s); - stbi__rewind(s); - return r; -} - - -// returns 0..31 for the highest set bit -static int stbi__high_bit(unsigned int z) -{ - int n=0; - if (z == 0) return -1; - if (z >= 0x10000) n += 16, z >>= 16; - if (z >= 0x00100) n += 8, z >>= 8; - if (z >= 0x00010) n += 4, z >>= 4; - if (z >= 0x00004) n += 2, z >>= 2; - if (z >= 0x00002) n += 1, z >>= 1; - return n; -} - -static int stbi__bitcount(unsigned int a) -{ - a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 - a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits - a = (a + (a >> 8)); // max 16 per 8 bits - a = (a + (a >> 16)); // max 32 per 8 bits - return a & 0xff; -} - -static int stbi__shiftsigned(int v, int shift, int bits) -{ - int result; - int z=0; - - if (shift < 0) v <<= -shift; - else v >>= shift; - result = v; - - z = bits; - while (z < 8) { - result += v >> z; - z += bits; - } - return result; -} - -static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi_uc *out; - unsigned int mr=0,mg=0,mb=0,ma=0, fake_a=0; - stbi_uc pal[256][4]; - int psize=0,i,j,compress=0,width; - int bpp, flip_vertically, pad, target, offset, hsz; - if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - offset = stbi__get32le(s); - hsz = stbi__get32le(s); - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); - if (hsz == 12) { - s->img_x = stbi__get16le(s); - s->img_y = stbi__get16le(s); - } else { - s->img_x = stbi__get32le(s); - s->img_y = stbi__get32le(s); - } - if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); - bpp = stbi__get16le(s); - if (bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); - flip_vertically = ((int) s->img_y) > 0; - s->img_y = abs((int) s->img_y); - if (hsz == 12) { - if (bpp < 24) - psize = (offset - 14 - 24) / 3; - } else { - compress = stbi__get32le(s); - if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); - stbi__get32le(s); // discard sizeof - stbi__get32le(s); // discard hres - stbi__get32le(s); // discard vres - stbi__get32le(s); // discard colorsused - stbi__get32le(s); // discard max important - if (hsz == 40 || hsz == 56) { - if (hsz == 56) { - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - } - if (bpp == 16 || bpp == 32) { - mr = mg = mb = 0; - if (compress == 0) { - if (bpp == 32) { - mr = 0xffu << 16; - mg = 0xffu << 8; - mb = 0xffu << 0; - ma = 0xffu << 24; - fake_a = 1; // @TODO: check for cases like alpha value is all 0 and switch it to 255 - STBI_NOTUSED(fake_a); - } else { - mr = 31u << 10; - mg = 31u << 5; - mb = 31u << 0; - } - } else if (compress == 3) { - mr = stbi__get32le(s); - mg = stbi__get32le(s); - mb = stbi__get32le(s); - // not documented, but generated by photoshop and handled by mspaint - if (mr == mg && mg == mb) { - // ?!?!? - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else { - STBI_ASSERT(hsz == 108 || hsz == 124); - mr = stbi__get32le(s); - mg = stbi__get32le(s); - mb = stbi__get32le(s); - ma = stbi__get32le(s); - stbi__get32le(s); // discard color space - for (i=0; i < 12; ++i) - stbi__get32le(s); // discard color space parameters - if (hsz == 124) { - stbi__get32le(s); // discard rendering intent - stbi__get32le(s); // discard offset of profile data - stbi__get32le(s); // discard size of profile data - stbi__get32le(s); // discard reserved - } - } - if (bpp < 16) - psize = (offset - 14 - hsz) >> 2; - } - s->img_n = ma ? 4 : 3; - if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 - target = req_comp; - else - target = s->img_n; // if they want monochrome, we'll post-convert - out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - if (bpp < 16) { - int z=0; - if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } - for (i=0; i < psize; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - if (hsz != 12) stbi__get8(s); - pal[i][3] = 255; - } - stbi__skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); - if (bpp == 4) width = (s->img_x + 1) >> 1; - else if (bpp == 8) width = s->img_x; - else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } - pad = (-width)&3; - for (j=0; j < (int) s->img_y; ++j) { - for (i=0; i < (int) s->img_x; i += 2) { - int v=stbi__get8(s),v2=0; - if (bpp == 4) { - v2 = v & 15; - v >>= 4; - } - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - v = (bpp == 8) ? stbi__get8(s) : v2; - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - } - stbi__skip(s, pad); - } - } else { - int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; - int z = 0; - int easy=0; - stbi__skip(s, offset - 14 - hsz); - if (bpp == 24) width = 3 * s->img_x; - else if (bpp == 16) width = 2*s->img_x; - else /* bpp = 32 and pad = 0 */ width=0; - pad = (-width) & 3; - if (bpp == 24) { - easy = 1; - } else if (bpp == 32) { - if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) - easy = 2; - } - if (!easy) { - if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } - // right shift amt to put high bit in position #7 - rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); - gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); - bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); - ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); - } - for (j=0; j < (int) s->img_y; ++j) { - if (easy) { - for (i=0; i < (int) s->img_x; ++i) { - unsigned char a; - out[z+2] = stbi__get8(s); - out[z+1] = stbi__get8(s); - out[z+0] = stbi__get8(s); - z += 3; - a = (easy == 2 ? stbi__get8(s) : 255); - if (target == 4) out[z++] = a; - } - } else { - for (i=0; i < (int) s->img_x; ++i) { - stbi__uint32 v = (stbi__uint32) (bpp == 16 ? stbi__get16le(s) : stbi__get32le(s)); - int a; - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); - a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); - if (target == 4) out[z++] = STBI__BYTECAST(a); - } - } - stbi__skip(s, pad); - } - } - if (flip_vertically) { - stbi_uc t; - for (j=0; j < (int) s->img_y>>1; ++j) { - stbi_uc *p1 = out + j *s->img_x*target; - stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; - for (i=0; i < (int) s->img_x*target; ++i) { - t = p1[i], p1[i] = p2[i], p2[i] = t; - } - } - } - - if (req_comp && req_comp != target) { - out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; - return out; -} -#endif - -// Targa Truevision - TGA -// by Jonathan Dummer -#ifndef STBI_NO_TGA -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) -{ - int tga_w, tga_h, tga_comp; - int sz; - stbi__get8(s); // discard Offset - sz = stbi__get8(s); // color type - if( sz > 1 ) { - stbi__rewind(s); - return 0; // only RGB or indexed allowed - } - sz = stbi__get8(s); // image type - // only RGB or grey allowed, +/- RLE - if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; - stbi__skip(s,9); - tga_w = stbi__get16le(s); - if( tga_w < 1 ) { - stbi__rewind(s); - return 0; // test width - } - tga_h = stbi__get16le(s); - if( tga_h < 1 ) { - stbi__rewind(s); - return 0; // test height - } - sz = stbi__get8(s); // bits per pixel - // only RGB or RGBA or grey allowed - if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) { - stbi__rewind(s); - return 0; - } - tga_comp = sz; - if (x) *x = tga_w; - if (y) *y = tga_h; - if (comp) *comp = tga_comp / 8; - return 1; // seems to have passed everything -} - -static int stbi__tga_test(stbi__context *s) -{ - int res; - int sz; - stbi__get8(s); // discard Offset - sz = stbi__get8(s); // color type - if ( sz > 1 ) return 0; // only RGB or indexed allowed - sz = stbi__get8(s); // image type - if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE - stbi__get16be(s); // discard palette start - stbi__get16be(s); // discard palette length - stbi__get8(s); // discard bits per palette color entry - stbi__get16be(s); // discard x origin - stbi__get16be(s); // discard y origin - if ( stbi__get16be(s) < 1 ) return 0; // test width - if ( stbi__get16be(s) < 1 ) return 0; // test height - sz = stbi__get8(s); // bits per pixel - if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) - res = 0; - else - res = 1; - stbi__rewind(s); - return res; -} - -static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - // read in the TGA header stuff - int tga_offset = stbi__get8(s); - int tga_indexed = stbi__get8(s); - int tga_image_type = stbi__get8(s); - int tga_is_RLE = 0; - int tga_palette_start = stbi__get16le(s); - int tga_palette_len = stbi__get16le(s); - int tga_palette_bits = stbi__get8(s); - int tga_x_origin = stbi__get16le(s); - int tga_y_origin = stbi__get16le(s); - int tga_width = stbi__get16le(s); - int tga_height = stbi__get16le(s); - int tga_bits_per_pixel = stbi__get8(s); - int tga_comp = tga_bits_per_pixel / 8; - int tga_inverted = stbi__get8(s); - // image data - unsigned char *tga_data; - unsigned char *tga_palette = NULL; - int i, j; - unsigned char raw_data[4]; - int RLE_count = 0; - int RLE_repeating = 0; - int read_next_pixel = 1; - - // do a tiny bit of precessing - if ( tga_image_type >= 8 ) - { - tga_image_type -= 8; - tga_is_RLE = 1; - } - /* int tga_alpha_bits = tga_inverted & 15; */ - tga_inverted = 1 - ((tga_inverted >> 5) & 1); - - // error check - if ( //(tga_indexed) || - (tga_width < 1) || (tga_height < 1) || - (tga_image_type < 1) || (tga_image_type > 3) || - ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) && - (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) - ) - { - return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA - } - - // If I'm paletted, then I'll use the number of bits from the palette - if ( tga_indexed ) - { - tga_comp = tga_palette_bits / 8; - } - - // tga info - *x = tga_width; - *y = tga_height; - if (comp) *comp = tga_comp; - - tga_data = (unsigned char*)stbi__malloc( tga_width * tga_height * tga_comp ); - if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); - - // skip to the data's starting position (offset usually = 0) - stbi__skip(s, tga_offset ); - - if ( !tga_indexed && !tga_is_RLE) { - for (i=0; i < tga_height; ++i) { - int y = tga_inverted ? tga_height -i - 1 : i; - stbi_uc *tga_row = tga_data + y*tga_width*tga_comp; - stbi__getn(s, tga_row, tga_width * tga_comp); - } - } else { - // do I need to load a palette? - if ( tga_indexed) - { - // any data to skip? (offset usually = 0) - stbi__skip(s, tga_palette_start ); - // load the palette - tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_palette_bits / 8 ); - if (!tga_palette) { - STBI_FREE(tga_data); - return stbi__errpuc("outofmem", "Out of memory"); - } - if (!stbi__getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { - STBI_FREE(tga_data); - STBI_FREE(tga_palette); - return stbi__errpuc("bad palette", "Corrupt TGA"); - } - } - // load the data - for (i=0; i < tga_width * tga_height; ++i) - { - // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? - if ( tga_is_RLE ) - { - if ( RLE_count == 0 ) - { - // yep, get the next byte as a RLE command - int RLE_cmd = stbi__get8(s); - RLE_count = 1 + (RLE_cmd & 127); - RLE_repeating = RLE_cmd >> 7; - read_next_pixel = 1; - } else if ( !RLE_repeating ) - { - read_next_pixel = 1; - } - } else - { - read_next_pixel = 1; - } - // OK, if I need to read a pixel, do it now - if ( read_next_pixel ) - { - // load however much data we did have - if ( tga_indexed ) - { - // read in 1 byte, then perform the lookup - int pal_idx = stbi__get8(s); - if ( pal_idx >= tga_palette_len ) - { - // invalid index - pal_idx = 0; - } - pal_idx *= tga_bits_per_pixel / 8; - for (j = 0; j*8 < tga_bits_per_pixel; ++j) - { - raw_data[j] = tga_palette[pal_idx+j]; - } - } else - { - // read in the data raw - for (j = 0; j*8 < tga_bits_per_pixel; ++j) - { - raw_data[j] = stbi__get8(s); - } - } - // clear the reading flag for the next pixel - read_next_pixel = 0; - } // end of reading a pixel - - // copy data - for (j = 0; j < tga_comp; ++j) - tga_data[i*tga_comp+j] = raw_data[j]; - - // in case we're in RLE mode, keep counting down - --RLE_count; - } - // do I need to invert the image? - if ( tga_inverted ) - { - for (j = 0; j*2 < tga_height; ++j) - { - int index1 = j * tga_width * tga_comp; - int index2 = (tga_height - 1 - j) * tga_width * tga_comp; - for (i = tga_width * tga_comp; i > 0; --i) - { - unsigned char temp = tga_data[index1]; - tga_data[index1] = tga_data[index2]; - tga_data[index2] = temp; - ++index1; - ++index2; - } - } - } - // clear my palette, if I had one - if ( tga_palette != NULL ) - { - STBI_FREE( tga_palette ); - } - } - - // swap RGB - if (tga_comp >= 3) - { - unsigned char* tga_pixel = tga_data; - for (i=0; i < tga_width * tga_height; ++i) - { - unsigned char temp = tga_pixel[0]; - tga_pixel[0] = tga_pixel[2]; - tga_pixel[2] = temp; - tga_pixel += tga_comp; - } - } - - // convert to target component count - if (req_comp && req_comp != tga_comp) - tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); - - // the things I do to get rid of an error message, and yet keep - // Microsoft's C compilers happy... [8^( - tga_palette_start = tga_palette_len = tga_palette_bits = - tga_x_origin = tga_y_origin = 0; - // OK, done - return tga_data; -} -#endif - -// ************************************************************************************************* -// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB - -#ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s) -{ - int r = (stbi__get32be(s) == 0x38425053); - stbi__rewind(s); - return r; -} - -static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - int pixelCount; - int channelCount, compression; - int channel, i, count, len; - int w,h; - stbi_uc *out; - - // Check identifier - if (stbi__get32be(s) != 0x38425053) // "8BPS" - return stbi__errpuc("not PSD", "Corrupt PSD image"); - - // Check file type version. - if (stbi__get16be(s) != 1) - return stbi__errpuc("wrong version", "Unsupported version of PSD image"); - - // Skip 6 reserved bytes. - stbi__skip(s, 6 ); - - // Read the number of channels (R, G, B, A, etc). - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) - return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); - - // Read the rows and columns of the image. - h = stbi__get32be(s); - w = stbi__get32be(s); - - // Make sure the depth is 8 bits. - if (stbi__get16be(s) != 8) - return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 bit"); - - // Make sure the color mode is RGB. - // Valid options are: - // 0: Bitmap - // 1: Grayscale - // 2: Indexed color - // 3: RGB color - // 4: CMYK color - // 7: Multichannel - // 8: Duotone - // 9: Lab color - if (stbi__get16be(s) != 3) - return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); - - // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) - stbi__skip(s,stbi__get32be(s) ); - - // Skip the image resources. (resolution, pen tool paths, etc) - stbi__skip(s, stbi__get32be(s) ); - - // Skip the reserved data. - stbi__skip(s, stbi__get32be(s) ); - - // Find out if the data is compressed. - // Known values: - // 0: no compression - // 1: RLE compressed - compression = stbi__get16be(s); - if (compression > 1) - return stbi__errpuc("bad compression", "PSD has an unknown compression format"); - - // Create the destination image. - out = (stbi_uc *) stbi__malloc(4 * w*h); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - pixelCount = w*h; - - // Initialize the data to zero. - //memset( out, 0, pixelCount * 4 ); - - // Finally, the image data. - if (compression) { - // RLE as used by .PSD and .TIFF - // Loop until you get the number of unpacked bytes you are expecting: - // Read the next source byte into n. - // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. - // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. - // Else if n is 128, noop. - // Endloop - - // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, - // which we're going to just skip. - stbi__skip(s, h * channelCount * 2 ); - - // Read the RLE data by channel. - for (channel = 0; channel < 4; channel++) { - stbi_uc *p; - - p = out+channel; - if (channel >= channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++) *p = (channel == 3 ? 255 : 0), p += 4; - } else { - // Read the RLE data. - count = 0; - while (count < pixelCount) { - len = stbi__get8(s); - if (len == 128) { - // No-op. - } else if (len < 128) { - // Copy next len+1 bytes literally. - len++; - count += len; - while (len) { - *p = stbi__get8(s); - p += 4; - len--; - } - } else if (len > 128) { - stbi_uc val; - // Next -len+1 bytes in the dest are replicated from next source byte. - // (Interpret len as a negative 8-bit int.) - len ^= 0x0FF; - len += 2; - val = stbi__get8(s); - count += len; - while (len) { - *p = val; - p += 4; - len--; - } - } - } - } - } - - } else { - // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) - // where each channel consists of an 8-bit value for each pixel in the image. - - // Read the data by channel. - for (channel = 0; channel < 4; channel++) { - stbi_uc *p; - - p = out + channel; - if (channel > channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++) *p = channel == 3 ? 255 : 0, p += 4; - } else { - // Read the data. - for (i = 0; i < pixelCount; i++) - *p = stbi__get8(s), p += 4; - } - } - } - - if (req_comp && req_comp != 4) { - out = stbi__convert_format(out, 4, req_comp, w, h); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - - if (comp) *comp = channelCount; - *y = h; - *x = w; - - return out; -} -#endif - -// ************************************************************************************************* -// Softimage PIC loader -// by Tom Seddon -// -// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format -// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ - -#ifndef STBI_NO_PIC -static int stbi__pic_is4(stbi__context *s,const char *str) -{ - int i; - for (i=0; i<4; ++i) - if (stbi__get8(s) != (stbi_uc)str[i]) - return 0; - - return 1; -} - -static int stbi__pic_test_core(stbi__context *s) -{ - int i; - - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) - return 0; - - for(i=0;i<84;++i) - stbi__get8(s); - - if (!stbi__pic_is4(s,"PICT")) - return 0; - - return 1; -} - -typedef struct -{ - stbi_uc size,type,channel; -} stbi__pic_packet; - -static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) -{ - int mask=0x80, i; - - for (i=0; i<4; ++i, mask>>=1) { - if (channel & mask) { - if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); - dest[i]=stbi__get8(s); - } - } - - return dest; -} - -static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) -{ - int mask=0x80,i; - - for (i=0;i<4; ++i, mask>>=1) - if (channel&mask) - dest[i]=src[i]; -} - -static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) -{ - int act_comp=0,num_packets=0,y,chained; - stbi__pic_packet packets[10]; - - // this will (should...) cater for even some bizarre stuff like having data - // for the same channel in multiple packets. - do { - stbi__pic_packet *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return stbi__errpuc("bad format","too many packets"); - - packet = &packets[num_packets++]; - - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); - - act_comp |= packet->channel; - - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); - if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); - } while (chained); - - *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? - - for(y=0; ytype) { - default: - return stbi__errpuc("bad format","packet has bad compression type"); - - case 0: {//uncompressed - int x; - - for(x=0;xchannel,dest)) - return 0; - break; - } - - case 1://Pure RLE - { - int left=width, i; - - while (left>0) { - stbi_uc count,value[4]; - - count=stbi__get8(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); - - if (count > left) - count = (stbi_uc) left; - - if (!stbi__readval(s,packet->channel,value)) return 0; - - for(i=0; ichannel,dest,value); - left -= count; - } - } - break; - - case 2: {//Mixed RLE - int left=width; - while (left>0) { - int count = stbi__get8(s), i; - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); - - if (count >= 128) { // Repeated - stbi_uc value[4]; - int i; - - if (count==128) - count = stbi__get16be(s); - else - count -= 127; - if (count > left) - return stbi__errpuc("bad file","scanline overrun"); - - if (!stbi__readval(s,packet->channel,value)) - return 0; - - for(i=0;ichannel,dest,value); - } else { // Raw - ++count; - if (count>left) return stbi__errpuc("bad file","scanline overrun"); - - for(i=0;ichannel,dest)) - return 0; - } - left-=count; - } - break; - } - } - } - } - - return result; -} - -static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp) -{ - stbi_uc *result; - int i, x,y; - - for (i=0; i<92; ++i) - stbi__get8(s); - - x = stbi__get16be(s); - y = stbi__get16be(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); - if ((1 << 28) / x < y) return stbi__errpuc("too large", "Image too large to decode"); - - stbi__get32be(s); //skip `ratio' - stbi__get16be(s); //skip `fields' - stbi__get16be(s); //skip `pad' - - // intermediate buffer is RGBA - result = (stbi_uc *) stbi__malloc(x*y*4); - memset(result, 0xff, x*y*4); - - if (!stbi__pic_load_core(s,x,y,comp, result)) { - STBI_FREE(result); - result=0; - } - *px = x; - *py = y; - if (req_comp == 0) req_comp = *comp; - result=stbi__convert_format(result,4,req_comp,x,y); - - return result; -} - -static int stbi__pic_test(stbi__context *s) -{ - int r = stbi__pic_test_core(s); - stbi__rewind(s); - return r; -} -#endif - -// ************************************************************************************************* -// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb - -#ifndef STBI_NO_GIF -typedef struct -{ - stbi__int16 prefix; - stbi_uc first; - stbi_uc suffix; -} stbi__gif_lzw; - -typedef struct -{ - int w,h; - stbi_uc *out; // output buffer (always 4 components) - int flags, bgindex, ratio, transparent, eflags; - stbi_uc pal[256][4]; - stbi_uc lpal[256][4]; - stbi__gif_lzw codes[4096]; - stbi_uc *color_table; - int parse, step; - int lflags; - int start_x, start_y; - int max_x, max_y; - int cur_x, cur_y; - int line_size; -} stbi__gif; - -static int stbi__gif_test_raw(stbi__context *s) -{ - int sz; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; - sz = stbi__get8(s); - if (sz != '9' && sz != '7') return 0; - if (stbi__get8(s) != 'a') return 0; - return 1; -} - -static int stbi__gif_test(stbi__context *s) -{ - int r = stbi__gif_test_raw(s); - stbi__rewind(s); - return r; -} - -static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) -{ - int i; - for (i=0; i < num_entries; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - pal[i][3] = transp == i ? 0 : 255; - } -} - -static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) -{ - stbi_uc version; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') - return stbi__err("not GIF", "Corrupt GIF"); - - version = stbi__get8(s); - if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); - if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); - - stbi__g_failure_reason = ""; - g->w = stbi__get16le(s); - g->h = stbi__get16le(s); - g->flags = stbi__get8(s); - g->bgindex = stbi__get8(s); - g->ratio = stbi__get8(s); - g->transparent = -1; - - if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments - - if (is_info) return 1; - - if (g->flags & 0x80) - stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); - - return 1; -} - -static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__gif g; - if (!stbi__gif_header(s, &g, comp, 1)) { - stbi__rewind( s ); - return 0; - } - if (x) *x = g.w; - if (y) *y = g.h; - return 1; -} - -static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) -{ - stbi_uc *p, *c; - - // recurse to decode the prefixes, since the linked-list is backwards, - // and working backwards through an interleaved image would be nasty - if (g->codes[code].prefix >= 0) - stbi__out_gif_code(g, g->codes[code].prefix); - - if (g->cur_y >= g->max_y) return; - - p = &g->out[g->cur_x + g->cur_y]; - c = &g->color_table[g->codes[code].suffix * 4]; - - if (c[3] >= 128) { - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = c[3]; - } - g->cur_x += 4; - - if (g->cur_x >= g->max_x) { - g->cur_x = g->start_x; - g->cur_y += g->step; - - while (g->cur_y >= g->max_y && g->parse > 0) { - g->step = (1 << g->parse) * g->line_size; - g->cur_y = g->start_y + (g->step >> 1); - --g->parse; - } - } -} - -static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) -{ - stbi_uc lzw_cs; - stbi__int32 len, code; - stbi__uint32 first; - stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; - stbi__gif_lzw *p; - - lzw_cs = stbi__get8(s); - clear = 1 << lzw_cs; - first = 1; - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - bits = 0; - valid_bits = 0; - for (code = 0; code < clear; code++) { - g->codes[code].prefix = -1; - g->codes[code].first = (stbi_uc) code; - g->codes[code].suffix = (stbi_uc) code; - } - - // support no starting clear code - avail = clear+2; - oldcode = -1; - - len = 0; - for(;;) { - if (valid_bits < codesize) { - if (len == 0) { - len = stbi__get8(s); // start new block - if (len == 0) - return g->out; - } - --len; - bits |= (stbi__int32) stbi__get8(s) << valid_bits; - valid_bits += 8; - } else { - stbi__int32 code = bits & codemask; - bits >>= codesize; - valid_bits -= codesize; - // @OPTIMIZE: is there some way we can accelerate the non-clear path? - if (code == clear) { // clear code - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - avail = clear + 2; - oldcode = -1; - first = 0; - } else if (code == clear + 1) { // end of stream code - stbi__skip(s, len); - while ((len = stbi__get8(s)) > 0) - stbi__skip(s,len); - return g->out; - } else if (code <= avail) { - if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); - - if (oldcode >= 0) { - p = &g->codes[avail++]; - if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF"); - p->prefix = (stbi__int16) oldcode; - p->first = g->codes[oldcode].first; - p->suffix = (code == avail) ? p->first : g->codes[code].first; - } else if (code == avail) - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - - stbi__out_gif_code(g, (stbi__uint16) code); - - if ((avail & codemask) == 0 && avail <= 0x0FFF) { - codesize++; - codemask = (1 << codesize) - 1; - } - - oldcode = code; - } else { - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - } - } - } -} - -static void stbi__fill_gif_background(stbi__gif *g) -{ - int i; - stbi_uc *c = g->pal[g->bgindex]; - // @OPTIMIZE: write a dword at a time - for (i = 0; i < g->w * g->h * 4; i += 4) { - stbi_uc *p = &g->out[i]; - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = c[3]; - } -} - -// this function is designed to support animated gifs, although stb_image doesn't support it -static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp) -{ - int i; - stbi_uc *old_out = 0; - - if (g->out == 0) { - if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header - g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); - stbi__fill_gif_background(g); - } else { - // animated-gif-only path - if (((g->eflags & 0x1C) >> 2) == 3) { - old_out = g->out; - g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); - memcpy(g->out, old_out, g->w*g->h*4); - } - } - - for (;;) { - switch (stbi__get8(s)) { - case 0x2C: /* Image Descriptor */ - { - stbi__int32 x, y, w, h; - stbi_uc *o; - - x = stbi__get16le(s); - y = stbi__get16le(s); - w = stbi__get16le(s); - h = stbi__get16le(s); - if (((x + w) > (g->w)) || ((y + h) > (g->h))) - return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); - - g->line_size = g->w * 4; - g->start_x = x * 4; - g->start_y = y * g->line_size; - g->max_x = g->start_x + w * 4; - g->max_y = g->start_y + h * g->line_size; - g->cur_x = g->start_x; - g->cur_y = g->start_y; - - g->lflags = stbi__get8(s); - - if (g->lflags & 0x40) { - g->step = 8 * g->line_size; // first interlaced spacing - g->parse = 3; - } else { - g->step = g->line_size; - g->parse = 0; - } - - if (g->lflags & 0x80) { - stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); - g->color_table = (stbi_uc *) g->lpal; - } else if (g->flags & 0x80) { - for (i=0; i < 256; ++i) // @OPTIMIZE: stbi__jpeg_reset only the previous transparent - g->pal[i][3] = 255; - if (g->transparent >= 0 && (g->eflags & 0x01)) - g->pal[g->transparent][3] = 0; - g->color_table = (stbi_uc *) g->pal; - } else - return stbi__errpuc("missing color table", "Corrupt GIF"); - - o = stbi__process_gif_raster(s, g); - if (o == NULL) return NULL; - - if (req_comp && req_comp != 4) - o = stbi__convert_format(o, 4, req_comp, g->w, g->h); - return o; - } - - case 0x21: // Comment Extension. - { - int len; - if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. - len = stbi__get8(s); - if (len == 4) { - g->eflags = stbi__get8(s); - stbi__get16le(s); // delay - g->transparent = stbi__get8(s); - } else { - stbi__skip(s, len); - break; - } - } - while ((len = stbi__get8(s)) != 0) - stbi__skip(s, len); - break; - } - - case 0x3B: // gif stream termination code - return (stbi_uc *) s; // using '1' causes warning on some compilers - - default: - return stbi__errpuc("unknown code", "Corrupt GIF"); - } - } -} - -static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi_uc *u = 0; - stbi__gif g; - memset(&g, 0, sizeof(g)); - - u = stbi__gif_load_next(s, &g, comp, req_comp); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker - if (u) { - *x = g.w; - *y = g.h; - } - - return u; -} - -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) -{ - return stbi__gif_info_raw(s,x,y,comp); -} -#endif - -// ************************************************************************************************* -// Radiance RGBE HDR loader -// originally by Nicolas Schulz -#ifndef STBI_NO_HDR -static int stbi__hdr_test_core(stbi__context *s) -{ - const char *signature = "#?RADIANCE\n"; - int i; - for (i=0; signature[i]; ++i) - if (stbi__get8(s) != signature[i]) - return 0; - return 1; -} - -static int stbi__hdr_test(stbi__context* s) -{ - int r = stbi__hdr_test_core(s); - stbi__rewind(s); - return r; -} - -#define STBI__HDR_BUFLEN 1024 -static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) -{ - int len=0; - char c = '\0'; - - c = (char) stbi__get8(z); - - while (!stbi__at_eof(z) && c != '\n') { - buffer[len++] = c; - if (len == STBI__HDR_BUFLEN-1) { - // flush to end of line - while (!stbi__at_eof(z) && stbi__get8(z) != '\n') - ; - break; - } - c = (char) stbi__get8(z); - } - - buffer[len] = 0; - return buffer; -} - -static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) -{ - if ( input[3] != 0 ) { - float f1; - // Exponent - f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); - if (req_comp <= 2) - output[0] = (input[0] + input[1] + input[2]) * f1 / 3; - else { - output[0] = input[0] * f1; - output[1] = input[1] * f1; - output[2] = input[2] * f1; - } - if (req_comp == 2) output[1] = 1; - if (req_comp == 4) output[3] = 1; - } else { - switch (req_comp) { - case 4: output[3] = 1; /* fallthrough */ - case 3: output[0] = output[1] = output[2] = 0; - break; - case 2: output[1] = 1; /* fallthrough */ - case 1: output[0] = 0; - break; - } - } -} - -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int width, height; - stbi_uc *scanline; - float *hdr_data; - int len; - unsigned char count, value; - int i, j, k, c1,c2, z; - - - // Check identifier - if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) - return stbi__errpf("not HDR", "Corrupt HDR image"); - - // Parse header - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); - - // Parse width and height - // can't use sscanf() if we're not using stdio! - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - height = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - width = (int) strtol(token, NULL, 10); - - *x = width; - *y = height; - - if (comp) *comp = 3; - if (req_comp == 0) req_comp = 3; - - // Read data - hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float)); - - // Load image data - // image data is stored as some number of sca - if ( width < 8 || width >= 32768) { - // Read flat data - for (j=0; j < height; ++j) { - for (i=0; i < width; ++i) { - stbi_uc rgbe[4]; - main_decode_loop: - stbi__getn(s, rgbe, 4); - stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); - } - } - } else { - // Read RLE-encoded data - scanline = NULL; - - for (j = 0; j < height; ++j) { - c1 = stbi__get8(s); - c2 = stbi__get8(s); - len = stbi__get8(s); - if (c1 != 2 || c2 != 2 || (len & 0x80)) { - // not run-length encoded, so we have to actually use THIS data as a decoded - // pixel (note this can't be a valid pixel--one of RGB must be >= 128) - stbi_uc rgbe[4]; - rgbe[0] = (stbi_uc) c1; - rgbe[1] = (stbi_uc) c2; - rgbe[2] = (stbi_uc) len; - rgbe[3] = (stbi_uc) stbi__get8(s); - stbi__hdr_convert(hdr_data, rgbe, req_comp); - i = 1; - j = 0; - STBI_FREE(scanline); - goto main_decode_loop; // yes, this makes no sense - } - len <<= 8; - len |= stbi__get8(s); - if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } - if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4); - - for (k = 0; k < 4; ++k) { - i = 0; - while (i < width) { - count = stbi__get8(s); - if (count > 128) { - // Run - value = stbi__get8(s); - count -= 128; - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = value; - } else { - // Dump - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = stbi__get8(s); - } - } - } - for (i=0; i < width; ++i) - stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); - } - STBI_FREE(scanline); - } - - return hdr_data; -} - -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - - if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) { - stbi__rewind( s ); - return 0; - } - - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) { - stbi__rewind( s ); - return 0; - } - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *y = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *x = (int) strtol(token, NULL, 10); - *comp = 3; - return 1; -} -#endif // STBI_NO_HDR - -#ifndef STBI_NO_BMP -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) -{ - int hsz; - if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') { - stbi__rewind( s ); - return 0; - } - stbi__skip(s,12); - hsz = stbi__get32le(s); - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) { - stbi__rewind( s ); - return 0; - } - if (hsz == 12) { - *x = stbi__get16le(s); - *y = stbi__get16le(s); - } else { - *x = stbi__get32le(s); - *y = stbi__get32le(s); - } - if (stbi__get16le(s) != 1) { - stbi__rewind( s ); - return 0; - } - *comp = stbi__get16le(s) / 8; - return 1; -} -#endif - -#ifndef STBI_NO_PSD -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) -{ - int channelCount; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - *y = stbi__get32be(s); - *x = stbi__get32be(s); - if (stbi__get16be(s) != 8) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 3) { - stbi__rewind( s ); - return 0; - } - *comp = 4; - return 1; -} -#endif - -#ifndef STBI_NO_PIC -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) -{ - int act_comp=0,num_packets=0,chained; - stbi__pic_packet packets[10]; - - stbi__skip(s, 92); - - *x = stbi__get16be(s); - *y = stbi__get16be(s); - if (stbi__at_eof(s)) return 0; - if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { - stbi__rewind( s ); - return 0; - } - - stbi__skip(s, 8); - - do { - stbi__pic_packet *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return 0; - - packet = &packets[num_packets++]; - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); - act_comp |= packet->channel; - - if (stbi__at_eof(s)) { - stbi__rewind( s ); - return 0; - } - if (packet->size != 8) { - stbi__rewind( s ); - return 0; - } - } while (chained); - - *comp = (act_comp & 0x10 ? 4 : 3); - - return 1; -} -#endif - -// ************************************************************************************************* -// Portable Gray Map and Portable Pixel Map loader -// by Ken Miller -// -// PGM: http://netpbm.sourceforge.net/doc/pgm.html -// PPM: http://netpbm.sourceforge.net/doc/ppm.html -// -// Known limitations: -// Does not support comments in the header section -// Does not support ASCII image data (formats P2 and P3) -// Does not support 16-bit-per-channel - -#ifndef STBI_NO_PNM - -static int stbi__pnm_test(stbi__context *s) -{ - char p, t; - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind( s ); - return 0; - } - return 1; -} - -static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi_uc *out; - if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) - return 0; - *x = s->img_x; - *y = s->img_y; - *comp = s->img_n; - - out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y); - - if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - return out; -} - -static int stbi__pnm_isspace(char c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; -} - -static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) -{ - while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) - *c = (char) stbi__get8(s); -} - -static int stbi__pnm_isdigit(char c) -{ - return c >= '0' && c <= '9'; -} - -static int stbi__pnm_getinteger(stbi__context *s, char *c) -{ - int value = 0; - - while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { - value = value*10 + (*c - '0'); - *c = (char) stbi__get8(s); - } - - return value; -} - -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) -{ - int maxv; - char c, p, t; - - stbi__rewind( s ); - - // Get identifier - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind( s ); - return 0; - } - - *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm - - c = (char) stbi__get8(s); - stbi__pnm_skip_whitespace(s, &c); - - *x = stbi__pnm_getinteger(s, &c); // read width - stbi__pnm_skip_whitespace(s, &c); - - *y = stbi__pnm_getinteger(s, &c); // read height - stbi__pnm_skip_whitespace(s, &c); - - maxv = stbi__pnm_getinteger(s, &c); // read max value - - if (maxv > 255) - return stbi__err("max value > 255", "PPM image not 8-bit"); - else - return 1; -} -#endif - -static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) -{ - #ifndef STBI_NO_JPEG - if (stbi__jpeg_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PNG - if (stbi__png_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_GIF - if (stbi__gif_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_BMP - if (stbi__bmp_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PSD - if (stbi__psd_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PIC - if (stbi__pic_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PNM - if (stbi__pnm_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_HDR - if (stbi__hdr_info(s, x, y, comp)) return 1; - #endif - - // test tga last because it's a crappy test! - #ifndef STBI_NO_TGA - if (stbi__tga_info(s, x, y, comp)) - return 1; - #endif - return stbi__err("unknown image type", "Image not of any known type, or corrupt"); -} - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_info_from_file(f, x, y, comp); - fclose(f); - return result; -} - -STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__info_main(&s,x,y,comp); - fseek(f,pos,SEEK_SET); - return r; -} -#endif // !STBI_NO_STDIO - -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__info_main(&s,x,y,comp); -} - -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__info_main(&s,x,y,comp); -} - -#endif // STB_IMAGE_IMPLEMENTATION - -/* - revision history: - 2.02 (2015-01-19) fix incorrect assert, fix warning - 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 - 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG - 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) - progressive JPEG (stb) - PGM/PPM support (Ken Miller) - STBI_MALLOC,STBI_REALLOC,STBI_FREE - GIF bugfix -- seemingly never worked - STBI_NO_*, STBI_ONLY_* - 1.48 (2014-12-14) fix incorrectly-named assert() - 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) - optimize PNG (ryg) - fix bug in interlaced PNG with user-specified channel count (stb) - 1.46 (2014-08-26) - fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG - 1.45 (2014-08-16) - fix MSVC-ARM internal compiler error by wrapping malloc - 1.44 (2014-08-07) - various warning fixes from Ronny Chevalier - 1.43 (2014-07-15) - fix MSVC-only compiler problem in code changed in 1.42 - 1.42 (2014-07-09) - don't define _CRT_SECURE_NO_WARNINGS (affects user code) - fixes to stbi__cleanup_jpeg path - added STBI_ASSERT to avoid requiring assert.h - 1.41 (2014-06-25) - fix search&replace from 1.36 that messed up comments/error messages - 1.40 (2014-06-22) - fix gcc struct-initialization warning - 1.39 (2014-06-15) - fix to TGA optimization when req_comp != number of components in TGA; - fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) - add support for BMP version 5 (more ignored fields) - 1.38 (2014-06-06) - suppress MSVC warnings on integer casts truncating values - fix accidental rename of 'skip' field of I/O - 1.37 (2014-06-04) - remove duplicate typedef - 1.36 (2014-06-03) - convert to header file single-file library - if de-iphone isn't set, load iphone images color-swapped instead of returning NULL - 1.35 (2014-05-27) - various warnings - fix broken STBI_SIMD path - fix bug where stbi_load_from_file no longer left file pointer in correct place - fix broken non-easy path for 32-bit BMP (possibly never used) - TGA optimization by Arseny Kapoulkine - 1.34 (unknown) - use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case - 1.33 (2011-07-14) - make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements - 1.32 (2011-07-13) - support for "info" function for all supported filetypes (SpartanJ) - 1.31 (2011-06-20) - a few more leak fixes, bug in PNG handling (SpartanJ) - 1.30 (2011-06-11) - added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) - removed deprecated format-specific test/load functions - removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway - error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) - fix inefficiency in decoding 32-bit BMP (David Woo) - 1.29 (2010-08-16) - various warning fixes from Aurelien Pocheville - 1.28 (2010-08-01) - fix bug in GIF palette transparency (SpartanJ) - 1.27 (2010-08-01) - cast-to-stbi_uc to fix warnings - 1.26 (2010-07-24) - fix bug in file buffering for PNG reported by SpartanJ - 1.25 (2010-07-17) - refix trans_data warning (Won Chun) - 1.24 (2010-07-12) - perf improvements reading from files on platforms with lock-heavy fgetc() - minor perf improvements for jpeg - deprecated type-specific functions so we'll get feedback if they're needed - attempt to fix trans_data warning (Won Chun) - 1.23 fixed bug in iPhone support - 1.22 (2010-07-10) - removed image *writing* support - stbi_info support from Jetro Lauha - GIF support from Jean-Marc Lienher - iPhone PNG-extensions from James Brown - warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) - 1.21 fix use of 'stbi_uc' in header (reported by jon blow) - 1.20 added support for Softimage PIC, by Tom Seddon - 1.19 bug in interlaced PNG corruption check (found by ryg) - 1.18 2008-08-02 - fix a threading bug (local mutable static) - 1.17 support interlaced PNG - 1.16 major bugfix - stbi__convert_format converted one too many pixels - 1.15 initialize some fields for thread safety - 1.14 fix threadsafe conversion bug - header-file-only version (#define STBI_HEADER_FILE_ONLY before including) - 1.13 threadsafe - 1.12 const qualifiers in the API - 1.11 Support installable IDCT, colorspace conversion routines - 1.10 Fixes for 64-bit (don't use "unsigned long") - optimized upsampling by Fabian "ryg" Giesen - 1.09 Fix format-conversion for PSD code (bad global variables!) - 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz - 1.07 attempt to fix C++ warning/errors again - 1.06 attempt to fix C++ warning/errors again - 1.05 fix TGA loading to return correct *comp and use good luminance calc - 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free - 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR - 1.02 support for (subset of) HDR files, float interface for preferred access to them - 1.01 fix bug: possible bug in handling right-side up bmps... not sure - fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all - 1.00 interface to zlib that skips zlib header - 0.99 correct handling of alpha in palette - 0.98 TGA loader by lonesock; dynamically add loaders (untested) - 0.97 jpeg errors on too large a file; also catch another malloc failure - 0.96 fix detection of invalid v value - particleman@mollyrocket forum - 0.95 during header scan, seek to markers in case of padding - 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same - 0.93 handle jpegtran output; verbose errors - 0.92 read 4,8,16,24,32-bit BMP files of several formats - 0.91 output 24-bit Windows 3.0 BMP files - 0.90 fix a few more warnings; bump version number to approach 1.0 - 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd - 0.60 fix compiling as c++ - 0.59 fix warnings: merge Dave Moore's -Wall fixes - 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian - 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available - 0.56 fix bug: zlib uncompressed mode len vs. nlen - 0.55 fix bug: restart_interval not initialized to 0 - 0.54 allow NULL for 'int *comp' - 0.53 fix bug in png 3->4; speedup png decoding - 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments - 0.51 obey req_comp requests, 1-component jpegs return as 1-component, - on 'test' only check type, not whether we support this variant - 0.50 first released version -*/ \ No newline at end of file diff --git a/vendor/stb_image.cpp b/vendor/stb_image.cpp new file mode 100644 index 0000000..e834e1e --- /dev/null +++ b/vendor/stb_image.cpp @@ -0,0 +1,4 @@ +#define STB_IMAGE_IMPLEMENTATION +#define STBI_ONLY_PNG +#define STBI_ONLY_BMP +#include "stb_image.h" diff --git a/vendor/stb_image.h b/vendor/stb_image.h new file mode 100644 index 0000000..cea66f5 --- /dev/null +++ b/vendor/stb_image.h @@ -0,0 +1,6326 @@ +/* stb_image - v2.02 - public domain image loader - http://nothings.org/stb_image.h + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8-bit-per-channel (16 bpc not supported) + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + + Revision 2.00 release notes: + + - Progressive JPEG is now supported. + + - PPM and PGM binary formats are now supported, thanks to Ken Miller. + + - x86 platforms now make use of SSE2 SIMD instructions for + JPEG decoding, and ARM platforms can use NEON SIMD if requested. + This work was done by Fabian "ryg" Giesen. SSE2 is used by + default, but NEON must be enabled explicitly; see docs. + + With other JPEG optimizations included in this version, we see + 2x speedup on a JPEG on an x86 machine, and a 1.5x speedup + on a JPEG on an ARM machine, relative to previous versions of this + library. The same results will not obtain for all JPGs and for all + x86/ARM machines. (Note that progressive JPEGs are significantly + slower to decode than regular JPEGs.) This doesn't mean that this + is the fastest JPEG decoder in the land; rather, it brings it + closer to parity with standard libraries. If you want the fastest + decode, look elsewhere. (See "Philosophy" section of docs below.) + + See final bullet items below for more info on SIMD. + + - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing + the memory allocator. Unlike other STBI libraries, these macros don't + support a context parameter, so if you need to pass a context in to + the allocator, you'll have to store it in a global or a thread-local + variable. + + - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and + STBI_NO_LINEAR. + STBI_NO_HDR: suppress implementation of .hdr reader format + STBI_NO_LINEAR: suppress high-dynamic-range light-linear float API + + - You can suppress implementation of any of the decoders to reduce + your code footprint by #defining one or more of the following + symbols before creating the implementation. + + STBI_NO_JPEG + STBI_NO_PNG + STBI_NO_BMP + STBI_NO_PSD + STBI_NO_TGA + STBI_NO_GIF + STBI_NO_HDR + STBI_NO_PIC + STBI_NO_PNM (.ppm and .pgm) + + - You can request *only* certain decoders and suppress all other ones + (this will be more forward-compatible, as addition of new decoders + doesn't require you to disable them explicitly): + + STBI_ONLY_JPEG + STBI_ONLY_PNG + STBI_ONLY_BMP + STBI_ONLY_PSD + STBI_ONLY_TGA + STBI_ONLY_GIF + STBI_ONLY_HDR + STBI_ONLY_PIC + STBI_ONLY_PNM (.ppm and .pgm) + + Note that you can define multiples of these, and you will get all + of them ("only x" and "only y" is interpreted to mean "only x&y"). + + - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still + want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB + + - Compilation of all SIMD code can be suppressed with + #define STBI_NO_SIMD + It should not be necessary to disable SIMD unless you have issues + compiling (e.g. using an x86 compiler which doesn't support SSE + intrinsics or that doesn't support the method used to detect + SSE2 support at run-time), and even those can be reported as + bugs so I can refine the built-in compile-time checking to be + smarter. + + - The old STBI_SIMD system which allowed installing a user-defined + IDCT etc. has been removed. If you need this, don't upgrade. My + assumption is that almost nobody was doing this, and those who + were will find the built-in SIMD more satisfactory anyway. + + - RGB values computed for JPEG images are slightly different from + previous versions of stb_image. (This is due to using less + integer precision in SIMD.) The C code has been adjusted so + that the same RGB values will be computed regardless of whether + SIMD support is available, so your app should always produce + consistent results. But these results are slightly different from + previous versions. (Specifically, about 3% of available YCbCr values + will compute different RGB results from pre-1.49 versions by +-1; + most of the deviating values are one smaller in the G channel.) + + - If you must produce consistent results with previous versions of + stb_image, #define STBI_JPEG_OLD and you will get the same results + you used to; however, you will not get the SIMD speedups for + the YCbCr-to-RGB conversion step (although you should still see + significant JPEG speedup from the other changes). + + Please note that STBI_JPEG_OLD is a temporary feature; it will be + removed in future versions of the library. It is only intended for + near-term back-compatibility use. + + + Latest revision history: + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD + progressive JPEG + PGM/PPM support + STBI_MALLOC,STBI_REALLOC,STBI_FREE + STBI_NO_*, STBI_ONLY_* + GIF bugfix + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted) + optimize PNG + fix bug in interlaced PNG with user-specified channel count + 1.46 (2014-08-26) fix broken tRNS chunk in non-paletted PNG + 1.45 (2014-08-16) workaround MSVC-ARM internal compiler error by wrapping malloc + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Bug fixes & warning fixes + Sean Barrett (jpeg, png, bmp) Marc LeBlanc + Nicolas Schulz (hdr, psd) Christpher Lloyd + Jonathan Dummer (tga) Dave Moore + Jean-Marc Lienher (gif) Won Chun + Tom Seddon (pic) the Horde3D community + Thatcher Ulrich (psd) Janez Zemva + Ken Miller (pgm, ppm) Jonathan Blow + Laurent Gomila + Aruelien Pocheville + Extensions, features Ryamond Barbiero + Jetro Lauha (stbi_info) David Woo + Martin "SpartanJ" Golini (stbi_info) Martin Golini + James "moose2000" Brown (iPhone PNG) Roy Eltham + Ben "Disch" Wenger (io callbacks) Luke Graham + Omar Cornut (1/2/4-bit PNG) Thomas Ruf + John Bartholomew + Ken Hamada + Optimizations & bugfixes Cort Stratton + Fabian "ryg" Giesen Blazej Dariusz Roszkowski + Arseny Kapoulkine Thibault Reuille + Paul Du Bois + Guillaume George + If your name should be here but Jerry Jansson + isn't, let Sean know. Hayaki Saito + Johan Duparc + Ronny Chevalier + Michal Cichon + Tero Hanninen + Sergio Gonzalez + Cass Everitt + Engin Manap + +License: + This software is in the public domain. Where that dedication is not + recognized, you are granted a perpetual, irrevocable license to copy + and modify this file however you want. + +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 16-bit-per-channel PNG +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - no 1-bit BMP +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *comp -- outputs # of image components in image file +// int req_comp -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. +// If req_comp is non-zero, *comp has the number of components that _would_ +// have been output otherwise. E.g. if you set req_comp to 4, you will always +// get RGBA output, but you can check *comp to see if it's trivially opaque +// because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *comp will be unchanged. The function stbi_failure_reason() +// can be queried for an extremely brief, end-user unfriendly explanation +// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid +// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy to use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// make more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// The output of the JPEG decoder is slightly different from versions where +// SIMD support was introduced (that is, for versions before 1.49). The +// difference is only +-1 in the 8-bit RGB channels, and only on a small +// fraction of pixels. You can force the pre-1.49 behavior by defining +// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path +// and hence cost some performance. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image now supports loading HDR images in general, and currently +// the Radiance .HDR file format, although the support is provided +// generically. You can still load any file through the existing interface; +// if you attempt to load an HDR file, it will be automatically remapped to +// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// By default we convert iphone-formatted PNGs back to RGB, even though +// they are internally encoded differently. You can disable this conversion +// by by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through (which +// is BGR stored in RGB). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// + + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for req_comp + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +typedef unsigned char stbi_uc; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *comp, int req_comp); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_HDR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// NOT THREADSAFE +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); + +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,sz) realloc(p,sz) +#define STBI_FREE(p) free(p) +#endif + +#if defined(__GNUC__) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// (but compiling with -msse2 allows the compiler to use SSE2 everywhere; +// this is just broken and gcc are jerks for not fixing it properly +// http://www.virtualdub.org/blog/pivot/entry.php?id=363 ) +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +static int stbi__sse2_available() +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +static int stbi__sse2_available() +{ +#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later + // GCC 4.8+ has a nice way to do this + return __builtin_cpu_supports("sse2"); +#else + // portable way to do this, preferably without using GCC inline ASM? + // just bail for now. + return 0; +#endif +} +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +// assume GCC or Clang on ARM targets +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + fseek((FILE*) user, n, SEEK_CUR); +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; +} + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +// this is not threadsafe +static const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static unsigned char *stbi_load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +#ifndef STBI_NO_STDIO + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi_load_main(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} +#endif //!STBI_NO_STDIO + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi_load_main(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi_load_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_LINEAR +static float *stbi_loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) + return stbi__hdr_load(s,x,y,comp,req_comp); + #endif + data = stbi_load_main(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi_loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi_loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi_loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_file(&s,f); + return stbi__hdr_test(&s); + #else + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + return 0; + #endif +} + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +#ifndef STBI_NO_LINEAR +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} + +static void stbi__skip(stbi__context *s, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} + +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} + +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} + +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} + +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} + +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + return z + (stbi__get16le(s) << 16); +} + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + + +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc(req_comp * x * y); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define COMBO(a,b) ((a)*8+(b)) + #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (COMBO(img_n, req_comp)) { + CASE(1,2) dest[0]=src[0], dest[1]=255; break; + CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; + CASE(2,1) dest[0]=src[0]; break; + CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; + CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; + CASE(3,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; + CASE(3,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; break; + CASE(4,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; + CASE(4,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; + CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; + default: STBI_ASSERT(0); + } + #undef CASE + } + + STBI_FREE(data); + return good; +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output = (float *) stbi__malloc(x * y * comp * sizeof(float)); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi_uc dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0,code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (stbi_uc) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (-1 << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & ~sgn); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc << j->succ_low); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else + r = 16; // r=15 is the code for 16 0s + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + ++k; + } else { + if (r == 0) { + if (s) + data[stbi__jpeg_dezigzag[k++]] = (short) s; + break; + } + --r; + ++k; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) << 12) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0] << 2; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4; + int t = q & 15,i; + if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s); + L -= 65; + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + stbi__skip(z->s, stbi__get16be(z->s)-2); + return 1; + } + return 0; +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + c = stbi__get8(s); + if (c != 3 && c != 1) return stbi__err("bad component count","Corrupt JPEG"); // JFIF requires + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + for (i=0; i < s->img_n; ++i) { + z->img_comp[i].id = stbi__get8(s); + if (z->img_comp[i].id != i+1) // JFIF requires + if (z->img_comp[i].id != i) // some version of jpegtran outputs non-JFIF-compliant files! + return stbi__err("bad component ID","Corrupt JPEG"); + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); + + if (z->img_comp[i].raw_data == NULL) { + for(--i; i >= 0; --i) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].data = NULL; + } + return stbi__err("outofmem", "Out of memory"); + } + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + z->img_comp[i].linebuf = NULL; + if (z->progressive) { + z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3; + z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3; + z->img_comp[i].raw_coeff = STBI_MALLOC(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } else { + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } else if (x != 0) { + return stbi__err("junk before marker", "Corrupt JPEG"); + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +#ifdef STBI_JPEG_OLD +// this is the same YCbCr-to-RGB calculation that stb_image has used +// historically before the algorithm changes in 1.49 +#define float2fixed(x) ((int) ((x) * 65536 + 0.5)) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 16) + 32768; // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr*float2fixed(1.40200f); + g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); + b = y_fixed + cb*float2fixed(1.77200f); + r >>= 16; + g >>= 16; + b >>= 16; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#else +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* float2fixed(1.40200f); + g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* float2fixed(1.40200f); + g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + #ifndef STBI_JPEG_OLD + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + #endif + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + #ifndef STBI_JPEG_OLD + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + #endif + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + int i; + for (i=0; i < j->s->img_n; ++i) { + if (j->img_comp[i].raw_data) { + STBI_FREE(j->img_comp[i].raw_data); + j->img_comp[i].raw_data = NULL; + j->img_comp[i].data = NULL; + } + if (j->img_comp[i].raw_coeff) { + STBI_FREE(j->img_comp[i].raw_coeff); + j->img_comp[i].raw_coeff = 0; + j->img_comp[i].coeff = 0; + } + if (j->img_comp[i].linebuf) { + STBI_FREE(j->img_comp[i].linebuf); + j->img_comp[i].linebuf = NULL; + } + } +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n; + + if (z->s->img_n == 3 && n < 3) + decode_n = 1; + else + decode_n = z->s->img_n; + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4]; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n; // report original components, not output + return output; + } +} + +static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__jpeg j; + j.s = s; + stbi__setup_jpeg(&j); + return load_jpeg_image(&j, x,y,comp,req_comp); +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg j; + j.s = s; + stbi__setup_jpeg(&j); + r = stbi__decode_jpeg_header(&j, STBI__SCAN_type); + stbi__rewind(s); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__jpeg j; + j.s = s; + return stbi__jpeg_info_raw(&j, x, y, comp); +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[288]; + stbi__uint16 value[288]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + STBI_ASSERT(sizes[i] <= (1 << i)); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt JPEG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int k = stbi__bit_reverse(next_code[s],s); + while (k < (1 << STBI__ZFAST_BITS)) { + z->fast[k] = fastv; + k += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + if (z->zbuffer >= z->zbuffer_end) return 0; + return *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + z->code_buffer |= stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + STBI_ASSERT(z->size[b] == s); + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) stbi__fill_bits(a); + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + int cur, limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (int) (z->zout - z->zout_start); + limit = (int) (z->zout_end - z->zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *) STBI_REALLOC(z->zout_start, limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + do *zout++ = v; while (--len); + } else { + do *zout++ = *p++; while (--len); + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < hlit + hdist) { + int c = stbi__zhuffman_decode(a, &z_codelength); + STBI_ASSERT(c >= 0 && c < 19); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else if (c == 16) { + c = stbi__zreceive(a,2)+3; + memset(lencodes+n, lencodes[n-1], c); + n += c; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + memset(lencodes+n, 0, c); + n += c; + } else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a,7)+11; + memset(lencodes+n, 0, c); + n += c; + } + } + if (n != hlit+hdist) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncomperssed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + STBI_ASSERT(a->num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +// @TODO: should statically initialize these for optimal thread safety +static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32]; +static void stbi__init_zdefaults(void) +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncomperssed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zdefault_distance[31]) stbi__init_zdefaults(); + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc(x * y * out_n); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + if (s->img_x == x && s->img_y == y) { + if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); + } else { // interlaced: + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + } + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior = cur - stride; + int filter = *raw++; + int filter_bytes = img_n; + int width = x; + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + STBI_ASSERT(img_width_bytes <= x); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*img_n; + #define CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); break; + CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); break; + } + #undef CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ + for (k=0; k < img_n; ++k) + switch (filter) { + CASE(STBI__F_none) cur[k] = raw[k]; break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-out_n]); break; + CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-out_n])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-out_n] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],0,0)); break; + } + #undef CASE + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + // insert alpha = 255 + stbi_uc *cur = a->out + stride*j; + int i; + if (img_n == 1) { + for (i=x-1; i >= 0; --i) { + cur[i*2+1] = 255; + cur[i*2+0] = cur[i]; + } + } else { + STBI_ASSERT(img_n == 3); + for (i=x-1; i >= 0; --i) { + cur[i*4+3] = 255; + cur[i*4+2] = cur[i*3+2]; + cur[i*4+1] = cur[i*3+1]; + cur[i*4+0] = cur[i*3+0]; + } + } + } + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n, + a->out + (j*x+i)*out_n, out_n); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load = 0; +static int stbi__de_iphone_flag = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + p[0] = p[2] * 255 / a; + p[1] = p[1] * 255 / a; + p[2] = t * 255 / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, depth=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + depth = stbi__get8(s); if (depth != 1 && depth != 2 && depth != 4 && depth != 8) return stbi__err("1/2/4/8-bit only","PNG not supported: 1/2/4/8-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + for (k=0; k < s->img_n; ++k) + tc[k] = (stbi_uc) (stbi__get16be(s) & 255) * stbi__depth_scale_table[depth]; // non 8-bit images will be larger + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if (ioff + c.length > idata_limit) { + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + p = (stbi_uc *) STBI_REALLOC(z->idata, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, color, interlace)) return 0; + if (has_trans) + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } + STBI_FREE(z->expanded); z->expanded = NULL; + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp) +{ + unsigned char *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_out_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) n += 16, z >>= 16; + if (z >= 0x00100) n += 8, z >>= 8; + if (z >= 0x00010) n += 4, z >>= 4; + if (z >= 0x00004) n += 2, z >>= 2; + if (z >= 0x00002) n += 1, z >>= 1; + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +static int stbi__shiftsigned(int v, int shift, int bits) +{ + int result; + int z=0; + + if (shift < 0) v <<= -shift; + else v >>= shift; + result = v; + + z = bits; + while (z < 8) { + result += v >> z; + z += bits; + } + return result; +} + +static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, fake_a=0; + stbi_uc pal[256][4]; + int psize=0,i,j,compress=0,width; + int bpp, flip_vertically, pad, target, offset, hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + offset = stbi__get32le(s); + hsz = stbi__get32le(s); + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + bpp = stbi__get16le(s); + if (bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + if (hsz == 12) { + if (bpp < 24) + psize = (offset - 14 - 24) / 3; + } else { + compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (bpp == 16 || bpp == 32) { + mr = mg = mb = 0; + if (compress == 0) { + if (bpp == 32) { + mr = 0xffu << 16; + mg = 0xffu << 8; + mb = 0xffu << 0; + ma = 0xffu << 24; + fake_a = 1; // @TODO: check for cases like alpha value is all 0 and switch it to 255 + STBI_NOTUSED(fake_a); + } else { + mr = 31u << 10; + mg = 31u << 5; + mb = 31u << 0; + } + } else if (compress == 3) { + mr = stbi__get32le(s); + mg = stbi__get32le(s); + mb = stbi__get32le(s); + // not documented, but generated by photoshop and handled by mspaint + if (mr == mg && mg == mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + STBI_ASSERT(hsz == 108 || hsz == 124); + mr = stbi__get32le(s); + mg = stbi__get32le(s); + mb = stbi__get32le(s); + ma = stbi__get32le(s); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + if (bpp < 16) + psize = (offset - 14 - hsz) >> 2; + } + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); + if (bpp == 4) width = (s->img_x + 1) >> 1; + else if (bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, offset - 14 - hsz); + if (bpp == 24) width = 3 * s->img_x; + else if (bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (bpp == 24) { + easy = 1; + } else if (bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + if (target == 4) out[z++] = a; + } + } else { + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (stbi__uint32) (bpp == 16 ? stbi__get16le(s) : stbi__get32le(s)); + int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i], p1[i] = p2[i], p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp; + int sz; + stbi__get8(s); // discard Offset + sz = stbi__get8(s); // color type + if( sz > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + sz = stbi__get8(s); // image type + // only RGB or grey allowed, +/- RLE + if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; + stbi__skip(s,9); + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + sz = stbi__get8(s); // bits per pixel + // only RGB or RGBA or grey allowed + if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) { + stbi__rewind(s); + return 0; + } + tga_comp = sz; + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp / 8; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res; + int sz; + stbi__get8(s); // discard Offset + sz = stbi__get8(s); // color type + if ( sz > 1 ) return 0; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE + stbi__get16be(s); // discard palette start + stbi__get16be(s); // discard palette length + stbi__get8(s); // discard bits per palette color entry + stbi__get16be(s); // discard x origin + stbi__get16be(s); // discard y origin + if ( stbi__get16be(s) < 1 ) return 0; // test width + if ( stbi__get16be(s) < 1 ) return 0; // test height + sz = stbi__get8(s); // bits per pixel + if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) + res = 0; + else + res = 1; + stbi__rewind(s); + return res; +} + +static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp = tga_bits_per_pixel / 8; + int tga_inverted = stbi__get8(s); + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4]; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + /* int tga_alpha_bits = tga_inverted & 15; */ + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // error check + if ( //(tga_indexed) || + (tga_width < 1) || (tga_height < 1) || + (tga_image_type < 1) || (tga_image_type > 3) || + ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) && + (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) + ) + { + return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA + } + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) + { + tga_comp = tga_palette_bits / 8; + } + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + tga_data = (unsigned char*)stbi__malloc( tga_width * tga_height * tga_comp ); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE) { + for (i=0; i < tga_height; ++i) { + int y = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + y*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_palette_bits / 8 ); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (!stbi__getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in 1 byte, then perform the lookup + int pal_idx = stbi__get8(s); + if ( pal_idx >= tga_palette_len ) + { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_bits_per_pixel / 8; + for (j = 0; j*8 < tga_bits_per_pixel; ++j) + { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else + { + // read in the data raw + for (j = 0; j*8 < tga_bits_per_pixel; ++j) + { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB + if (tga_comp >= 3) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + int pixelCount; + int channelCount, compression; + int channel, i, count, len; + int w,h; + stbi_uc *out; + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + // Make sure the depth is 8 bits. + if (stbi__get16be(s) != 8) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Create the destination image. + out = (stbi_uc *) stbi__malloc(4 * w*h); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++) *p = (channel == 3 ? 255 : 0), p += 4; + } else { + // Read the RLE data. + count = 0; + while (count < pixelCount) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len ^= 0x0FF; + len += 2; + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out + channel; + if (channel > channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++) *p = channel == 3 ? 255 : 0, p += 4; + } else { + // Read the data. + for (i = 0; i < pixelCount; i++) + *p = stbi__get8(s), p += 4; + } + } + } + + if (req_comp && req_comp != 4) { + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = channelCount; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + int i; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp) +{ + stbi_uc *result; + int i, x,y; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if ((1 << 28) / x < y) return stbi__errpuc("too large", "Image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc(x*y*4); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[4096]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif g; + if (!stbi__gif_header(s, &g, comp, 1)) { + stbi__rewind( s ); + return 0; + } + if (x) *x = g.w; + if (y) *y = g.h; + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + p = &g->out[g->cur_x + g->cur_y]; + c = &g->color_table[g->codes[code].suffix * 4]; + + if (c[3] >= 128) { + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (code = 0; code < clear; code++) { + g->codes[code].prefix = -1; + g->codes[code].first = (stbi_uc) code; + g->codes[code].suffix = (stbi_uc) code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF"); + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +static void stbi__fill_gif_background(stbi__gif *g) +{ + int i; + stbi_uc *c = g->pal[g->bgindex]; + // @OPTIMIZE: write a dword at a time + for (i = 0; i < g->w * g->h * 4; i += 4) { + stbi_uc *p = &g->out[i]; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp) +{ + int i; + stbi_uc *old_out = 0; + + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); + stbi__fill_gif_background(g); + } else { + // animated-gif-only path + if (((g->eflags & 0x1C) >> 2) == 3) { + old_out = g->out; + g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); + memcpy(g->out, old_out, g->w*g->h*4); + } + } + + for (;;) { + switch (stbi__get8(s)) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + for (i=0; i < 256; ++i) // @OPTIMIZE: stbi__jpeg_reset only the previous transparent + g->pal[i][3] = 255; + if (g->transparent >= 0 && (g->eflags & 0x01)) + g->pal[g->transparent][3] = 0; + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (o == NULL) return NULL; + + if (req_comp && req_comp != 4) + o = stbi__convert_format(o, 4, req_comp, g->w, g->h); + return o; + } + + case 0x21: // Comment Extension. + { + int len; + if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + stbi__get16le(s); // delay + g->transparent = stbi__get8(s); + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) + stbi__skip(s, len); + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + + u = stbi__gif_load_next(s, &g, comp, req_comp); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + } + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s) +{ + const char *signature = "#?RADIANCE\n"; + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s); + stbi__rewind(s); + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + + + // Check identifier + if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + // Read data + hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float)); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4); + + for (k = 0; k < 4; ++k) { + i = 0; + while (i < width) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + + if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') { + stbi__rewind( s ); + return 0; + } + stbi__skip(s,12); + hsz = stbi__get32le(s); + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) { + stbi__rewind( s ); + return 0; + } + if (hsz == 12) { + *x = stbi__get16le(s); + *y = stbi__get16le(s); + } else { + *x = stbi__get32le(s); + *y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) { + stbi__rewind( s ); + return 0; + } + *comp = stbi__get16le(s) / 8; + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + if (stbi__get16be(s) != 8) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained; + stbi__pic_packet packets[10]; + + stbi__skip(s, 92); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) return 0; + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) +// Does not support 16-bit-per-channel + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *out; + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; + *x = s->img_x; + *y = s->img_y; + *comp = s->img_n; + + out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv; + char c, p, t; + + stbi__rewind( s ); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 2008-08-02 + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 first released version +*/ \ No newline at end of file -- cgit 1.4.1 From 36cceabfc5ddd22d9ae0d6c4dee9d4041bf2e348 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sat, 28 Apr 2018 18:52:55 -0400 Subject: Implemented map object sprites Map objects cannot be interacted with or collided with yet but the sprites are loaded. --- src/components/realizable.h | 7 +++ src/game.cpp | 5 ++- src/systems/realizing.cpp | 104 ++++++++++++++++++++++++++++++++++++++++++-- src/systems/realizing.h | 7 ++- 4 files changed, 116 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/components/realizable.h b/src/components/realizable.h index f6a7eb4..0858e7a 100644 --- a/src/components/realizable.h +++ b/src/components/realizable.h @@ -18,6 +18,13 @@ public: */ std::string worldFile; + /** + * Path to the XML file containing the map object prototype definitions. + * + * @managed_by RealizingSystem + */ + std::string prototypeFile; + /** * Starting map and player location for a new game. * diff --git a/src/game.cpp b/src/game.cpp index b7dd200..d10c52c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -40,7 +40,10 @@ Game::Game() systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); - systemManager_.getSystem().initSingleton("res/maps.xml"); + systemManager_.getSystem().initSingleton( + "res/maps.xml", + "res/entities.xml"); + systemManager_.getSystem().initPlayer(); glfwSwapInterval(1); diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp index 09c38f3..c86dd5e 100644 --- a/src/systems/realizing.cpp +++ b/src/systems/realizing.cpp @@ -2,8 +2,10 @@ #include #include #include +#include #include "game.h" #include "consts.h" +#include "animation.h" #include "components/realizable.h" #include "components/mappable.h" #include "components/animatable.h" @@ -27,16 +29,58 @@ inline xmlChar* getProp(xmlNodePtr node, const char* attr) // TODO: neither the XML doc nor any of the emplaced entities are properly // destroyed if this method throws an exception. -EntityManager::id_type RealizingSystem::initSingleton(std::string filename) +EntityManager::id_type RealizingSystem::initSingleton( + std::string worldFile, + std::string prototypeFile) { id_type world = game_.getEntityManager().emplaceEntity(); auto& realizable = game_.getEntityManager(). emplaceComponent(world); + realizable.worldFile = worldFile; + realizable.prototypeFile = prototypeFile; + auto& mapping = game_.getSystemManager().getSystem(); - xmlDocPtr doc = xmlParseFile(filename.c_str()); + xmlChar* key = nullptr; + + // Create a mapping between prototype names and the XML trees defining them. + xmlDocPtr protoXml = xmlParseFile(prototypeFile.c_str()); + if (protoXml == nullptr) + { + throw std::invalid_argument("Cannot find prototypes file"); + } + + xmlNodePtr protoTop = xmlDocGetRootElement(protoXml); + if (protoTop == nullptr) + { + throw std::invalid_argument("Error parsing prototypes file"); + } + + if (xmlStrcmp(protoTop->name, reinterpret_cast("entities"))) + { + throw std::invalid_argument("Error parsing prototypes file"); + } + + std::map prototypes; + + for (xmlNodePtr node = protoTop->xmlChildrenNode; + node != nullptr; + node = node->next) + { + if (!xmlStrcmp(node->name, reinterpret_cast("entity"))) + { + key = getProp(node, "id"); + std::string prototypeId = reinterpret_cast(key); + xmlFree(key); + + prototypes[prototypeId] = node; + } + } + + // Create entities from the world definition. + xmlDocPtr doc = xmlParseFile(worldFile.c_str()); if (doc == nullptr) { throw std::invalid_argument("Cannot find world file"); @@ -53,8 +97,6 @@ EntityManager::id_type RealizingSystem::initSingleton(std::string filename) throw std::invalid_argument("Error parsing world file"); } - xmlChar* key = nullptr; - key = getProp(top, "startx"); realizable.startingX = atoi(reinterpret_cast(key)); xmlFree(key); @@ -113,6 +155,59 @@ EntityManager::id_type RealizingSystem::initSingleton(std::string filename) } xmlFree(key); + } else if (!xmlStrcmp( + mapNode->name, + reinterpret_cast("entity"))) + { + id_type mapObject = game_.getEntityManager().emplaceEntity(); + + key = getProp(mapNode, "type"); + std::string prototypeId = reinterpret_cast(key); + xmlFree(key); + + xmlNodePtr prototypeNode = prototypes[prototypeId]; + + // Set the coordinates from the object definition. + auto& transformable = game_.getEntityManager(). + emplaceComponent(mapObject); + + key = getProp(mapNode, "x"); + transformable.origX = atoi(reinterpret_cast(key)); + xmlFree(key); + + key = getProp(mapNode, "y"); + transformable.origY = atoi(reinterpret_cast(key)); + xmlFree(key); + + // Set the sprite and size using the prototype definition. + key = getProp(prototypeNode, "sprite"); + std::string spritePath = reinterpret_cast(key); + xmlFree(key); + + key = getProp(prototypeNode, "width"); + transformable.origW = atoi(reinterpret_cast(key)); + xmlFree(key); + + key = getProp(prototypeNode, "height"); + transformable.origH = atoi(reinterpret_cast(key)); + xmlFree(key); + + AnimationSet objectAnim( + spritePath.c_str(), + transformable.origW, + transformable.origH, + 1); + + objectAnim.emplaceAnimation("static", 0, 1, 1); + + auto& animatable = game_.getEntityManager(). + emplaceComponent( + mapObject, + std::move(objectAnim)); + + animatable.origAnimation = "static"; + + mappable.objects.push_back(mapObject); } else if (!xmlStrcmp( mapNode->name, reinterpret_cast("adjacent"))) @@ -172,6 +267,7 @@ EntityManager::id_type RealizingSystem::initSingleton(std::string filename) } xmlFreeDoc(doc); + xmlFreeDoc(protoXml); loadMap(realizable.entityByMapId[realizable.startingMapId]); diff --git a/src/systems/realizing.h b/src/systems/realizing.h index c681892..595c58f 100644 --- a/src/systems/realizing.h +++ b/src/systems/realizing.h @@ -1,6 +1,7 @@ #ifndef REALIZING_H_6853748C #define REALIZING_H_6853748C +#include #include "system.h" class RealizingSystem : public System { @@ -12,9 +13,11 @@ public: /** * Creates the singleton realizable entity and initializes it with the - * provided world definition. + * provided world definition and map object prototype definition. */ - id_type initSingleton(std::string filename); + id_type initSingleton( + std::string worldFile, + std::string prototypeFile); /** * Helper method that returns the entity ID of the (assumed) singleton entity -- cgit 1.4.1 From c00668c58b26325203cb6815bc3dedf1e7d7ac5e Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sun, 29 Apr 2018 16:45:55 -0400 Subject: Added map object collision Collision checking in PonderingSystem was rewritten to work as follows: horizontal movement is step first, then vertical. In each step, the closest environmental boundary to the body is found on the axis of movement in the space traversed by the body. Then, if any map objects fall in the region between the body's old position and the environmental boundary (or body new position if no boundary was found), process collision with those bodies in increasing distance order, stopping if a collision stops movement short of where the next collision would take place. After this, process collision with all of the environmental boundaries at the axis distance found earlier, as long as movement hasn't stopped short. This is not the most optimal implementation, and there is a lot of code repetition, but it is a start and it works. All map objects currently function as walls. This fixes the bug where you could, with pixel-perfect precision, jump into the corner of a wall tile. The top of the hitbox for the spike tile was lowered by one pixel. This fixes a problem where if the player is halfway on a floor tile and halfway over a spike tile, the floor tile would not stop the spike tile from being processed, and the player would die. --- CMakeLists.txt | 1 - src/collision.cpp | 97 ----- src/collision.h | 81 ---- src/components/mappable.h | 4 +- src/components/ponderable.h | 16 + src/systems/mapping.cpp | 2 +- src/systems/pondering.cpp | 882 +++++++++++++++++++++++++++++++++----------- src/systems/pondering.h | 23 ++ src/systems/realizing.cpp | 4 + 9 files changed, 714 insertions(+), 396 deletions(-) delete mode 100644 src/collision.cpp delete mode 100644 src/collision.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 49a0384..cd652e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,7 +55,6 @@ add_executable(Aromatherapy src/game.cpp src/animation.cpp src/util.cpp - src/collision.cpp src/renderer/renderer.cpp src/renderer/mesh.cpp src/renderer/shader.cpp diff --git a/src/collision.cpp b/src/collision.cpp deleted file mode 100644 index b747a90..0000000 --- a/src/collision.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "collision.h" - -bool Collision::operator<(const Collision& other) const -{ - // Most important is the type of collision - if (type_ != other.type_) - { - return (static_cast(type_) > static_cast(other.type_)); - } - - // Next, categorize the collisions arbitrarily based on direction - if (dir_ != other.dir_) - { - return (static_cast(dir_) < static_cast(other.dir_)); - } - - // We want to process closer collisions first - if (axis_ != other.axis_) - { - switch (dir_) - { - case Direction::left: - case Direction::up: - { - return (axis_ < other.axis_); - } - - case Direction::right: - case Direction::down: - { - return (axis_ > other.axis_); - } - } - } - - // Order the remaining attributes arbitrarily - return std::tie(collider_, lower_, upper_) < - std::tie(other.collider_, other.lower_, other.upper_); -} - -bool Collision::isColliding( - double x, - double y, - int w, - int h) const -{ - int right = x + w; - int bottom = y + h; - - switch (dir_) - { - case Direction::left: - case Direction::right: - { - if (!((bottom > lower_) && (y < upper_))) - { - return false; - } - - break; - } - - case Direction::up: - case Direction::down: - { - if (!((right > lower_) && (x < upper_))) - { - return false; - } - - break; - } - } - - switch (dir_) - { - case Direction::left: - { - return (axis_ >= x); - } - - case Direction::right: - { - return (axis_ <= right); - } - - case Direction::up: - { - return (axis_ >= y); - } - - case Direction::down: - { - return (axis_ <= bottom); - } - } -} diff --git a/src/collision.h b/src/collision.h deleted file mode 100644 index e5371f8..0000000 --- a/src/collision.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef COLLISION_H_53D84877 -#define COLLISION_H_53D84877 - -#include "entity_manager.h" -#include "direction.h" - -class Collision { -public: - - using id_type = EntityManager::id_type; - - // Types are defined in descending priority order - enum class Type { - wall, - platform, - adjacency, - warp, - danger - }; - - Collision( - id_type collider, - Direction dir, - Type type, - int axis, - double lower, - double upper) : - collider_(collider), - dir_(dir), - type_(type), - axis_(axis), - lower_(lower), - upper_(upper) - { - } - - inline id_type getCollider() const - { - return collider_; - } - - inline Direction getDirection() const - { - return dir_; - } - - inline Type getType() const - { - return type_; - } - - inline int getAxis() const - { - return axis_; - } - - inline double getLower() const - { - return lower_; - } - - inline double getUpper() const - { - return upper_; - } - - bool operator<(const Collision& other) const; - - bool isColliding(double x, double y, int w, int h) const; - -private: - - id_type collider_; - Direction dir_; - Type type_; - int axis_; - double lower_; - double upper_; -}; - -#endif /* end of include guard: COLLISION_H_53D84877 */ diff --git a/src/components/mappable.h b/src/components/mappable.h index 6f3d38e..e92074e 100644 --- a/src/components/mappable.h +++ b/src/components/mappable.h @@ -7,7 +7,7 @@ #include #include "component.h" #include "renderer/texture.h" -#include "collision.h" +#include "components/ponderable.h" #include "entity_manager.h" class MappableComponent : public Component { @@ -46,7 +46,7 @@ public: class Boundary { public: - using Type = Collision::Type; + using Type = PonderableComponent::Collision; Boundary( double axis, diff --git a/src/components/ponderable.h b/src/components/ponderable.h index fd7e775..5354f87 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -20,6 +20,17 @@ public: freefalling }; + /** + * List of different types of collidable surfaces. + */ + enum class Collision { + wall, + platform, + adjacency, + warp, + danger + }; + /** * Constructor for initializing the body type, which is a constant. */ @@ -66,6 +77,11 @@ public: */ bool collidable = true; + /** + * The effect that colliding with this body has. + */ + Collision colliderType = Collision::wall; + /** * If this flag is disabled, the entity will be ignored by the pondering * system. diff --git a/src/systems/mapping.cpp b/src/systems/mapping.cpp index af67aed..d78c8fe 100644 --- a/src/systems/mapping.cpp +++ b/src/systems/mapping.cpp @@ -175,7 +175,7 @@ void MappingSystem::generateBoundaries(id_type mapEntity) addBoundary( mappable.downBoundaries, - y * TILE_HEIGHT, + y * TILE_HEIGHT + 1, x * TILE_WIDTH, (x+1) * TILE_WIDTH, MappableComponent::Boundary::Type::danger); diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 4ae6176..04b45a1 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -11,7 +11,6 @@ #include "systems/playing.h" #include "systems/realizing.h" #include "consts.h" -#include "collision.h" void PonderingSystem::tick(double dt) { @@ -56,304 +55,566 @@ void PonderingSystem::tick(double dt) const double oldRight = oldX + transformable.w; const double oldBottom = oldY + transformable.h; - double newX = oldX + ponderable.velX * dt; - double newY = oldY + ponderable.velY * dt; + CollisionResult result; + result.newX = oldX + ponderable.velX * dt; + result.newY = oldY + ponderable.velY * dt; bool oldGrounded = ponderable.grounded; ponderable.grounded = false; - std::priority_queue collisions; - - // Find collisions - if (newX < oldX) + // Find horizontal collisions. + if (result.newX < oldX) { - for (auto it = mappable.leftBoundaries.lower_bound(oldX); - (it != std::end(mappable.leftBoundaries)) && (it->first >= newX); - it++) + bool boundaryCollision = false; + auto it = mappable.leftBoundaries.lower_bound(oldX); + + // Find the axis distance of the closest environmental boundary. + for (; + (it != std::end(mappable.leftBoundaries)) && + (it->first >= result.newX); + it++) { - if ((oldBottom > it->second.lower) - && (oldY < it->second.upper)) + // Check that the boundary is in range for the other axis. + if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) { // We have a collision! - collisions.emplace( - mapEntity, - Direction::left, - it->second.type, - it->first, - it->second.lower, - it->second.upper); + boundaryCollision = true; + + break; } } - } else if (newX > oldX) - { - for (auto it = mappable.rightBoundaries.lower_bound(oldRight); - (it != std::end(mappable.rightBoundaries)) - && (it->first <= (newX + transformable.w)); - it++) + + // Find a list of potential colliders, sorted so that the closest is + // first. + std::vector colliders; + + for (id_type collider : entities) { - if ((oldBottom > it->second.lower) - && (oldY < it->second.upper)) + // Can't collide with self. + if (collider == entity) { - // We have a collision! - collisions.emplace( - mapEntity, - Direction::right, - it->second.type, - it->first, - it->second.lower, - it->second.upper); + continue; } - } - } - if (newY < oldY) - { - for (auto it = mappable.upBoundaries.lower_bound(oldY); - (it != std::end(mappable.upBoundaries)) && (it->first >= newY); - it++) - { - if ((oldRight > it->second.lower) - && (oldX < it->second.upper)) + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); + + // Only check objects that are active. + if (!colliderPonder.active) { - // We have a collision! - collisions.emplace( - mapEntity, - Direction::up, - it->second.type, - it->first, - it->second.lower, - it->second.upper); + continue; } - } - } else if (newY > oldY) - { - for (auto it = mappable.downBoundaries.lower_bound(oldBottom); - (it != std::end(mappable.downBoundaries)) - && (it->first <= (newY + transformable.h)); - it++) - { - if ((oldRight > it->second.lower) - && (oldX < it->second.upper)) + + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would move into the potential collider, + if ((colliderTrans.x + colliderTrans.w > result.newX) && + // that it wasn't already colliding, + (colliderTrans.x + colliderTrans.w <= oldX) && + // that the position on the other axis is in range, + (colliderTrans.y + colliderTrans.h > oldY) && + (colliderTrans.y < oldBottom) && + // and that the collider is not farther away than the environmental + // boundary. + (!boundaryCollision || + (colliderTrans.x + colliderTrans.w >= it->first))) { - // We have a collision! - collisions.emplace( - mapEntity, - Direction::down, - it->second.type, - it->first, - it->second.lower, - it->second.upper); + colliders.push_back(collider); } } - } - // Process collisions in order of priority - bool adjacentlyWarping = false; - Direction adjWarpDir; - size_t adjWarpMapId; + std::sort( + std::begin(colliders), + std::end(colliders), + [&] (id_type left, id_type right) { + auto& leftTrans = game_.getEntityManager(). + getComponent(left); - while (!collisions.empty()) - { - Collision collision = collisions.top(); - collisions.pop(); - - // Make sure that they are still colliding - if (!collision.isColliding( - newX, - newY, - transformable.w, - transformable.h)) - { - continue; - } + auto& rightTrans = game_.getEntityManager(). + getComponent(right); - bool touchedWall = false; - bool stopProcessing = false; + return (rightTrans.x < leftTrans.x); + }); - switch (collision.getType()) + for (id_type collider : colliders) { - case Collision::Type::wall: + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would still move into the potential collider. + if (colliderTrans.x + colliderTrans.w <= result.newX) { - touchedWall = true; + break; + } + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); + + processCollision( + entity, + collider, + Direction::left, + colliderPonder.colliderType, + colliderTrans.x + colliderTrans.w, + colliderTrans.y, + colliderTrans.y + colliderTrans.h, + result); + + if (result.stopProcessing) + { break; } + } - case Collision::Type::platform: + // If movement hasn't been stopped by an intermediary object, and + // collision checking hasn't been stopped, process the environmental + // boundaries closest to the entity. + if (!result.stopProcessing && !result.touchedWall && boundaryCollision) + { + double boundaryAxis = it->first; + + for (; + (it != std::end(mappable.leftBoundaries)) && + (it->first == boundaryAxis); + it++) { - if (game_.getEntityManager(). - hasComponent(entity)) + if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) { - auto& orientable = game_.getEntityManager(). - getComponent(entity); - - if (orientable.getDropState() != - OrientableComponent::DropState::none) + processCollision( + entity, + mapEntity, + Direction::left, + it->second.type, + it->first, + it->second.lower, + it->second.upper, + result); + + if (result.stopProcessing) { - orientable.setDropState(OrientableComponent::DropState::active); - } else { - touchedWall = true; + break; } - } else { - touchedWall = true; } + } + } + } else if (result.newX > oldX) + { + bool boundaryCollision = false; + auto it = mappable.rightBoundaries.lower_bound(oldRight); + + // Find the axis distance of the closest environmental boundary. + for (; + (it != std::end(mappable.rightBoundaries)) + && (it->first <= (result.newX + transformable.w)); + it++) + { + // Check that the boundary is in range for the other axis. + if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) + { + // We have a collision! + boundaryCollision = true; break; } + } + + // Find a list of potential colliders, sorted so that the closest is + // first. + std::vector colliders; - case Collision::Type::adjacency: + for (id_type collider : entities) + { + // Can't collide with self. + if (collider == entity) { - auto& mappable = game_.getEntityManager(). - getComponent(collision.getCollider()); + continue; + } - auto& adj = [&] () -> const MappableComponent::Adjacent& { - switch (collision.getDirection()) - { - case Direction::left: return mappable.leftAdjacent; - case Direction::right: return mappable.rightAdjacent; - case Direction::up: return mappable.upAdjacent; - case Direction::down: return mappable.downAdjacent; - } - }(); + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - switch (adj.type) - { - case MappableComponent::Adjacent::Type::wall: - { - touchedWall = true; + // Only check objects that are active. + if (!colliderPonder.active) + { + continue; + } - break; - } + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would move into the potential collider, + if ((colliderTrans.x < result.newX + transformable.w) && + // that it wasn't already colliding, + (colliderTrans.x >= oldRight) && + // that the position on the other axis is in range, + (colliderTrans.y + colliderTrans.h > oldY) && + (colliderTrans.y < oldBottom) && + // and that the collider is not farther away than the environmental + // boundary. + (!boundaryCollision || (colliderTrans.x <= it->first))) + { + colliders.push_back(collider); + } + } - case MappableComponent::Adjacent::Type::wrap: - { - switch (collision.getDirection()) - { - case Direction::left: - { - newX = GAME_WIDTH + WALL_GAP - transformable.w; + std::sort( + std::begin(colliders), + std::end(colliders), + [&] (id_type left, id_type right) { + auto& leftTrans = game_.getEntityManager(). + getComponent(left); - break; - } + auto& rightTrans = game_.getEntityManager(). + getComponent(right); - case Direction::right: - { - newX = -WALL_GAP; + return (leftTrans.x < rightTrans.x); + }); - break; - } + for (id_type collider : colliders) + { + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); - case Direction::up: - { - newY = MAP_HEIGHT * TILE_HEIGHT + WALL_GAP - transformable.h; + // Check if the entity would still move into the potential collider. + if (colliderTrans.x >= result.newX + transformable.w) + { + break; + } - break; - } + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - case Direction::down: - { - newY = -WALL_GAP; + processCollision( + entity, + collider, + Direction::right, + colliderPonder.colliderType, + colliderTrans.x, + colliderTrans.y, + colliderTrans.y + colliderTrans.h, + result); + + if (result.stopProcessing) + { + break; + } + } - break; - } - } - } + // If movement hasn't been stopped by an intermediary object, and + // collision checking hasn't been stopped, process the environmental + // boundaries closest to the entity. + if (!result.stopProcessing && !result.touchedWall && boundaryCollision) + { + double boundaryAxis = it->first; - case MappableComponent::Adjacent::Type::warp: + for (; + (it != std::end(mappable.rightBoundaries)) && + (it->first == boundaryAxis); + it++) + { + if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) + { + processCollision( + entity, + mapEntity, + Direction::right, + it->second.type, + it->first, + it->second.lower, + it->second.upper, + result); + + if (result.stopProcessing) { - if (game_.getEntityManager(). - hasComponent(entity)) - { - adjacentlyWarping = true; - adjWarpDir = collision.getDirection(); - adjWarpMapId = adj.mapId; - } - break; } + } + } + } + } - case MappableComponent::Adjacent::Type::reverse: - { - // TODO: not yet implemented. + // Find vertical collisions + result.touchedWall = false; - break; - } - } + if ((!result.stopProcessing) && (result.newY < oldY)) + { + bool boundaryCollision = false; + auto it = mappable.upBoundaries.lower_bound(oldY); + + // Find the axis distance of the closest environmental boundary. + for (; + (it != std::end(mappable.upBoundaries)) && + (it->first >= result.newY); + it++) + { + // Check that the boundary is in range for the other axis. + if ((result.newX + transformable.h > it->second.lower) && + (result.newX < it->second.upper)) + { + // We have a collision! + boundaryCollision = true; break; } + } - case Collision::Type::danger: + // Find a list of potential colliders, sorted so that the closest is + // first. + std::vector colliders; + + for (id_type collider : entities) + { + // Can't collide with self. + if (collider == entity) { - if (game_.getEntityManager(). - hasComponent(entity)) - { - game_.getSystemManager().getSystem().die(entity); + continue; + } - adjacentlyWarping = false; - } + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - stopProcessing = true; + // Only check objects that are active. + if (!colliderPonder.active) + { + continue; + } - break; + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would move into the potential collider, + if ((colliderTrans.y + colliderTrans.h > result.newY) && + // that it wasn't already colliding, + (colliderTrans.y + colliderTrans.h <= oldY) && + // that the position on the other axis is in range, + (colliderTrans.x + colliderTrans.w > result.newX) && + (colliderTrans.x < result.newX + transformable.w) && + // and that the collider is not farther away than the environmental + // boundary. + (!boundaryCollision || + (colliderTrans.y + colliderTrans.h >= it->first))) + { + colliders.push_back(collider); } + } + + std::sort( + std::begin(colliders), + std::end(colliders), + [&] (id_type left, id_type right) { + auto& leftTrans = game_.getEntityManager(). + getComponent(left); + + auto& rightTrans = game_.getEntityManager(). + getComponent(right); - default: + return (rightTrans.y < leftTrans.y); + }); + + for (id_type collider : colliders) + { + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would still move into the potential collider. + if (colliderTrans.y + colliderTrans.h <= result.newY) { - // Not yet implemented. + break; + } + + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); + processCollision( + entity, + collider, + Direction::up, + colliderPonder.colliderType, + colliderTrans.y + colliderTrans.h, + colliderTrans.x, + colliderTrans.x + colliderTrans.w, + result); + + if (result.stopProcessing) + { break; } } - if (stopProcessing) + // If movement hasn't been stopped by an intermediary object, and + // collision checking hasn't been stopped, process the environmental + // boundaries closest to the entity. + if (!result.stopProcessing && !result.touchedWall && boundaryCollision) { - break; + double boundaryAxis = it->first; + + for (; + (it != std::end(mappable.upBoundaries)) && + (it->first == boundaryAxis); + it++) + { + if ((result.newX + transformable.w > it->second.lower) && + (result.newX < it->second.upper)) + { + processCollision( + entity, + mapEntity, + Direction::up, + it->second.type, + it->first, + it->second.lower, + it->second.upper, + result); + + if (result.stopProcessing) + { + break; + } + } + } } + } else if ((!result.stopProcessing) && (result.newY > oldY)) + { + bool boundaryCollision = false; + auto it = mappable.downBoundaries.lower_bound(oldBottom); + + // Find the axis distance of the closest environmental boundary. + for (; + (it != std::end(mappable.downBoundaries)) + && (it->first <= (result.newY + transformable.h)); + it++) + { + // Check that the boundary is in range for the other axis. + if ((result.newX + transformable.w > it->second.lower) && + (result.newX < it->second.upper)) + { + // We have a collision! + boundaryCollision = true; - if (touchedWall) + break; + } + } + + // Find a list of potential colliders, sorted so that the closest is + // first. + std::vector colliders; + + for (id_type collider : entities) { - switch (collision.getDirection()) + // Can't collide with self. + if (collider == entity) { - case Direction::left: - { - newX = collision.getAxis(); - ponderable.velX = 0.0; + continue; + } - break; - } + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - case Direction::right: - { - newX = collision.getAxis() - transformable.w; - ponderable.velX = 0.0; + // Only check objects that are active. + if (!colliderPonder.active) + { + continue; + } - break; - } + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would move into the potential collider, + if ((colliderTrans.y < result.newY + transformable.h) && + // that it wasn't already colliding, + (colliderTrans.y >= oldBottom) && + // that the position on the other axis is in range, + (colliderTrans.x + colliderTrans.w > result.newX) && + (colliderTrans.x < result.newX + transformable.w) && + // and that the collider is not farther away than the environmental + // boundary. + (!boundaryCollision || (colliderTrans.y <= it->first))) + { + colliders.push_back(collider); + } + } - case Direction::up: - { - newY = collision.getAxis(); - ponderable.velY = 0.0; + std::sort( + std::begin(colliders), + std::end(colliders), + [&] (id_type left, id_type right) { + auto& leftTrans = game_.getEntityManager(). + getComponent(left); - break; - } + auto& rightTrans = game_.getEntityManager(). + getComponent(right); - case Direction::down: - { - newY = collision.getAxis() - transformable.h; - ponderable.velY = 0.0; - ponderable.grounded = true; + return (leftTrans.y < rightTrans.y); + }); + + for (id_type collider : colliders) + { + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would still move into the potential collider. + if (colliderTrans.y >= result.newY + transformable.h) + { + break; + } + + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); + + processCollision( + entity, + collider, + Direction::down, + colliderPonder.colliderType, + colliderTrans.y, + colliderTrans.x, + colliderTrans.x + colliderTrans.w, + result); + + if (result.stopProcessing) + { + break; + } + } + + // If movement hasn't been stopped by an intermediary object, and + // collision checking hasn't been stopped, process the environmental + // boundaries closest to the entity. + if (!result.stopProcessing && !result.touchedWall && boundaryCollision) + { + double boundaryAxis = it->first; - break; + for (; + (it != std::end(mappable.downBoundaries)) && + (it->first == boundaryAxis); + it++) + { + if ((result.newX + transformable.w > it->second.lower) && + (result.newX < it->second.upper)) + { + processCollision( + entity, + mapEntity, + Direction::down, + it->second.type, + it->first, + it->second.lower, + it->second.upper, + result); + + if (result.stopProcessing) + { + break; + } } } } } // Move - transformable.x = newX; - transformable.y = newY; + transformable.x = result.newX; + transformable.y = result.newY; // Perform cleanup for orientable entites if (game_.getEntityManager().hasComponent(entity)) @@ -381,12 +642,12 @@ void PonderingSystem::tick(double dt) } // Move to an adjacent map, if necessary - if (adjacentlyWarping) + if (result.adjacentlyWarping) { - double warpX = newX; - double warpY = newY; + double warpX = result.newX; + double warpY = result.newY; - switch (adjWarpDir) + switch (result.adjWarpDir) { case Direction::left: { @@ -420,7 +681,7 @@ void PonderingSystem::tick(double dt) game_.getSystemManager().getSystem(). changeMap( entity, - adjWarpMapId, + result.adjWarpMapId, warpX, warpY); } @@ -453,3 +714,196 @@ void PonderingSystem::initPrototype(id_type prototype) ponderable.frozen = false; ponderable.collidable = true; } + +void PonderingSystem::processCollision( + id_type entity, + id_type collider, + Direction dir, + PonderableComponent::Collision type, + double axis, + double lower, + double upper, + CollisionResult& result) +{ + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + auto& transformable = game_.getEntityManager(). + getComponent(entity); + + switch (type) + { + case PonderableComponent::Collision::wall: + { + result.touchedWall = true; + + break; + } + + case PonderableComponent::Collision::platform: + { + if (game_.getEntityManager(). + hasComponent(entity)) + { + auto& orientable = game_.getEntityManager(). + getComponent(entity); + + if (orientable.getDropState() != + OrientableComponent::DropState::none) + { + orientable.setDropState(OrientableComponent::DropState::active); + } else { + result.touchedWall = true; + } + } else { + result.touchedWall = true; + } + + break; + } + + case PonderableComponent::Collision::adjacency: + { + auto& mappable = game_.getEntityManager(). + getComponent(collider); + + auto& adj = [&] () -> const MappableComponent::Adjacent& { + switch (dir) + { + case Direction::left: return mappable.leftAdjacent; + case Direction::right: return mappable.rightAdjacent; + case Direction::up: return mappable.upAdjacent; + case Direction::down: return mappable.downAdjacent; + } + }(); + + switch (adj.type) + { + case MappableComponent::Adjacent::Type::wall: + { + result.touchedWall = true; + + break; + } + + case MappableComponent::Adjacent::Type::wrap: + { + switch (dir) + { + case Direction::left: + { + result.newX = GAME_WIDTH + WALL_GAP - transformable.w; + + break; + } + + case Direction::right: + { + result.newX = -WALL_GAP; + + break; + } + + case Direction::up: + { + result.newY = + MAP_HEIGHT * TILE_HEIGHT + WALL_GAP - transformable.h; + + break; + } + + case Direction::down: + { + result.newY = -WALL_GAP; + + break; + } + } + } + + case MappableComponent::Adjacent::Type::warp: + { + if (game_.getEntityManager(). + hasComponent(entity)) + { + result.adjacentlyWarping = true; + result.adjWarpDir = dir; + result.adjWarpMapId = adj.mapId; + } + + break; + } + + case MappableComponent::Adjacent::Type::reverse: + { + // TODO: not yet implemented. + + break; + } + } + + break; + } + + case PonderableComponent::Collision::danger: + { + if (game_.getEntityManager(). + hasComponent(entity)) + { + game_.getSystemManager().getSystem().die(entity); + + result.adjacentlyWarping = false; + } + + result.stopProcessing = true; + + break; + } + + default: + { + // Not yet implemented. + + break; + } + } + + if (!result.stopProcessing && result.touchedWall) + { + switch (dir) + { + case Direction::left: + { + result.newX = axis; + ponderable.velX = 0.0; + + break; + } + + case Direction::right: + { + result.newX = axis - transformable.w; + ponderable.velX = 0.0; + + break; + } + + case Direction::up: + { + result.newY = axis; + ponderable.velY = 0.0; + + break; + } + + case Direction::down: + { + result.newY = axis - transformable.h; + ponderable.velY = 0.0; + ponderable.grounded = true; + + break; + } + } + } +} diff --git a/src/systems/pondering.h b/src/systems/pondering.h index 58e6496..aa430db 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -18,6 +18,29 @@ public: void initPrototype(id_type prototype); +private: + + struct CollisionResult + { + double newX; + double newY; + bool stopProcessing = false; + bool touchedWall = false; + bool adjacentlyWarping = false; + Direction adjWarpDir; + size_t adjWarpMapId; + }; + + void processCollision( + id_type entity, + id_type collider, + Direction dir, + PonderableComponent::Collision type, + double axis, + double lower, + double upper, + CollisionResult& result); + }; #endif /* end of include guard: PONDERING_H_F2530E0E */ diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp index c86dd5e..3656acb 100644 --- a/src/systems/realizing.cpp +++ b/src/systems/realizing.cpp @@ -207,6 +207,10 @@ EntityManager::id_type RealizingSystem::initSingleton( animatable.origAnimation = "static"; + // Create a physics body. + game_.getSystemManager().getSystem(). + initializeBody(mapObject, PonderableComponent::Type::vacuumed); + mappable.objects.push_back(mapObject); } else if (!xmlStrcmp( mapNode->name, -- cgit 1.4.1 From b2311e1ba43a72a205b51a24376a1f363faa569e Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sun, 29 Apr 2018 16:47:27 -0400 Subject: Added missing #include --- src/systems/pondering.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 04b45a1..5143f8e 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -1,5 +1,6 @@ #include "pondering.h" #include +#include #include "game.h" #include "components/ponderable.h" #include "components/transformable.h" -- cgit 1.4.1 From 83f51a6892629921b4cc482b986656a0a5cc5f6a Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Thu, 3 May 2018 14:41:01 -0400 Subject: Added simple AI implementation The new AutomatingSystem and AutomatableComponent are responsible for simple AI tasks. This currently is limited to moving entities at a certain speed for certain periods of time. These tasks are arranged as a set of behaviors, which are picked randomly when automation starts or when a behavior finishes executing. A behavior is a sequence of actions that run one after another. Currently, if an automated entity is blocked from moving by a collision, it will be coerced out of its intended path. This is because the automation parameters are stored as a speed and a duration, rather than a starting location and an ending location. This may end up being changed, or made configurable, as this is an early implementation of this feature and will need to be more complex later. Added an RNG object to the Game class, so that the AutomatingSystem can pick behaviors at random. --- CMakeLists.txt | 1 + src/components/automatable.h | 96 ++++++++++++++++++++++++ src/game.cpp | 4 +- src/game.h | 9 ++- src/main.cpp | 6 +- src/systems/automating.cpp | 71 ++++++++++++++++++ src/systems/automating.h | 19 +++++ src/systems/realizing.cpp | 174 +++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 377 insertions(+), 3 deletions(-) create mode 100644 src/components/automatable.h create mode 100644 src/systems/automating.cpp create mode 100644 src/systems/automating.h (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index cd652e2..04ca668 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,7 @@ add_executable(Aromatherapy src/systems/playing.cpp src/systems/scheduling.cpp src/systems/realizing.cpp + src/systems/automating.cpp vendor/stb_image.cpp ) diff --git a/src/components/automatable.h b/src/components/automatable.h new file mode 100644 index 0000000..b37945f --- /dev/null +++ b/src/components/automatable.h @@ -0,0 +1,96 @@ +#ifndef AUTOMATABLE_H_3D519131 +#define AUTOMATABLE_H_3D519131 + +#include "component.h" +#include +#include + +class AutomatableComponent : public Component { +public: + + /** + * Helper class that defines an automatable action. + */ + class Action { + public: + + /** + * The horizontal and vertical speed, in pixels/sec, that the entity should + * move at. + */ + double speedX; + double speedY; + + /** + * The duration of the action in seconds. + */ + double dur; + }; + + /** + * Helper type that defines a behavior that an entity can exhibit, which is a + * list of actions that are stepped through in sequence. + */ + using Behavior = std::vector; + + /** + * A group of behaviors that the entity can exhibit, which are picked at + * random at the start of automation and whenever a behavior completes. + * + * @managed_by RealizingSystem + */ + std::vector behaviors; + + /** + * A random distribution over the above behaviors. + * + * @managed_by RealizingSystem + */ + std::discrete_distribution behaviorDist; + + /** + * A flag indicating whether a behavior is currently executing. + * + * @managed_by AutomatingSystem + */ + bool behaviorRunning = false; + + /** + * A flag indicating whether an action is currently executing. + * + * @managed_by AutomatingSystem + */ + bool actionRunning = false; + + /** + * The index of the currently executing behavior, if there is one. + * + * @managed_by AutomatingSystem + */ + size_t currentBehavior; + + /** + * The index of the currently executing action, if there is one. + * + * @managed_by AutomatingSystem + */ + size_t currentAction; + + /** + * The amount of time remaining, in seconds, of the currently executing + * action. + * + * @managed_by AutomatingSystem + */ + double remaining; + + /** + * If this flag is disabled, the entity will be ignored by the automating + * system. + * + * @managed_by RealizingSystem + */ + bool active = false; +}; + +#endif /* end of include guard: AUTOMATABLE_H_3D519131 */ diff --git a/src/game.cpp b/src/game.cpp index d10c52c..bf2b10b 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -12,6 +12,7 @@ #include "systems/playing.h" #include "systems/scheduling.h" #include "systems/realizing.h" +#include "systems/automating.h" #include "animation.h" #include "consts.h" @@ -29,12 +30,13 @@ void key_callback(GLFWwindow* window, int key, int, int action, int) game.systemManager_.input(key, action); } -Game::Game() +Game::Game(std::mt19937& rng) : rng_(rng) { systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); + systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); systemManager_.emplaceSystem(*this); diff --git a/src/game.h b/src/game.h index 92a67d9..dc256c6 100644 --- a/src/game.h +++ b/src/game.h @@ -1,6 +1,7 @@ #ifndef GAME_H_1014DDC9 #define GAME_H_1014DDC9 +#include #include "entity_manager.h" #include "system_manager.h" #include "renderer/renderer.h" @@ -8,10 +9,15 @@ class Game { public: - Game(); + Game(std::mt19937& rng); void execute(); + inline std::mt19937& getRng() + { + return rng_; + } + inline Renderer& getRenderer() { return renderer_; @@ -36,6 +42,7 @@ public: private: + std::mt19937 rng_; Renderer renderer_; EntityManager entityManager_; SystemManager systemManager_; diff --git a/src/main.cpp b/src/main.cpp index ddbc15f..d59d0f9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,15 @@ +#include #include "muxer.h" #include "game.h" int main() { + std::random_device randomDevice; + std::mt19937 rng(randomDevice()); + initMuxer(); - Game game; + Game game(rng); game.execute(); destroyMuxer(); diff --git a/src/systems/automating.cpp b/src/systems/automating.cpp new file mode 100644 index 0000000..0d85957 --- /dev/null +++ b/src/systems/automating.cpp @@ -0,0 +1,71 @@ +#include "automating.h" +#include "game.h" +#include "components/automatable.h" +#include "components/ponderable.h" +#include "systems/pondering.h" + +void AutomatingSystem::tick(double dt) +{ + auto entities = game_.getEntityManager().getEntitiesWithComponents< + AutomatableComponent, + PonderableComponent>(); + + for (id_type entity : entities) + { + auto& automatable = game_.getEntityManager(). + getComponent(entity); + + if (!automatable.active) + { + continue; + } + + if (automatable.behaviorRunning && + (automatable.remaining <= 0.0)) + { + automatable.currentAction++; + automatable.actionRunning = false; + + if (automatable.currentAction == + automatable.behaviors[automatable.currentBehavior].size()) + { + automatable.behaviorRunning = false; + } + } + + if (!automatable.behaviorRunning) + { + automatable.currentBehavior = automatable.behaviorDist(game_.getRng()); + automatable.currentAction = 0; + automatable.behaviorRunning = true; + } + + AutomatableComponent::Action& curAction = + automatable.behaviors + [automatable.currentBehavior] + [automatable.currentAction]; + + if (!automatable.actionRunning) + { + automatable.remaining = curAction.dur; + automatable.actionRunning = true; + } + + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + ponderable.velX = curAction.speedX; + ponderable.velY = curAction.speedY; + + automatable.remaining -= dt; + } +} + +void AutomatingSystem::initPrototype(id_type prototype) +{ + auto& automatable = game_.getEntityManager(). + getComponent(prototype); + + automatable.behaviorRunning = false; + automatable.actionRunning = false; +} diff --git a/src/systems/automating.h b/src/systems/automating.h new file mode 100644 index 0000000..c78b7cf --- /dev/null +++ b/src/systems/automating.h @@ -0,0 +1,19 @@ +#ifndef AUTOMATING_H_E6E5D76E +#define AUTOMATING_H_E6E5D76E + +#include "system.h" + +class AutomatingSystem : public System { +public: + + AutomatingSystem(Game& game) : System(game) + { + } + + void tick(double dt); + + void initPrototype(id_type prototype); + +}; + +#endif /* end of include guard: AUTOMATING_H_E6E5D76E */ diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp index 3656acb..8e670ac 100644 --- a/src/systems/realizing.cpp +++ b/src/systems/realizing.cpp @@ -12,9 +12,11 @@ #include "components/playable.h" #include "components/ponderable.h" #include "components/transformable.h" +#include "components/automatable.h" #include "systems/mapping.h" #include "systems/animating.h" #include "systems/pondering.h" +#include "systems/automating.h" inline xmlChar* getProp(xmlNodePtr node, const char* attr) { @@ -27,6 +29,92 @@ inline xmlChar* getProp(xmlNodePtr node, const char* attr) return key; } +void parseAI( + xmlNodePtr node, + std::vector& behavior, + const std::map& items) +{ + xmlChar* key = nullptr; + + if (!xmlStrcmp( + node->name, + reinterpret_cast("switch"))) + { + key = getProp(node, "item"); + std::string switchItem = reinterpret_cast(key); + xmlFree(key); + + for (xmlNodePtr switchNode = node->xmlChildrenNode; + switchNode != nullptr; + switchNode = switchNode->next) + { + if (!xmlStrcmp( + switchNode->name, + reinterpret_cast("case"))) + { + key = getProp(switchNode, "value"); + int caseValue = atoi(reinterpret_cast(key)); + xmlFree(key); + + if (items.at(switchItem) == caseValue) + { + for (xmlNodePtr caseNode = switchNode->xmlChildrenNode; + caseNode != nullptr; + caseNode = caseNode->next) + { + parseAI( + caseNode, + behavior, + items); + } + } + } + } + } else if (!xmlStrcmp( + node->name, + reinterpret_cast("move"))) + { + key = getProp(node, "direction"); + std::string direction = reinterpret_cast(key); + xmlFree(key); + + key = getProp(node, "length-var"); + std::string lengthVar = reinterpret_cast(key); + xmlFree(key); + + key = getProp(node, "speed-var"); + std::string speedVar = reinterpret_cast(key); + xmlFree(key); + + double length = items.at(lengthVar); + double speed = items.at(speedVar); + + AutomatableComponent::Action action; + + if (direction == "left") + { + action.speedX = -speed; + action.speedY = 0; + } else if (direction == "right") + { + action.speedX = speed; + action.speedY = 0; + } else if (direction == "up") + { + action.speedX = 0; + action.speedY = -speed; + } else if (direction == "down") + { + action.speedX = 0; + action.speedY = speed; + } + + action.dur = length / speed; + + behavior.push_back(std::move(action)); + } +} + // TODO: neither the XML doc nor any of the emplaced entities are properly // destroyed if this method throws an exception. EntityManager::id_type RealizingSystem::initSingleton( @@ -211,6 +299,70 @@ EntityManager::id_type RealizingSystem::initSingleton( game_.getSystemManager().getSystem(). initializeBody(mapObject, PonderableComponent::Type::vacuumed); + // Look for any object configuration. + std::map items; + + for (xmlNodePtr objectNode = mapNode->xmlChildrenNode; + objectNode != nullptr; + objectNode = objectNode->next) + { + if (!xmlStrcmp( + objectNode->name, + reinterpret_cast("item"))) + { + key = getProp(objectNode, "id"); + std::string itemName = reinterpret_cast(key); + xmlFree(key); + + key = xmlNodeGetContent(objectNode); + int itemVal = atoi(reinterpret_cast(key)); + xmlFree(key); + + items[itemName] = itemVal; + } + } + + // Add any AI behaviors. + std::vector behaviorWeights; + + for (xmlNodePtr protoSubNode = prototypeNode->xmlChildrenNode; + protoSubNode != nullptr; + protoSubNode = protoSubNode->next) + { + if (!xmlStrcmp( + protoSubNode->name, + reinterpret_cast("ai"))) + { + if (!game_.getEntityManager(). + hasComponent(mapObject)) + { + game_.getEntityManager(). + emplaceComponent(mapObject); + } + + auto& automatable = game_.getEntityManager(). + getComponent(mapObject); + + key = getProp(protoSubNode, "chance"); + behaviorWeights.push_back(atof(reinterpret_cast(key))); + xmlFree(key); + + std::vector behavior; + + for (xmlNodePtr aiNode = protoSubNode->xmlChildrenNode; + aiNode != nullptr; + aiNode = aiNode->next) + { + parseAI( + aiNode, + behavior, + items); + } + + automatable.behaviors.push_back(std::move(behavior)); + } + } + mappable.objects.push_back(mapObject); } else if (!xmlStrcmp( mapNode->name, @@ -304,6 +456,7 @@ void RealizingSystem::loadMap(id_type mapEntity) auto& animating = game_.getSystemManager().getSystem(); auto& pondering = game_.getSystemManager().getSystem(); + auto& automating = game_.getSystemManager().getSystem(); std::set players = game_.getEntityManager().getEntitiesWithComponents< @@ -366,6 +519,11 @@ void RealizingSystem::loadMap(id_type mapEntity) pondering.initPrototype(prototype); } + if (game_.getEntityManager().hasComponent(prototype)) + { + automating.initPrototype(prototype); + } + enterActiveMap(prototype); } @@ -399,6 +557,14 @@ void RealizingSystem::enterActiveMap(id_type entity) ponderable.active = true; } + + if (game_.getEntityManager().hasComponent(entity)) + { + auto& automatable = game_.getEntityManager(). + getComponent(entity); + + automatable.active = true; + } } void RealizingSystem::leaveActiveMap(id_type entity) @@ -418,4 +584,12 @@ void RealizingSystem::leaveActiveMap(id_type entity) ponderable.active = false; } + + if (game_.getEntityManager().hasComponent(entity)) + { + auto& automatable = game_.getEntityManager(). + getComponent(entity); + + automatable.active = false; + } } -- cgit 1.4.1 From 69c04dfb6c49e7b2d34a6699c071f037880fbde5 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 4 May 2018 00:08:35 -0400 Subject: Added ferrying (buggy) A freefalling body is considered to be "ferried" if it is grounded by another body (not a map). Its location is then dependent on the ferry's location; in this way, the ferry carries the passenger around. This implementation is kind of buggy currently: first of all, ferrying does not work vertically upward, because the ferry will consider the passenger to be a wall and will not continue moving upward. Second, ferries are not processed before passengers, so passengers can move in a physics tick using the knowledge of a ferry's location before it moves in that tick. Third, if the transform coordinates are set by any system other than the PonderingSystem, the relative coordinates to the ferry will not be updated and the body will not be unferried if necessary. This is still a cool commit because, three years later, we have finally overcome the issue that stopped development on the original branch in 2015. --- src/components/ponderable.h | 33 ++++++++++++++++++++++++++ src/systems/pondering.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++-- src/systems/pondering.h | 1 + 3 files changed, 89 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/components/ponderable.h b/src/components/ponderable.h index 5354f87..45150a0 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -1,11 +1,15 @@ #ifndef TANGIBLE_H_746DB3EE #define TANGIBLE_H_746DB3EE +#include #include "component.h" +#include "entity_manager.h" class PonderableComponent : public Component { public: + using id_type = EntityManager::id_type; + /** * List of different types of physical bodies. * @@ -66,6 +70,35 @@ public: */ bool grounded = false; + /** + * Whether or not a freefalling body is being ferried by another body. + * + * @managed_by PonderingSystem + */ + bool ferried = false; + + /** + * The entity that is ferrying this body, if there is one. + * + * @managed_by PonderingSystem + */ + id_type ferry; + + /** + * The location of the body relative to the location of its ferry. + * + * @managed_by PonderingSystem + */ + double relX; + double relY; + + /** + * The bodies that are being ferried by this body. + * + * @managed_by PonderingSystem + */ + std::set passengers; + /** * If enabled, this will prevent the body from moving. */ diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 5143f8e..ccfd66f 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -57,8 +57,21 @@ void PonderingSystem::tick(double dt) const double oldBottom = oldY + transformable.h; CollisionResult result; - result.newX = oldX + ponderable.velX * dt; - result.newY = oldY + ponderable.velY * dt; + + if (ponderable.ferried) + { + auto& ferryTrans = game_.getEntityManager(). + getComponent(ponderable.ferry); + + result.newX = ferryTrans.x + ponderable.relX; + result.newY = ferryTrans.y + ponderable.relY; + } else { + result.newX = transformable.x; + result.newY = transformable.y; + } + + result.newX += ponderable.velX * dt; + result.newY += ponderable.velY * dt; bool oldGrounded = ponderable.grounded; ponderable.grounded = false; @@ -642,6 +655,43 @@ void PonderingSystem::tick(double dt) } } + // Handle ferry passengers + if ((ponderable.type == PonderableComponent::Type::freefalling) && + (ponderable.grounded != oldGrounded)) + { + if (ponderable.grounded && + game_.getEntityManager(). + hasComponent(result.groundEntity)) + { + // The body is now being ferried + auto& ferryPonder = game_.getEntityManager(). + getComponent(result.groundEntity); + + ponderable.ferried = true; + ponderable.ferry = result.groundEntity; + + ferryPonder.passengers.insert(entity); + } else if (ponderable.ferried) + { + // The body is no longer being ferried + ponderable.ferried = false; + + auto& ferryPonder = game_.getEntityManager(). + getComponent(ponderable.ferry); + + ferryPonder.passengers.erase(entity); + } + } + + if (ponderable.ferried) + { + auto& ferryTrans = game_.getEntityManager(). + getComponent(ponderable.ferry); + + ponderable.relX = transformable.x - ferryTrans.x; + ponderable.relY = transformable.y - ferryTrans.y; + } + // Move to an adjacent map, if necessary if (result.adjacentlyWarping) { @@ -714,6 +764,8 @@ void PonderingSystem::initPrototype(id_type prototype) ponderable.grounded = false; ponderable.frozen = false; ponderable.collidable = true; + ponderable.ferried = false; + ponderable.passengers.clear(); } void PonderingSystem::processCollision( @@ -900,6 +952,7 @@ void PonderingSystem::processCollision( case Direction::down: { result.newY = axis - transformable.h; + result.groundEntity = collider; ponderable.velY = 0.0; ponderable.grounded = true; diff --git a/src/systems/pondering.h b/src/systems/pondering.h index aa430db..b195814 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -29,6 +29,7 @@ private: bool adjacentlyWarping = false; Direction adjWarpDir; size_t adjWarpMapId; + id_type groundEntity; }; void processCollision( -- cgit 1.4.1 From 123192db10cdf5244f27d08256ece738f60a9e2c Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 4 May 2018 10:23:02 -0400 Subject: Unferried players while changing maps This fixes the third problem described in 8f1c4f1 -- that if a ferried body's transform is modified outside of the PonderingSystem, it will not be unferried as appropriate. This does still require that any future code that modifies a body's transform also unferries the body first. --- src/systems/playing.cpp | 8 +++----- src/systems/pondering.cpp | 26 +++++++++++++++++++------- src/systems/pondering.h | 14 ++++++++++++++ 3 files changed, 36 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/systems/playing.cpp b/src/systems/playing.cpp index b04f0cb..acec4e7 100644 --- a/src/systems/playing.cpp +++ b/src/systems/playing.cpp @@ -79,11 +79,7 @@ void PlayingSystem::changeMap( auto& transformable = game_.getEntityManager(). getComponent(player); - auto& animatable = game_.getEntityManager(). - getComponent(player); - - auto& ponderable = game_.getEntityManager(). - getComponent(player); + auto& pondering = game_.getSystemManager().getSystem(); auto& realizing = game_.getSystemManager().getSystem(); @@ -105,6 +101,8 @@ void PlayingSystem::changeMap( playable.mapId = newMapEntity; } + pondering.unferry(player); + transformable.x = x; transformable.y = y; diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index ccfd66f..4aa47f2 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -655,7 +655,7 @@ void PonderingSystem::tick(double dt) } } - // Handle ferry passengers + // Ferry or unferry as necessary if ((ponderable.type == PonderableComponent::Type::freefalling) && (ponderable.grounded != oldGrounded)) { @@ -674,15 +674,11 @@ void PonderingSystem::tick(double dt) } else if (ponderable.ferried) { // The body is no longer being ferried - ponderable.ferried = false; - - auto& ferryPonder = game_.getEntityManager(). - getComponent(ponderable.ferry); - - ferryPonder.passengers.erase(entity); + unferry(entity); } } + // Update a ferry passenger's relative position if (ponderable.ferried) { auto& ferryTrans = game_.getEntityManager(). @@ -768,6 +764,22 @@ void PonderingSystem::initPrototype(id_type prototype) ponderable.passengers.clear(); } +void PonderingSystem::unferry(id_type entity) +{ + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + + if (ponderable.ferried) + { + ponderable.ferried = false; + + auto& ferryPonder = game_.getEntityManager(). + getComponent(ponderable.ferry); + + ferryPonder.passengers.erase(entity); + } +} + void PonderingSystem::processCollision( id_type entity, id_type collider, diff --git a/src/systems/pondering.h b/src/systems/pondering.h index b195814..adc0cda 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -16,8 +16,22 @@ public: void initializeBody(id_type entity, PonderableComponent::Type type); + /** + * Initializes a ponderable map object from its prototype data. + * + * @requires entity is ponderable + * @requires entity is a map object + */ void initPrototype(id_type prototype); + /** + * Unferries an entity if it is a passenger of another entity. Use before + * moving a ponderable entity outside the PonderingSystem. + * + * @requires entity is ponderable + */ + void unferry(id_type entity); + private: struct CollisionResult -- cgit 1.4.1 From ff99cefc647f9215ad1cdc9f408c9fc655b45706 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 4 May 2018 10:26:07 -0400 Subject: Added a comment to TransformableComponent describing the ferrying stipulation --- src/components/transformable.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/components/transformable.h b/src/components/transformable.h index 3296e49..6f3c2ef 100644 --- a/src/components/transformable.h +++ b/src/components/transformable.h @@ -8,6 +8,12 @@ public: /** * The coordinates of the entity. + * + * Note that ponderable entities sometimes have special behavior related to + * their coordinates, specifically that ferried bodies will behave oddly if + * their coordinates are changed outside of the PonderingSystem. Before doing + * so, use PonderingSystem::unferry on the body to ensure that it is not + * ferried. */ double x; double y; -- cgit 1.4.1 From 893dbf8a235db2b4f1fafacf90290b0821f0048c Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 4 May 2018 10:50:15 -0400 Subject: Recursively handle ferried bodies PonderingSystem now recursively ticks bodies, starting with unferried bodies at the top level, and recursively ticking their passengers. This fixes the second issue described in 8f1c4f1 -- that passengers may be ticked before their ferries, causing it to use out-of-date information about the ferry's location. --- src/systems/pondering.cpp | 1232 +++++++++++++++++++++++---------------------- src/systems/pondering.h | 5 + 2 files changed, 637 insertions(+), 600 deletions(-) (limited to 'src') diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 4aa47f2..e6417eb 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -15,15 +15,6 @@ void PonderingSystem::tick(double dt) { - auto& realizable = game_.getEntityManager(). - getComponent( - game_.getSystemManager().getSystem().getSingleton()); - - id_type mapEntity = realizable.activeMap; - - auto& mappable = game_.getEntityManager(). - getComponent(mapEntity); - auto entities = game_.getEntityManager().getEntitiesWithComponents< PonderableComponent, TransformableComponent>(); @@ -33,750 +24,791 @@ void PonderingSystem::tick(double dt) auto& ponderable = game_.getEntityManager(). getComponent(entity); - if (!ponderable.active || ponderable.frozen) + // We will recursively process ferried bodies after their ferries have been + // processed, so hold off on processing ferried bodies at the top level. + if (ponderable.ferried) { continue; } - auto& transformable = game_.getEntityManager(). - getComponent(entity); + tickBody( + entity, + dt, + entities); + } +} - // Accelerate - ponderable.velX += ponderable.accelX * dt; - ponderable.velY += ponderable.accelY * dt; +void PonderingSystem::initializeBody( + id_type entity, + PonderableComponent::Type type) +{ + auto& ponderable = game_.getEntityManager(). + emplaceComponent(entity, type); - if ((ponderable.type == PonderableComponent::Type::freefalling) - && (ponderable.velY > TERMINAL_VELOCITY)) - { - ponderable.velY = TERMINAL_VELOCITY; - } + if (type == PonderableComponent::Type::freefalling) + { + ponderable.accelY = NORMAL_GRAVITY; + } +} - const double oldX = transformable.x; - const double oldY = transformable.y; - const double oldRight = oldX + transformable.w; - const double oldBottom = oldY + transformable.h; +void PonderingSystem::initPrototype(id_type prototype) +{ + auto& ponderable = game_.getEntityManager(). + getComponent(prototype); - CollisionResult result; + ponderable.velX = 0.0; + ponderable.velY = 0.0; + ponderable.accelX = 0.0; + ponderable.accelY = 0.0; + ponderable.grounded = false; + ponderable.frozen = false; + ponderable.collidable = true; + ponderable.ferried = false; + ponderable.passengers.clear(); +} - if (ponderable.ferried) - { - auto& ferryTrans = game_.getEntityManager(). - getComponent(ponderable.ferry); - - result.newX = ferryTrans.x + ponderable.relX; - result.newY = ferryTrans.y + ponderable.relY; - } else { - result.newX = transformable.x; - result.newY = transformable.y; - } +void PonderingSystem::unferry(id_type entity) +{ + auto& ponderable = game_.getEntityManager(). + getComponent(entity); - result.newX += ponderable.velX * dt; - result.newY += ponderable.velY * dt; + if (ponderable.ferried) + { + ponderable.ferried = false; - bool oldGrounded = ponderable.grounded; - ponderable.grounded = false; + auto& ferryPonder = game_.getEntityManager(). + getComponent(ponderable.ferry); - // Find horizontal collisions. - if (result.newX < oldX) - { - bool boundaryCollision = false; - auto it = mappable.leftBoundaries.lower_bound(oldX); + ferryPonder.passengers.erase(entity); + } +} - // Find the axis distance of the closest environmental boundary. - for (; - (it != std::end(mappable.leftBoundaries)) && - (it->first >= result.newX); - it++) - { - // Check that the boundary is in range for the other axis. - if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) - { - // We have a collision! - boundaryCollision = true; +void PonderingSystem::tickBody( + id_type entity, + double dt, + const std::set& entities) +{ + auto& ponderable = game_.getEntityManager(). + getComponent(entity); - break; - } - } + if (!ponderable.active || ponderable.frozen) + { + continue; + } - // Find a list of potential colliders, sorted so that the closest is - // first. - std::vector colliders; + auto& realizable = game_.getEntityManager(). + getComponent( + game_.getSystemManager().getSystem().getSingleton()); - for (id_type collider : entities) - { - // Can't collide with self. - if (collider == entity) - { - continue; - } + id_type mapEntity = realizable.activeMap; - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + auto& mappable = game_.getEntityManager(). + getComponent(mapEntity); - // Only check objects that are active. - if (!colliderPonder.active) - { - continue; - } + auto& transformable = game_.getEntityManager(). + getComponent(entity); - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); - - // Check if the entity would move into the potential collider, - if ((colliderTrans.x + colliderTrans.w > result.newX) && - // that it wasn't already colliding, - (colliderTrans.x + colliderTrans.w <= oldX) && - // that the position on the other axis is in range, - (colliderTrans.y + colliderTrans.h > oldY) && - (colliderTrans.y < oldBottom) && - // and that the collider is not farther away than the environmental - // boundary. - (!boundaryCollision || - (colliderTrans.x + colliderTrans.w >= it->first))) - { - colliders.push_back(collider); - } - } + // Accelerate + ponderable.velX += ponderable.accelX * dt; + ponderable.velY += ponderable.accelY * dt; - std::sort( - std::begin(colliders), - std::end(colliders), - [&] (id_type left, id_type right) { - auto& leftTrans = game_.getEntityManager(). - getComponent(left); + if ((ponderable.type == PonderableComponent::Type::freefalling) + && (ponderable.velY > TERMINAL_VELOCITY)) + { + ponderable.velY = TERMINAL_VELOCITY; + } - auto& rightTrans = game_.getEntityManager(). - getComponent(right); + const double oldX = transformable.x; + const double oldY = transformable.y; + const double oldRight = oldX + transformable.w; + const double oldBottom = oldY + transformable.h; - return (rightTrans.x < leftTrans.x); - }); + CollisionResult result; - for (id_type collider : colliders) - { - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); + if (ponderable.ferried) + { + auto& ferryTrans = game_.getEntityManager(). + getComponent(ponderable.ferry); + + result.newX = ferryTrans.x + ponderable.relX; + result.newY = ferryTrans.y + ponderable.relY; + } else { + result.newX = transformable.x; + result.newY = transformable.y; + } - // Check if the entity would still move into the potential collider. - if (colliderTrans.x + colliderTrans.w <= result.newX) - { - break; - } + result.newX += ponderable.velX * dt; + result.newY += ponderable.velY * dt; - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + bool oldGrounded = ponderable.grounded; + ponderable.grounded = false; - processCollision( - entity, - collider, - Direction::left, - colliderPonder.colliderType, - colliderTrans.x + colliderTrans.w, - colliderTrans.y, - colliderTrans.y + colliderTrans.h, - result); + // Find horizontal collisions. + if (result.newX < oldX) + { + bool boundaryCollision = false; + auto it = mappable.leftBoundaries.lower_bound(oldX); + + // Find the axis distance of the closest environmental boundary. + for (; + (it != std::end(mappable.leftBoundaries)) && + (it->first >= result.newX); + it++) + { + // Check that the boundary is in range for the other axis. + if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) + { + // We have a collision! + boundaryCollision = true; - if (result.stopProcessing) - { - break; - } + break; } + } - // If movement hasn't been stopped by an intermediary object, and - // collision checking hasn't been stopped, process the environmental - // boundaries closest to the entity. - if (!result.stopProcessing && !result.touchedWall && boundaryCollision) - { - double boundaryAxis = it->first; + // Find a list of potential colliders, sorted so that the closest is + // first. + std::vector colliders; - for (; - (it != std::end(mappable.leftBoundaries)) && - (it->first == boundaryAxis); - it++) - { - if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) - { - processCollision( - entity, - mapEntity, - Direction::left, - it->second.type, - it->first, - it->second.lower, - it->second.upper, - result); - - if (result.stopProcessing) - { - break; - } - } - } - } - } else if (result.newX > oldX) + for (id_type collider : entities) { - bool boundaryCollision = false; - auto it = mappable.rightBoundaries.lower_bound(oldRight); - - // Find the axis distance of the closest environmental boundary. - for (; - (it != std::end(mappable.rightBoundaries)) - && (it->first <= (result.newX + transformable.w)); - it++) + // Can't collide with self. + if (collider == entity) { - // Check that the boundary is in range for the other axis. - if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) - { - // We have a collision! - boundaryCollision = true; - - break; - } + continue; } - // Find a list of potential colliders, sorted so that the closest is - // first. - std::vector colliders; + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - for (id_type collider : entities) + // Only check objects that are active. + if (!colliderPonder.active) { - // Can't collide with self. - if (collider == entity) - { - continue; - } - - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); - - // Only check objects that are active. - if (!colliderPonder.active) - { - continue; - } + continue; + } - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); - - // Check if the entity would move into the potential collider, - if ((colliderTrans.x < result.newX + transformable.w) && - // that it wasn't already colliding, - (colliderTrans.x >= oldRight) && - // that the position on the other axis is in range, - (colliderTrans.y + colliderTrans.h > oldY) && - (colliderTrans.y < oldBottom) && - // and that the collider is not farther away than the environmental - // boundary. - (!boundaryCollision || (colliderTrans.x <= it->first))) - { - colliders.push_back(collider); - } + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would move into the potential collider, + if ((colliderTrans.x + colliderTrans.w > result.newX) && + // that it wasn't already colliding, + (colliderTrans.x + colliderTrans.w <= oldX) && + // that the position on the other axis is in range, + (colliderTrans.y + colliderTrans.h > oldY) && + (colliderTrans.y < oldBottom) && + // and that the collider is not farther away than the environmental + // boundary. + (!boundaryCollision || + (colliderTrans.x + colliderTrans.w >= it->first))) + { + colliders.push_back(collider); } + } - std::sort( - std::begin(colliders), - std::end(colliders), - [&] (id_type left, id_type right) { - auto& leftTrans = game_.getEntityManager(). - getComponent(left); + std::sort( + std::begin(colliders), + std::end(colliders), + [&] (id_type left, id_type right) { + auto& leftTrans = game_.getEntityManager(). + getComponent(left); - auto& rightTrans = game_.getEntityManager(). - getComponent(right); + auto& rightTrans = game_.getEntityManager(). + getComponent(right); - return (leftTrans.x < rightTrans.x); - }); + return (rightTrans.x < leftTrans.x); + }); - for (id_type collider : colliders) - { - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); + for (id_type collider : colliders) + { + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); - // Check if the entity would still move into the potential collider. - if (colliderTrans.x >= result.newX + transformable.w) - { - break; - } + // Check if the entity would still move into the potential collider. + if (colliderTrans.x + colliderTrans.w <= result.newX) + { + break; + } - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - processCollision( - entity, - collider, - Direction::right, - colliderPonder.colliderType, - colliderTrans.x, - colliderTrans.y, - colliderTrans.y + colliderTrans.h, - result); + processCollision( + entity, + collider, + Direction::left, + colliderPonder.colliderType, + colliderTrans.x + colliderTrans.w, + colliderTrans.y, + colliderTrans.y + colliderTrans.h, + result); - if (result.stopProcessing) - { - break; - } + if (result.stopProcessing) + { + break; } + } - // If movement hasn't been stopped by an intermediary object, and - // collision checking hasn't been stopped, process the environmental - // boundaries closest to the entity. - if (!result.stopProcessing && !result.touchedWall && boundaryCollision) - { - double boundaryAxis = it->first; + // If movement hasn't been stopped by an intermediary object, and + // collision checking hasn't been stopped, process the environmental + // boundaries closest to the entity. + if (!result.stopProcessing && !result.touchedWall && boundaryCollision) + { + double boundaryAxis = it->first; - for (; - (it != std::end(mappable.rightBoundaries)) && - (it->first == boundaryAxis); - it++) + for (; + (it != std::end(mappable.leftBoundaries)) && + (it->first == boundaryAxis); + it++) + { + if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) { - if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) + processCollision( + entity, + mapEntity, + Direction::left, + it->second.type, + it->first, + it->second.lower, + it->second.upper, + result); + + if (result.stopProcessing) { - processCollision( - entity, - mapEntity, - Direction::right, - it->second.type, - it->first, - it->second.lower, - it->second.upper, - result); - - if (result.stopProcessing) - { - break; - } + break; } } } } - - // Find vertical collisions - result.touchedWall = false; - - if ((!result.stopProcessing) && (result.newY < oldY)) + } else if (result.newX > oldX) + { + bool boundaryCollision = false; + auto it = mappable.rightBoundaries.lower_bound(oldRight); + + // Find the axis distance of the closest environmental boundary. + for (; + (it != std::end(mappable.rightBoundaries)) + && (it->first <= (result.newX + transformable.w)); + it++) { - bool boundaryCollision = false; - auto it = mappable.upBoundaries.lower_bound(oldY); - - // Find the axis distance of the closest environmental boundary. - for (; - (it != std::end(mappable.upBoundaries)) && - (it->first >= result.newY); - it++) + // Check that the boundary is in range for the other axis. + if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) { - // Check that the boundary is in range for the other axis. - if ((result.newX + transformable.h > it->second.lower) && - (result.newX < it->second.upper)) - { - // We have a collision! - boundaryCollision = true; + // We have a collision! + boundaryCollision = true; - break; - } + break; } + } - // Find a list of potential colliders, sorted so that the closest is - // first. - std::vector colliders; + // Find a list of potential colliders, sorted so that the closest is + // first. + std::vector colliders; - for (id_type collider : entities) + for (id_type collider : entities) + { + // Can't collide with self. + if (collider == entity) { - // Can't collide with self. - if (collider == entity) - { - continue; - } + continue; + } - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - // Only check objects that are active. - if (!colliderPonder.active) - { - continue; - } + // Only check objects that are active. + if (!colliderPonder.active) + { + continue; + } - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); - - // Check if the entity would move into the potential collider, - if ((colliderTrans.y + colliderTrans.h > result.newY) && - // that it wasn't already colliding, - (colliderTrans.y + colliderTrans.h <= oldY) && - // that the position on the other axis is in range, - (colliderTrans.x + colliderTrans.w > result.newX) && - (colliderTrans.x < result.newX + transformable.w) && - // and that the collider is not farther away than the environmental - // boundary. - (!boundaryCollision || - (colliderTrans.y + colliderTrans.h >= it->first))) - { - colliders.push_back(collider); - } + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would move into the potential collider, + if ((colliderTrans.x < result.newX + transformable.w) && + // that it wasn't already colliding, + (colliderTrans.x >= oldRight) && + // that the position on the other axis is in range, + (colliderTrans.y + colliderTrans.h > oldY) && + (colliderTrans.y < oldBottom) && + // and that the collider is not farther away than the environmental + // boundary. + (!boundaryCollision || (colliderTrans.x <= it->first))) + { + colliders.push_back(collider); } + } - std::sort( - std::begin(colliders), - std::end(colliders), - [&] (id_type left, id_type right) { - auto& leftTrans = game_.getEntityManager(). - getComponent(left); + std::sort( + std::begin(colliders), + std::end(colliders), + [&] (id_type left, id_type right) { + auto& leftTrans = game_.getEntityManager(). + getComponent(left); - auto& rightTrans = game_.getEntityManager(). - getComponent(right); + auto& rightTrans = game_.getEntityManager(). + getComponent(right); - return (rightTrans.y < leftTrans.y); - }); + return (leftTrans.x < rightTrans.x); + }); - for (id_type collider : colliders) - { - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); + for (id_type collider : colliders) + { + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); - // Check if the entity would still move into the potential collider. - if (colliderTrans.y + colliderTrans.h <= result.newY) - { - break; - } + // Check if the entity would still move into the potential collider. + if (colliderTrans.x >= result.newX + transformable.w) + { + break; + } - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - processCollision( - entity, - collider, - Direction::up, - colliderPonder.colliderType, - colliderTrans.y + colliderTrans.h, - colliderTrans.x, - colliderTrans.x + colliderTrans.w, - result); + processCollision( + entity, + collider, + Direction::right, + colliderPonder.colliderType, + colliderTrans.x, + colliderTrans.y, + colliderTrans.y + colliderTrans.h, + result); - if (result.stopProcessing) - { - break; - } + if (result.stopProcessing) + { + break; } + } - // If movement hasn't been stopped by an intermediary object, and - // collision checking hasn't been stopped, process the environmental - // boundaries closest to the entity. - if (!result.stopProcessing && !result.touchedWall && boundaryCollision) - { - double boundaryAxis = it->first; + // If movement hasn't been stopped by an intermediary object, and + // collision checking hasn't been stopped, process the environmental + // boundaries closest to the entity. + if (!result.stopProcessing && !result.touchedWall && boundaryCollision) + { + double boundaryAxis = it->first; - for (; - (it != std::end(mappable.upBoundaries)) && - (it->first == boundaryAxis); - it++) + for (; + (it != std::end(mappable.rightBoundaries)) && + (it->first == boundaryAxis); + it++) + { + if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) { - if ((result.newX + transformable.w > it->second.lower) && - (result.newX < it->second.upper)) + processCollision( + entity, + mapEntity, + Direction::right, + it->second.type, + it->first, + it->second.lower, + it->second.upper, + result); + + if (result.stopProcessing) { - processCollision( - entity, - mapEntity, - Direction::up, - it->second.type, - it->first, - it->second.lower, - it->second.upper, - result); - - if (result.stopProcessing) - { - break; - } + break; } } } - } else if ((!result.stopProcessing) && (result.newY > oldY)) - { - bool boundaryCollision = false; - auto it = mappable.downBoundaries.lower_bound(oldBottom); + } + } - // Find the axis distance of the closest environmental boundary. - for (; - (it != std::end(mappable.downBoundaries)) - && (it->first <= (result.newY + transformable.h)); - it++) + // Find vertical collisions + result.touchedWall = false; + + if ((!result.stopProcessing) && (result.newY < oldY)) + { + bool boundaryCollision = false; + auto it = mappable.upBoundaries.lower_bound(oldY); + + // Find the axis distance of the closest environmental boundary. + for (; + (it != std::end(mappable.upBoundaries)) && + (it->first >= result.newY); + it++) + { + // Check that the boundary is in range for the other axis. + if ((result.newX + transformable.h > it->second.lower) && + (result.newX < it->second.upper)) { - // Check that the boundary is in range for the other axis. - if ((result.newX + transformable.w > it->second.lower) && - (result.newX < it->second.upper)) - { - // We have a collision! - boundaryCollision = true; + // We have a collision! + boundaryCollision = true; - break; - } + break; } + } - // Find a list of potential colliders, sorted so that the closest is - // first. - std::vector colliders; + // Find a list of potential colliders, sorted so that the closest is + // first. + std::vector colliders; - for (id_type collider : entities) + for (id_type collider : entities) + { + // Can't collide with self. + if (collider == entity) { - // Can't collide with self. - if (collider == entity) - { - continue; - } + continue; + } - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - // Only check objects that are active. - if (!colliderPonder.active) - { - continue; - } + // Only check objects that are active. + if (!colliderPonder.active) + { + continue; + } - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); - - // Check if the entity would move into the potential collider, - if ((colliderTrans.y < result.newY + transformable.h) && - // that it wasn't already colliding, - (colliderTrans.y >= oldBottom) && - // that the position on the other axis is in range, - (colliderTrans.x + colliderTrans.w > result.newX) && - (colliderTrans.x < result.newX + transformable.w) && - // and that the collider is not farther away than the environmental - // boundary. - (!boundaryCollision || (colliderTrans.y <= it->first))) - { - colliders.push_back(collider); - } + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would move into the potential collider, + if ((colliderTrans.y + colliderTrans.h > result.newY) && + // that it wasn't already colliding, + (colliderTrans.y + colliderTrans.h <= oldY) && + // that the position on the other axis is in range, + (colliderTrans.x + colliderTrans.w > result.newX) && + (colliderTrans.x < result.newX + transformable.w) && + // and that the collider is not farther away than the environmental + // boundary. + (!boundaryCollision || + (colliderTrans.y + colliderTrans.h >= it->first))) + { + colliders.push_back(collider); } + } - std::sort( - std::begin(colliders), - std::end(colliders), - [&] (id_type left, id_type right) { - auto& leftTrans = game_.getEntityManager(). - getComponent(left); + std::sort( + std::begin(colliders), + std::end(colliders), + [&] (id_type left, id_type right) { + auto& leftTrans = game_.getEntityManager(). + getComponent(left); - auto& rightTrans = game_.getEntityManager(). - getComponent(right); + auto& rightTrans = game_.getEntityManager(). + getComponent(right); - return (leftTrans.y < rightTrans.y); - }); + return (rightTrans.y < leftTrans.y); + }); - for (id_type collider : colliders) - { - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); + for (id_type collider : colliders) + { + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); - // Check if the entity would still move into the potential collider. - if (colliderTrans.y >= result.newY + transformable.h) - { - break; - } + // Check if the entity would still move into the potential collider. + if (colliderTrans.y + colliderTrans.h <= result.newY) + { + break; + } - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - processCollision( - entity, - collider, - Direction::down, - colliderPonder.colliderType, - colliderTrans.y, - colliderTrans.x, - colliderTrans.x + colliderTrans.w, - result); + processCollision( + entity, + collider, + Direction::up, + colliderPonder.colliderType, + colliderTrans.y + colliderTrans.h, + colliderTrans.x, + colliderTrans.x + colliderTrans.w, + result); - if (result.stopProcessing) - { - break; - } + if (result.stopProcessing) + { + break; } + } - // If movement hasn't been stopped by an intermediary object, and - // collision checking hasn't been stopped, process the environmental - // boundaries closest to the entity. - if (!result.stopProcessing && !result.touchedWall && boundaryCollision) - { - double boundaryAxis = it->first; + // If movement hasn't been stopped by an intermediary object, and + // collision checking hasn't been stopped, process the environmental + // boundaries closest to the entity. + if (!result.stopProcessing && !result.touchedWall && boundaryCollision) + { + double boundaryAxis = it->first; - for (; - (it != std::end(mappable.downBoundaries)) && - (it->first == boundaryAxis); - it++) + for (; + (it != std::end(mappable.upBoundaries)) && + (it->first == boundaryAxis); + it++) + { + if ((result.newX + transformable.w > it->second.lower) && + (result.newX < it->second.upper)) { - if ((result.newX + transformable.w > it->second.lower) && - (result.newX < it->second.upper)) + processCollision( + entity, + mapEntity, + Direction::up, + it->second.type, + it->first, + it->second.lower, + it->second.upper, + result); + + if (result.stopProcessing) { - processCollision( - entity, - mapEntity, - Direction::down, - it->second.type, - it->first, - it->second.lower, - it->second.upper, - result); - - if (result.stopProcessing) - { - break; - } + break; } } } } + } else if ((!result.stopProcessing) && (result.newY > oldY)) + { + bool boundaryCollision = false; + auto it = mappable.downBoundaries.lower_bound(oldBottom); + + // Find the axis distance of the closest environmental boundary. + for (; + (it != std::end(mappable.downBoundaries)) + && (it->first <= (result.newY + transformable.h)); + it++) + { + // Check that the boundary is in range for the other axis. + if ((result.newX + transformable.w > it->second.lower) && + (result.newX < it->second.upper)) + { + // We have a collision! + boundaryCollision = true; - // Move - transformable.x = result.newX; - transformable.y = result.newY; + break; + } + } + + // Find a list of potential colliders, sorted so that the closest is + // first. + std::vector colliders; - // Perform cleanup for orientable entites - if (game_.getEntityManager().hasComponent(entity)) + for (id_type collider : entities) { - auto& orientable = game_.getEntityManager(). - getComponent(entity); + // Can't collide with self. + if (collider == entity) + { + continue; + } + + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - // Handle changes in groundedness - if (ponderable.grounded != oldGrounded) + // Only check objects that are active. + if (!colliderPonder.active) { - if (ponderable.grounded) - { - game_.getSystemManager().getSystem().land(entity); - } else { - game_.getSystemManager(). - getSystem().startFalling(entity); - } + continue; } - // Complete dropping, if necessary - if (orientable.getDropState() == OrientableComponent::DropState::active) + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would move into the potential collider, + if ((colliderTrans.y < result.newY + transformable.h) && + // that it wasn't already colliding, + (colliderTrans.y >= oldBottom) && + // that the position on the other axis is in range, + (colliderTrans.x + colliderTrans.w > result.newX) && + (colliderTrans.x < result.newX + transformable.w) && + // and that the collider is not farther away than the environmental + // boundary. + (!boundaryCollision || (colliderTrans.y <= it->first))) { - orientable.setDropState(OrientableComponent::DropState::none); + colliders.push_back(collider); } } - // Ferry or unferry as necessary - if ((ponderable.type == PonderableComponent::Type::freefalling) && - (ponderable.grounded != oldGrounded)) - { - if (ponderable.grounded && - game_.getEntityManager(). - hasComponent(result.groundEntity)) - { - // The body is now being ferried - auto& ferryPonder = game_.getEntityManager(). - getComponent(result.groundEntity); + std::sort( + std::begin(colliders), + std::end(colliders), + [&] (id_type left, id_type right) { + auto& leftTrans = game_.getEntityManager(). + getComponent(left); + + auto& rightTrans = game_.getEntityManager(). + getComponent(right); - ponderable.ferried = true; - ponderable.ferry = result.groundEntity; + return (leftTrans.y < rightTrans.y); + }); - ferryPonder.passengers.insert(entity); - } else if (ponderable.ferried) + for (id_type collider : colliders) + { + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would still move into the potential collider. + if (colliderTrans.y >= result.newY + transformable.h) { - // The body is no longer being ferried - unferry(entity); + break; } - } - // Update a ferry passenger's relative position - if (ponderable.ferried) - { - auto& ferryTrans = game_.getEntityManager(). - getComponent(ponderable.ferry); + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - ponderable.relX = transformable.x - ferryTrans.x; - ponderable.relY = transformable.y - ferryTrans.y; + processCollision( + entity, + collider, + Direction::down, + colliderPonder.colliderType, + colliderTrans.y, + colliderTrans.x, + colliderTrans.x + colliderTrans.w, + result); + + if (result.stopProcessing) + { + break; + } } - // Move to an adjacent map, if necessary - if (result.adjacentlyWarping) + // If movement hasn't been stopped by an intermediary object, and + // collision checking hasn't been stopped, process the environmental + // boundaries closest to the entity. + if (!result.stopProcessing && !result.touchedWall && boundaryCollision) { - double warpX = result.newX; - double warpY = result.newY; + double boundaryAxis = it->first; - switch (result.adjWarpDir) + for (; + (it != std::end(mappable.downBoundaries)) && + (it->first == boundaryAxis); + it++) { - case Direction::left: + if ((result.newX + transformable.w > it->second.lower) && + (result.newX < it->second.upper)) { - warpX = GAME_WIDTH + WALL_GAP - transformable.w; - - break; + processCollision( + entity, + mapEntity, + Direction::down, + it->second.type, + it->first, + it->second.lower, + it->second.upper, + result); + + if (result.stopProcessing) + { + break; + } } + } + } + } - case Direction::right: - { - warpX = -WALL_GAP; + // Move + transformable.x = result.newX; + transformable.y = result.newY; - break; - } + // Perform cleanup for orientable entites + if (game_.getEntityManager().hasComponent(entity)) + { + auto& orientable = game_.getEntityManager(). + getComponent(entity); - case Direction::up: - { - warpY = MAP_HEIGHT * TILE_HEIGHT - transformable.h; + // Handle changes in groundedness + if (ponderable.grounded != oldGrounded) + { + if (ponderable.grounded) + { + game_.getSystemManager().getSystem().land(entity); + } else { + game_.getSystemManager(). + getSystem().startFalling(entity); + } + } - break; - } + // Complete dropping, if necessary + if (orientable.getDropState() == OrientableComponent::DropState::active) + { + orientable.setDropState(OrientableComponent::DropState::none); + } + } - case Direction::down: - { - warpY = -WALL_GAP; + // Ferry or unferry as necessary + if ((ponderable.type == PonderableComponent::Type::freefalling) && + (ponderable.grounded != oldGrounded)) + { + if (ponderable.grounded && + game_.getEntityManager(). + hasComponent(result.groundEntity)) + { + // The body is now being ferried + auto& ferryPonder = game_.getEntityManager(). + getComponent(result.groundEntity); - break; - } - } + ponderable.ferried = true; + ponderable.ferry = result.groundEntity; - game_.getSystemManager().getSystem(). - changeMap( - entity, - result.adjWarpMapId, - warpX, - warpY); + ferryPonder.passengers.insert(entity); + } else if (ponderable.ferried) + { + // The body is no longer being ferried + unferry(entity); } } -} -void PonderingSystem::initializeBody( - id_type entity, - PonderableComponent::Type type) -{ - auto& ponderable = game_.getEntityManager(). - emplaceComponent(entity, type); + // Update a ferry passenger's relative position + if (ponderable.ferried) + { + auto& ferryTrans = game_.getEntityManager(). + getComponent(ponderable.ferry); - if (type == PonderableComponent::Type::freefalling) + ponderable.relX = transformable.x - ferryTrans.x; + ponderable.relY = transformable.y - ferryTrans.y; + } + + // Handle ferry passengers + std::set passengers = ponderable.passengers; + + for (id_type passenger : passengers) { - ponderable.accelY = NORMAL_GRAVITY; + tickBody( + passenger, + dt, + entities); } -} -void PonderingSystem::initPrototype(id_type prototype) -{ - auto& ponderable = game_.getEntityManager(). - getComponent(prototype); + // Move to an adjacent map, if necessary + if (result.adjacentlyWarping) + { + double warpX = result.newX; + double warpY = result.newY; - ponderable.velX = 0.0; - ponderable.velY = 0.0; - ponderable.accelX = 0.0; - ponderable.accelY = 0.0; - ponderable.grounded = false; - ponderable.frozen = false; - ponderable.collidable = true; - ponderable.ferried = false; - ponderable.passengers.clear(); -} + switch (result.adjWarpDir) + { + case Direction::left: + { + warpX = GAME_WIDTH + WALL_GAP - transformable.w; -void PonderingSystem::unferry(id_type entity) -{ - auto& ponderable = game_.getEntityManager(). - getComponent(entity); + break; + } - if (ponderable.ferried) - { - ponderable.ferried = false; + case Direction::right: + { + warpX = -WALL_GAP; - auto& ferryPonder = game_.getEntityManager(). - getComponent(ponderable.ferry); + break; + } - ferryPonder.passengers.erase(entity); + case Direction::up: + { + warpY = MAP_HEIGHT * TILE_HEIGHT - transformable.h; + + break; + } + + case Direction::down: + { + warpY = -WALL_GAP; + + break; + } + } + + game_.getSystemManager().getSystem(). + changeMap( + entity, + result.adjWarpMapId, + warpX, + warpY); } } diff --git a/src/systems/pondering.h b/src/systems/pondering.h index adc0cda..eed0d32 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -46,6 +46,11 @@ private: id_type groundEntity; }; + void tickBody( + id_type entity, + double dt, + const std::set& entities); + void processCollision( id_type entity, id_type collider, -- cgit 1.4.1 From 83534176373bd05a13db88ffff095f52cca07a21 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 4 May 2018 11:08:48 -0400 Subject: Fixed behavior of frozen bodies Frozen bodies are now still ticked, but their velocities and positions are no longer changed. This change was made so that frozen bodies can still be ungrounded/unferried, and that passengers of frozen bodies can still be ticked. Also fixes a compile error. --- src/components/ponderable.h | 5 ++++- src/systems/pondering.cpp | 50 ++++++++++++++++++++++++++------------------- 2 files changed, 33 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/components/ponderable.h b/src/components/ponderable.h index 45150a0..6a01400 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -100,7 +100,10 @@ public: std::set passengers; /** - * If enabled, this will prevent the body from moving. + * If enabled, this will prevent the body from moving and accelerating. The + * velocity and position of the body can still be affected by sources external + * to the PonderingSystem. Enabling this will cause applicable bodies to + * become ungrounded and unferried. */ bool frozen = false; diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index e6417eb..0be3add 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -91,9 +91,9 @@ void PonderingSystem::tickBody( auto& ponderable = game_.getEntityManager(). getComponent(entity); - if (!ponderable.active || ponderable.frozen) + if (!ponderable.active) { - continue; + return; } auto& realizable = game_.getEntityManager(). @@ -109,13 +109,16 @@ void PonderingSystem::tickBody( getComponent(entity); // Accelerate - ponderable.velX += ponderable.accelX * dt; - ponderable.velY += ponderable.accelY * dt; - - if ((ponderable.type == PonderableComponent::Type::freefalling) - && (ponderable.velY > TERMINAL_VELOCITY)) + if (!ponderable.frozen) { - ponderable.velY = TERMINAL_VELOCITY; + ponderable.velX += ponderable.accelX * dt; + ponderable.velY += ponderable.accelY * dt; + + if ((ponderable.type == PonderableComponent::Type::freefalling) + && (ponderable.velY > TERMINAL_VELOCITY)) + { + ponderable.velY = TERMINAL_VELOCITY; + } } const double oldX = transformable.x; @@ -124,21 +127,23 @@ void PonderingSystem::tickBody( const double oldBottom = oldY + transformable.h; CollisionResult result; + result.newX = transformable.x; + result.newY = transformable.y; - if (ponderable.ferried) + if (!ponderable.frozen) { - auto& ferryTrans = game_.getEntityManager(). - getComponent(ponderable.ferry); + if (ponderable.ferried) + { + auto& ferryTrans = game_.getEntityManager(). + getComponent(ponderable.ferry); - result.newX = ferryTrans.x + ponderable.relX; - result.newY = ferryTrans.y + ponderable.relY; - } else { - result.newX = transformable.x; - result.newY = transformable.y; - } + result.newX = ferryTrans.x + ponderable.relX; + result.newY = ferryTrans.y + ponderable.relY; + } - result.newX += ponderable.velX * dt; - result.newY += ponderable.velY * dt; + result.newX += ponderable.velX * dt; + result.newY += ponderable.velY * dt; + } bool oldGrounded = ponderable.grounded; ponderable.grounded = false; @@ -694,8 +699,11 @@ void PonderingSystem::tickBody( } // Move - transformable.x = result.newX; - transformable.y = result.newY; + if (!ponderable.frozen) + { + transformable.x = result.newX; + transformable.y = result.newY; + } // Perform cleanup for orientable entites if (game_.getEntityManager().hasComponent(entity)) -- cgit 1.4.1 From 5b3d87d24b4c2c750d34d1e970254358cba087a4 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 4 May 2018 11:16:02 -0400 Subject: Fixed behavior of uncollidable bodies The collidable flag, previously unused, now correctly disables collision detection when unset. This has the side effect of platforms being able to move through a dying player. It is undecided whether this behavior is wanted. --- src/components/ponderable.h | 3 +- src/systems/pondering.cpp | 880 ++++++++++++++++++++++---------------------- 2 files changed, 445 insertions(+), 438 deletions(-) (limited to 'src') diff --git a/src/components/ponderable.h b/src/components/ponderable.h index 6a01400..eff20e9 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -109,7 +109,8 @@ public: /** * If disabled, collision detection for this body will not be performed and - * other bodies will ignore it. + * other bodies will ignore it. Disabling this will cause applicable bodies to + * become ungrounded and unferried. */ bool collidable = true; diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 0be3add..f5d3df2 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -148,272 +148,275 @@ void PonderingSystem::tickBody( bool oldGrounded = ponderable.grounded; ponderable.grounded = false; - // Find horizontal collisions. - if (result.newX < oldX) + if (ponderable.collidable) { - bool boundaryCollision = false; - auto it = mappable.leftBoundaries.lower_bound(oldX); - - // Find the axis distance of the closest environmental boundary. - for (; - (it != std::end(mappable.leftBoundaries)) && - (it->first >= result.newX); - it++) + // Find horizontal collisions. + if (result.newX < oldX) { - // Check that the boundary is in range for the other axis. - if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) + bool boundaryCollision = false; + auto it = mappable.leftBoundaries.lower_bound(oldX); + + // Find the axis distance of the closest environmental boundary. + for (; + (it != std::end(mappable.leftBoundaries)) && + (it->first >= result.newX); + it++) { - // We have a collision! - boundaryCollision = true; + // Check that the boundary is in range for the other axis. + if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) + { + // We have a collision! + boundaryCollision = true; - break; + break; + } } - } - // Find a list of potential colliders, sorted so that the closest is - // first. - std::vector colliders; + // Find a list of potential colliders, sorted so that the closest is + // first. + std::vector colliders; - for (id_type collider : entities) - { - // Can't collide with self. - if (collider == entity) + for (id_type collider : entities) { - continue; - } + // Can't collide with self. + if (collider == entity) + { + continue; + } - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - // Only check objects that are active. - if (!colliderPonder.active) - { - continue; - } + // Only check objects that are active and collidable. + if (!colliderPonder.active || !colliderPonder.collidable) + { + continue; + } - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); - - // Check if the entity would move into the potential collider, - if ((colliderTrans.x + colliderTrans.w > result.newX) && - // that it wasn't already colliding, - (colliderTrans.x + colliderTrans.w <= oldX) && - // that the position on the other axis is in range, - (colliderTrans.y + colliderTrans.h > oldY) && - (colliderTrans.y < oldBottom) && - // and that the collider is not farther away than the environmental - // boundary. - (!boundaryCollision || - (colliderTrans.x + colliderTrans.w >= it->first))) - { - colliders.push_back(collider); + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would move into the potential collider, + if ((colliderTrans.x + colliderTrans.w > result.newX) && + // that it wasn't already colliding, + (colliderTrans.x + colliderTrans.w <= oldX) && + // that the position on the other axis is in range, + (colliderTrans.y + colliderTrans.h > oldY) && + (colliderTrans.y < oldBottom) && + // and that the collider is not farther away than the environmental + // boundary. + (!boundaryCollision || + (colliderTrans.x + colliderTrans.w >= it->first))) + { + colliders.push_back(collider); + } } - } - std::sort( - std::begin(colliders), - std::end(colliders), - [&] (id_type left, id_type right) { - auto& leftTrans = game_.getEntityManager(). - getComponent(left); + std::sort( + std::begin(colliders), + std::end(colliders), + [&] (id_type left, id_type right) { + auto& leftTrans = game_.getEntityManager(). + getComponent(left); - auto& rightTrans = game_.getEntityManager(). - getComponent(right); + auto& rightTrans = game_.getEntityManager(). + getComponent(right); - return (rightTrans.x < leftTrans.x); - }); + return (rightTrans.x < leftTrans.x); + }); - for (id_type collider : colliders) - { - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); - - // Check if the entity would still move into the potential collider. - if (colliderTrans.x + colliderTrans.w <= result.newX) + for (id_type collider : colliders) { - break; - } + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + // Check if the entity would still move into the potential collider. + if (colliderTrans.x + colliderTrans.w <= result.newX) + { + break; + } - processCollision( - entity, - collider, - Direction::left, - colliderPonder.colliderType, - colliderTrans.x + colliderTrans.w, - colliderTrans.y, - colliderTrans.y + colliderTrans.h, - result); - - if (result.stopProcessing) - { - break; - } - } + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - // If movement hasn't been stopped by an intermediary object, and - // collision checking hasn't been stopped, process the environmental - // boundaries closest to the entity. - if (!result.stopProcessing && !result.touchedWall && boundaryCollision) - { - double boundaryAxis = it->first; + processCollision( + entity, + collider, + Direction::left, + colliderPonder.colliderType, + colliderTrans.x + colliderTrans.w, + colliderTrans.y, + colliderTrans.y + colliderTrans.h, + result); - for (; - (it != std::end(mappable.leftBoundaries)) && - (it->first == boundaryAxis); - it++) + if (result.stopProcessing) + { + break; + } + } + + // If movement hasn't been stopped by an intermediary object, and + // collision checking hasn't been stopped, process the environmental + // boundaries closest to the entity. + if (!result.stopProcessing && !result.touchedWall && boundaryCollision) { - if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) + double boundaryAxis = it->first; + + for (; + (it != std::end(mappable.leftBoundaries)) && + (it->first == boundaryAxis); + it++) { - processCollision( - entity, - mapEntity, - Direction::left, - it->second.type, - it->first, - it->second.lower, - it->second.upper, - result); - - if (result.stopProcessing) + if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) { - break; + processCollision( + entity, + mapEntity, + Direction::left, + it->second.type, + it->first, + it->second.lower, + it->second.upper, + result); + + if (result.stopProcessing) + { + break; + } } } } - } - } else if (result.newX > oldX) - { - bool boundaryCollision = false; - auto it = mappable.rightBoundaries.lower_bound(oldRight); - - // Find the axis distance of the closest environmental boundary. - for (; - (it != std::end(mappable.rightBoundaries)) - && (it->first <= (result.newX + transformable.w)); - it++) + } else if (result.newX > oldX) { - // Check that the boundary is in range for the other axis. - if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) + bool boundaryCollision = false; + auto it = mappable.rightBoundaries.lower_bound(oldRight); + + // Find the axis distance of the closest environmental boundary. + for (; + (it != std::end(mappable.rightBoundaries)) + && (it->first <= (result.newX + transformable.w)); + it++) { - // We have a collision! - boundaryCollision = true; + // Check that the boundary is in range for the other axis. + if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) + { + // We have a collision! + boundaryCollision = true; - break; + break; + } } - } - // Find a list of potential colliders, sorted so that the closest is - // first. - std::vector colliders; + // Find a list of potential colliders, sorted so that the closest is + // first. + std::vector colliders; - for (id_type collider : entities) - { - // Can't collide with self. - if (collider == entity) + for (id_type collider : entities) { - continue; - } + // Can't collide with self. + if (collider == entity) + { + continue; + } - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - // Only check objects that are active. - if (!colliderPonder.active) - { - continue; - } + // Only check objects that are active and collidable. + if (!colliderPonder.active || !colliderPonder.collidable) + { + continue; + } - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); - - // Check if the entity would move into the potential collider, - if ((colliderTrans.x < result.newX + transformable.w) && - // that it wasn't already colliding, - (colliderTrans.x >= oldRight) && - // that the position on the other axis is in range, - (colliderTrans.y + colliderTrans.h > oldY) && - (colliderTrans.y < oldBottom) && - // and that the collider is not farther away than the environmental - // boundary. - (!boundaryCollision || (colliderTrans.x <= it->first))) - { - colliders.push_back(collider); + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would move into the potential collider, + if ((colliderTrans.x < result.newX + transformable.w) && + // that it wasn't already colliding, + (colliderTrans.x >= oldRight) && + // that the position on the other axis is in range, + (colliderTrans.y + colliderTrans.h > oldY) && + (colliderTrans.y < oldBottom) && + // and that the collider is not farther away than the environmental + // boundary. + (!boundaryCollision || (colliderTrans.x <= it->first))) + { + colliders.push_back(collider); + } } - } - - std::sort( - std::begin(colliders), - std::end(colliders), - [&] (id_type left, id_type right) { - auto& leftTrans = game_.getEntityManager(). - getComponent(left); - auto& rightTrans = game_.getEntityManager(). - getComponent(right); + std::sort( + std::begin(colliders), + std::end(colliders), + [&] (id_type left, id_type right) { + auto& leftTrans = game_.getEntityManager(). + getComponent(left); - return (leftTrans.x < rightTrans.x); - }); + auto& rightTrans = game_.getEntityManager(). + getComponent(right); - for (id_type collider : colliders) - { - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); + return (leftTrans.x < rightTrans.x); + }); - // Check if the entity would still move into the potential collider. - if (colliderTrans.x >= result.newX + transformable.w) + for (id_type collider : colliders) { - break; - } + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + // Check if the entity would still move into the potential collider. + if (colliderTrans.x >= result.newX + transformable.w) + { + break; + } - processCollision( - entity, - collider, - Direction::right, - colliderPonder.colliderType, - colliderTrans.x, - colliderTrans.y, - colliderTrans.y + colliderTrans.h, - result); - - if (result.stopProcessing) - { - break; - } - } + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - // If movement hasn't been stopped by an intermediary object, and - // collision checking hasn't been stopped, process the environmental - // boundaries closest to the entity. - if (!result.stopProcessing && !result.touchedWall && boundaryCollision) - { - double boundaryAxis = it->first; + processCollision( + entity, + collider, + Direction::right, + colliderPonder.colliderType, + colliderTrans.x, + colliderTrans.y, + colliderTrans.y + colliderTrans.h, + result); - for (; - (it != std::end(mappable.rightBoundaries)) && - (it->first == boundaryAxis); - it++) + if (result.stopProcessing) + { + break; + } + } + + // If movement hasn't been stopped by an intermediary object, and + // collision checking hasn't been stopped, process the environmental + // boundaries closest to the entity. + if (!result.stopProcessing && !result.touchedWall && boundaryCollision) { - if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) + double boundaryAxis = it->first; + + for (; + (it != std::end(mappable.rightBoundaries)) && + (it->first == boundaryAxis); + it++) { - processCollision( - entity, - mapEntity, - Direction::right, - it->second.type, - it->first, - it->second.lower, - it->second.upper, - result); - - if (result.stopProcessing) + if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) { - break; + processCollision( + entity, + mapEntity, + Direction::right, + it->second.type, + it->first, + it->second.lower, + it->second.upper, + result); + + if (result.stopProcessing) + { + break; + } } } } @@ -421,277 +424,280 @@ void PonderingSystem::tickBody( } // Find vertical collisions - result.touchedWall = false; - - if ((!result.stopProcessing) && (result.newY < oldY)) + if (ponderable.collidable && !result.stopProcessing) { - bool boundaryCollision = false; - auto it = mappable.upBoundaries.lower_bound(oldY); - - // Find the axis distance of the closest environmental boundary. - for (; - (it != std::end(mappable.upBoundaries)) && - (it->first >= result.newY); - it++) + result.touchedWall = false; + + if (result.newY < oldY) { - // Check that the boundary is in range for the other axis. - if ((result.newX + transformable.h > it->second.lower) && - (result.newX < it->second.upper)) + bool boundaryCollision = false; + auto it = mappable.upBoundaries.lower_bound(oldY); + + // Find the axis distance of the closest environmental boundary. + for (; + (it != std::end(mappable.upBoundaries)) && + (it->first >= result.newY); + it++) { - // We have a collision! - boundaryCollision = true; + // Check that the boundary is in range for the other axis. + if ((result.newX + transformable.h > it->second.lower) && + (result.newX < it->second.upper)) + { + // We have a collision! + boundaryCollision = true; - break; + break; + } } - } - // Find a list of potential colliders, sorted so that the closest is - // first. - std::vector colliders; + // Find a list of potential colliders, sorted so that the closest is + // first. + std::vector colliders; - for (id_type collider : entities) - { - // Can't collide with self. - if (collider == entity) + for (id_type collider : entities) { - continue; - } + // Can't collide with self. + if (collider == entity) + { + continue; + } - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - // Only check objects that are active. - if (!colliderPonder.active) - { - continue; - } + // Only check objects that are active and collidable. + if (!colliderPonder.active || !colliderPonder.collidable) + { + continue; + } - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); - - // Check if the entity would move into the potential collider, - if ((colliderTrans.y + colliderTrans.h > result.newY) && - // that it wasn't already colliding, - (colliderTrans.y + colliderTrans.h <= oldY) && - // that the position on the other axis is in range, - (colliderTrans.x + colliderTrans.w > result.newX) && - (colliderTrans.x < result.newX + transformable.w) && - // and that the collider is not farther away than the environmental - // boundary. - (!boundaryCollision || - (colliderTrans.y + colliderTrans.h >= it->first))) - { - colliders.push_back(collider); + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would move into the potential collider, + if ((colliderTrans.y + colliderTrans.h > result.newY) && + // that it wasn't already colliding, + (colliderTrans.y + colliderTrans.h <= oldY) && + // that the position on the other axis is in range, + (colliderTrans.x + colliderTrans.w > result.newX) && + (colliderTrans.x < result.newX + transformable.w) && + // and that the collider is not farther away than the environmental + // boundary. + (!boundaryCollision || + (colliderTrans.y + colliderTrans.h >= it->first))) + { + colliders.push_back(collider); + } } - } - - std::sort( - std::begin(colliders), - std::end(colliders), - [&] (id_type left, id_type right) { - auto& leftTrans = game_.getEntityManager(). - getComponent(left); - auto& rightTrans = game_.getEntityManager(). - getComponent(right); + std::sort( + std::begin(colliders), + std::end(colliders), + [&] (id_type left, id_type right) { + auto& leftTrans = game_.getEntityManager(). + getComponent(left); - return (rightTrans.y < leftTrans.y); - }); + auto& rightTrans = game_.getEntityManager(). + getComponent(right); - for (id_type collider : colliders) - { - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); + return (rightTrans.y < leftTrans.y); + }); - // Check if the entity would still move into the potential collider. - if (colliderTrans.y + colliderTrans.h <= result.newY) + for (id_type collider : colliders) { - break; - } + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + // Check if the entity would still move into the potential collider. + if (colliderTrans.y + colliderTrans.h <= result.newY) + { + break; + } - processCollision( - entity, - collider, - Direction::up, - colliderPonder.colliderType, - colliderTrans.y + colliderTrans.h, - colliderTrans.x, - colliderTrans.x + colliderTrans.w, - result); - - if (result.stopProcessing) - { - break; - } - } + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - // If movement hasn't been stopped by an intermediary object, and - // collision checking hasn't been stopped, process the environmental - // boundaries closest to the entity. - if (!result.stopProcessing && !result.touchedWall && boundaryCollision) - { - double boundaryAxis = it->first; + processCollision( + entity, + collider, + Direction::up, + colliderPonder.colliderType, + colliderTrans.y + colliderTrans.h, + colliderTrans.x, + colliderTrans.x + colliderTrans.w, + result); - for (; - (it != std::end(mappable.upBoundaries)) && - (it->first == boundaryAxis); - it++) + if (result.stopProcessing) + { + break; + } + } + + // If movement hasn't been stopped by an intermediary object, and + // collision checking hasn't been stopped, process the environmental + // boundaries closest to the entity. + if (!result.stopProcessing && !result.touchedWall && boundaryCollision) { - if ((result.newX + transformable.w > it->second.lower) && - (result.newX < it->second.upper)) + double boundaryAxis = it->first; + + for (; + (it != std::end(mappable.upBoundaries)) && + (it->first == boundaryAxis); + it++) { - processCollision( - entity, - mapEntity, - Direction::up, - it->second.type, - it->first, - it->second.lower, - it->second.upper, - result); - - if (result.stopProcessing) + if ((result.newX + transformable.w > it->second.lower) && + (result.newX < it->second.upper)) { - break; + processCollision( + entity, + mapEntity, + Direction::up, + it->second.type, + it->first, + it->second.lower, + it->second.upper, + result); + + if (result.stopProcessing) + { + break; + } } } } - } - } else if ((!result.stopProcessing) && (result.newY > oldY)) - { - bool boundaryCollision = false; - auto it = mappable.downBoundaries.lower_bound(oldBottom); - - // Find the axis distance of the closest environmental boundary. - for (; - (it != std::end(mappable.downBoundaries)) - && (it->first <= (result.newY + transformable.h)); - it++) + } else if (result.newY > oldY) { - // Check that the boundary is in range for the other axis. - if ((result.newX + transformable.w > it->second.lower) && - (result.newX < it->second.upper)) + bool boundaryCollision = false; + auto it = mappable.downBoundaries.lower_bound(oldBottom); + + // Find the axis distance of the closest environmental boundary. + for (; + (it != std::end(mappable.downBoundaries)) + && (it->first <= (result.newY + transformable.h)); + it++) { - // We have a collision! - boundaryCollision = true; + // Check that the boundary is in range for the other axis. + if ((result.newX + transformable.w > it->second.lower) && + (result.newX < it->second.upper)) + { + // We have a collision! + boundaryCollision = true; - break; + break; + } } - } - // Find a list of potential colliders, sorted so that the closest is - // first. - std::vector colliders; + // Find a list of potential colliders, sorted so that the closest is + // first. + std::vector colliders; - for (id_type collider : entities) - { - // Can't collide with self. - if (collider == entity) + for (id_type collider : entities) { - continue; - } + // Can't collide with self. + if (collider == entity) + { + continue; + } - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - // Only check objects that are active. - if (!colliderPonder.active) - { - continue; - } + // Only check objects that are active and collidable. + if (!colliderPonder.active || !colliderPonder.collidable) + { + continue; + } - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); - - // Check if the entity would move into the potential collider, - if ((colliderTrans.y < result.newY + transformable.h) && - // that it wasn't already colliding, - (colliderTrans.y >= oldBottom) && - // that the position on the other axis is in range, - (colliderTrans.x + colliderTrans.w > result.newX) && - (colliderTrans.x < result.newX + transformable.w) && - // and that the collider is not farther away than the environmental - // boundary. - (!boundaryCollision || (colliderTrans.y <= it->first))) - { - colliders.push_back(collider); + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would move into the potential collider, + if ((colliderTrans.y < result.newY + transformable.h) && + // that it wasn't already colliding, + (colliderTrans.y >= oldBottom) && + // that the position on the other axis is in range, + (colliderTrans.x + colliderTrans.w > result.newX) && + (colliderTrans.x < result.newX + transformable.w) && + // and that the collider is not farther away than the environmental + // boundary. + (!boundaryCollision || (colliderTrans.y <= it->first))) + { + colliders.push_back(collider); + } } - } - - std::sort( - std::begin(colliders), - std::end(colliders), - [&] (id_type left, id_type right) { - auto& leftTrans = game_.getEntityManager(). - getComponent(left); - auto& rightTrans = game_.getEntityManager(). - getComponent(right); + std::sort( + std::begin(colliders), + std::end(colliders), + [&] (id_type left, id_type right) { + auto& leftTrans = game_.getEntityManager(). + getComponent(left); - return (leftTrans.y < rightTrans.y); - }); + auto& rightTrans = game_.getEntityManager(). + getComponent(right); - for (id_type collider : colliders) - { - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); + return (leftTrans.y < rightTrans.y); + }); - // Check if the entity would still move into the potential collider. - if (colliderTrans.y >= result.newY + transformable.h) + for (id_type collider : colliders) { - break; - } + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + // Check if the entity would still move into the potential collider. + if (colliderTrans.y >= result.newY + transformable.h) + { + break; + } - processCollision( - entity, - collider, - Direction::down, - colliderPonder.colliderType, - colliderTrans.y, - colliderTrans.x, - colliderTrans.x + colliderTrans.w, - result); - - if (result.stopProcessing) - { - break; - } - } + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - // If movement hasn't been stopped by an intermediary object, and - // collision checking hasn't been stopped, process the environmental - // boundaries closest to the entity. - if (!result.stopProcessing && !result.touchedWall && boundaryCollision) - { - double boundaryAxis = it->first; + processCollision( + entity, + collider, + Direction::down, + colliderPonder.colliderType, + colliderTrans.y, + colliderTrans.x, + colliderTrans.x + colliderTrans.w, + result); - for (; - (it != std::end(mappable.downBoundaries)) && - (it->first == boundaryAxis); - it++) + if (result.stopProcessing) + { + break; + } + } + + // If movement hasn't been stopped by an intermediary object, and + // collision checking hasn't been stopped, process the environmental + // boundaries closest to the entity. + if (!result.stopProcessing && !result.touchedWall && boundaryCollision) { - if ((result.newX + transformable.w > it->second.lower) && - (result.newX < it->second.upper)) + double boundaryAxis = it->first; + + for (; + (it != std::end(mappable.downBoundaries)) && + (it->first == boundaryAxis); + it++) { - processCollision( - entity, - mapEntity, - Direction::down, - it->second.type, - it->first, - it->second.lower, - it->second.upper, - result); - - if (result.stopProcessing) + if ((result.newX + transformable.w > it->second.lower) && + (result.newX < it->second.upper)) { - break; + processCollision( + entity, + mapEntity, + Direction::down, + it->second.type, + it->first, + it->second.lower, + it->second.upper, + result); + + if (result.stopProcessing) + { + break; + } } } } -- cgit 1.4.1 From 296a1c3aa0bdb27e7ee9b53f0382938d0fe6d1a0 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Fri, 4 May 2018 11:34:57 -0400 Subject: Fixed bug with upward tilemap collision A body moving upward would have its transform incorrectly measured against the map collision boundaries. --- src/systems/pondering.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index f5d3df2..ed14772 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -440,7 +440,7 @@ void PonderingSystem::tickBody( it++) { // Check that the boundary is in range for the other axis. - if ((result.newX + transformable.h > it->second.lower) && + if ((result.newX + transformable.w > it->second.lower) && (result.newX < it->second.upper)) { // We have a collision! -- cgit 1.4.1 From 96e6f3231aed9919d660a06944f1d96dc8241f8e Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Tue, 8 May 2018 18:38:28 -0400 Subject: Started refactoring collision detection to use directional functor Because there was a lot of code replication with collision detection, this new implementation uses a functor that takes a parameter object describing the things that are different between the four directions. This allows the collision detection code to be writen only once. It's currently very ugly, but should work identically to before. --- src/systems/pondering.cpp | 1088 +++++++++++++++++++++------------------------ src/systems/pondering.h | 40 +- 2 files changed, 533 insertions(+), 595 deletions(-) (limited to 'src') diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index ed14772..7b3ab2d 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -96,15 +96,6 @@ void PonderingSystem::tickBody( return; } - auto& realizable = game_.getEntityManager(). - getComponent( - game_.getSystemManager().getSystem().getSingleton()); - - id_type mapEntity = realizable.activeMap; - - auto& mappable = game_.getEntityManager(). - getComponent(mapEntity); - auto& transformable = game_.getEntityManager(). getComponent(entity); @@ -121,14 +112,9 @@ void PonderingSystem::tickBody( } } - const double oldX = transformable.x; - const double oldY = transformable.y; - const double oldRight = oldX + transformable.w; - const double oldBottom = oldY + transformable.h; - - CollisionResult result; - result.newX = transformable.x; - result.newY = transformable.y; + // Move + double newX = transformable.x; + double newY = transformable.y; if (!ponderable.frozen) { @@ -137,692 +123,626 @@ void PonderingSystem::tickBody( auto& ferryTrans = game_.getEntityManager(). getComponent(ponderable.ferry); - result.newX = ferryTrans.x + ponderable.relX; - result.newY = ferryTrans.y + ponderable.relY; + newX = ferryTrans.x + ponderable.relX; + newY = ferryTrans.y + ponderable.relY; } - result.newX += ponderable.velX * dt; - result.newY += ponderable.velY * dt; + newX += ponderable.velX * dt; + newY += ponderable.velY * dt; } - bool oldGrounded = ponderable.grounded; - ponderable.grounded = false; + CollisionResult result = + moveBody( + entity, + newX, + newY); - if (ponderable.collidable) + // Perform cleanup for orientable entites + bool groundedChanged = (ponderable.grounded != result.grounded); + ponderable.grounded = result.grounded; + + if (game_.getEntityManager().hasComponent(entity)) { - // Find horizontal collisions. - if (result.newX < oldX) - { - bool boundaryCollision = false; - auto it = mappable.leftBoundaries.lower_bound(oldX); + auto& orientable = game_.getEntityManager(). + getComponent(entity); - // Find the axis distance of the closest environmental boundary. - for (; - (it != std::end(mappable.leftBoundaries)) && - (it->first >= result.newX); - it++) + // Handle changes in groundedness + if (groundedChanged) + { + if (ponderable.grounded) { - // Check that the boundary is in range for the other axis. - if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) - { - // We have a collision! - boundaryCollision = true; - - break; - } + game_.getSystemManager().getSystem().land(entity); + } else { + game_.getSystemManager(). + getSystem().startFalling(entity); } + } - // Find a list of potential colliders, sorted so that the closest is - // first. - std::vector colliders; + // Complete dropping, if necessary + if (orientable.getDropState() == OrientableComponent::DropState::active) + { + orientable.setDropState(OrientableComponent::DropState::none); + } + } - for (id_type collider : entities) - { - // Can't collide with self. - if (collider == entity) - { - continue; - } + // Ferry or unferry as necessary + if ((ponderable.type == PonderableComponent::Type::freefalling) && + groundedChanged) + { + if (ponderable.grounded && + game_.getEntityManager(). + hasComponent(result.groundEntity)) + { + // The body is now being ferried + auto& ferryPonder = game_.getEntityManager(). + getComponent(result.groundEntity); + + ponderable.ferried = true; + ponderable.ferry = result.groundEntity; - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + ferryPonder.passengers.insert(entity); + } else if (ponderable.ferried) + { + // The body is no longer being ferried + unferry(entity); + } + } - // Only check objects that are active and collidable. - if (!colliderPonder.active || !colliderPonder.collidable) - { - continue; - } + // Update a ferry passenger's relative position + if (ponderable.ferried) + { + auto& ferryTrans = game_.getEntityManager(). + getComponent(ponderable.ferry); - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); - - // Check if the entity would move into the potential collider, - if ((colliderTrans.x + colliderTrans.w > result.newX) && - // that it wasn't already colliding, - (colliderTrans.x + colliderTrans.w <= oldX) && - // that the position on the other axis is in range, - (colliderTrans.y + colliderTrans.h > oldY) && - (colliderTrans.y < oldBottom) && - // and that the collider is not farther away than the environmental - // boundary. - (!boundaryCollision || - (colliderTrans.x + colliderTrans.w >= it->first))) - { - colliders.push_back(collider); - } - } + ponderable.relX = transformable.x - ferryTrans.x; + ponderable.relY = transformable.y - ferryTrans.y; + } - std::sort( - std::begin(colliders), - std::end(colliders), - [&] (id_type left, id_type right) { - auto& leftTrans = game_.getEntityManager(). - getComponent(left); + // Handle ferry passengers + std::set passengers = ponderable.passengers; - auto& rightTrans = game_.getEntityManager(). - getComponent(right); + for (id_type passenger : passengers) + { + tickBody( + passenger, + dt, + entities); + } - return (rightTrans.x < leftTrans.x); - }); + // Move to an adjacent map, if necessary + if (result.adjacentlyWarping) + { + double warpX = result.newX; + double warpY = result.newY; - for (id_type collider : colliders) + switch (result.adjWarpDir) + { + case Direction::left: { - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); - - // Check if the entity would still move into the potential collider. - if (colliderTrans.x + colliderTrans.w <= result.newX) - { - break; - } + warpX = GAME_WIDTH + WALL_GAP - transformable.w; - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + break; + } - processCollision( - entity, - collider, - Direction::left, - colliderPonder.colliderType, - colliderTrans.x + colliderTrans.w, - colliderTrans.y, - colliderTrans.y + colliderTrans.h, - result); + case Direction::right: + { + warpX = -WALL_GAP; - if (result.stopProcessing) - { - break; - } + break; } - // If movement hasn't been stopped by an intermediary object, and - // collision checking hasn't been stopped, process the environmental - // boundaries closest to the entity. - if (!result.stopProcessing && !result.touchedWall && boundaryCollision) + case Direction::up: { - double boundaryAxis = it->first; + warpY = MAP_HEIGHT * TILE_HEIGHT - transformable.h; - for (; - (it != std::end(mappable.leftBoundaries)) && - (it->first == boundaryAxis); - it++) - { - if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) - { - processCollision( - entity, - mapEntity, - Direction::left, - it->second.type, - it->first, - it->second.lower, - it->second.upper, - result); - - if (result.stopProcessing) - { - break; - } - } - } + break; } - } else if (result.newX > oldX) - { - bool boundaryCollision = false; - auto it = mappable.rightBoundaries.lower_bound(oldRight); - // Find the axis distance of the closest environmental boundary. - for (; - (it != std::end(mappable.rightBoundaries)) - && (it->first <= (result.newX + transformable.w)); - it++) + case Direction::down: { - // Check that the boundary is in range for the other axis. - if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) - { - // We have a collision! - boundaryCollision = true; + warpY = -WALL_GAP; - break; - } + break; } + } - // Find a list of potential colliders, sorted so that the closest is - // first. - std::vector colliders; - - for (id_type collider : entities) - { - // Can't collide with self. - if (collider == entity) - { - continue; - } + game_.getSystemManager().getSystem(). + changeMap( + entity, + result.adjWarpMapId, + warpX, + warpY); + } +} - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); +CollisionResult PonderingSystem::moveBody( + id_type entity, + double x, + double y) +{ + auto& ponderable = game_.getEntityManager(). + getComponent(entity); - // Only check objects that are active and collidable. - if (!colliderPonder.active || !colliderPonder.collidable) - { - continue; - } + auto& transformable = game_.getEntityManager(). + getComponent(entity); - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); - - // Check if the entity would move into the potential collider, - if ((colliderTrans.x < result.newX + transformable.w) && - // that it wasn't already colliding, - (colliderTrans.x >= oldRight) && - // that the position on the other axis is in range, - (colliderTrans.y + colliderTrans.h > oldY) && - (colliderTrans.y < oldBottom) && - // and that the collider is not farther away than the environmental - // boundary. - (!boundaryCollision || (colliderTrans.x <= it->first))) - { - colliders.push_back(collider); - } - } + const double oldX = transformable.x; + const double oldY = transformable.y; + const double oldRight = oldX + transformable.w; + const double oldBottom = oldY + transformable.h; - std::sort( - std::begin(colliders), - std::end(colliders), - [&] (id_type left, id_type right) { - auto& leftTrans = game_.getEntityManager(). - getComponent(left); + CollisionResult result; - auto& rightTrans = game_.getEntityManager(). - getComponent(right); + if (ponderable.collidable) + { + result = detectCollisions(entity, x, y); + } else { + result.newX = x; + result.newY = y; + } - return (leftTrans.x < rightTrans.x); - }); + // Move + if (!ponderable.frozen) + { + transformable.x = result.newX; + transformable.y = result.newY; + } - for (id_type collider : colliders) - { - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); + return result; +} - // Check if the entity would still move into the potential collider. - if (colliderTrans.x >= result.newX + transformable.w) - { - break; - } +namespace CollisionParams { - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + template + class Desc : public HorizVert { + public: - processCollision( - entity, - collider, - Direction::right, - colliderPonder.colliderType, - colliderTrans.x, - colliderTrans.y, - colliderTrans.y + colliderTrans.h, - result); + inline static bool AtLeastInAxisSweep( + double boundaryAxis, + double entityAxis) + { + return (boundaryAxis >= entityAxis); + } - if (result.stopProcessing) - { - break; - } - } + inline static bool IsPastAxis( + double colliderAxis, + double entityAxis) + { + return (colliderAxis > entityAxis); + } - // If movement hasn't been stopped by an intermediary object, and - // collision checking hasn't been stopped, process the environmental - // boundaries closest to the entity. - if (!result.stopProcessing && !result.touchedWall && boundaryCollision) - { - double boundaryAxis = it->first; + inline static double OldAxis(const TransformableComponent& transformable) + { + return HorizVert::AxisOldLower(transformable); + } - for (; - (it != std::end(mappable.rightBoundaries)) && - (it->first == boundaryAxis); - it++) - { - if ((oldBottom > it->second.lower) && (oldY < it->second.upper)) - { - processCollision( - entity, - mapEntity, - Direction::right, - it->second.type, - it->first, - it->second.lower, - it->second.upper, - result); - - if (result.stopProcessing) - { - break; - } - } - } - } + inline static double NewAxis( + const CollisionResult& result, + const TransformableComponent&) + { + return HorizVert::AxisNewLower(result); } - } - // Find vertical collisions - if (ponderable.collidable && !result.stopProcessing) - { - result.touchedWall = false; + inline static double ObjectAxis(const TransformableComponent& transformable) + { + return HorizVert::AxisOldUpper(transformable); + } - if (result.newY < oldY) + inline static bool Closer(double left, double right) { - bool boundaryCollision = false; - auto it = mappable.upBoundaries.lower_bound(oldY); + return right < left; + } + }; - // Find the axis distance of the closest environmental boundary. - for (; - (it != std::end(mappable.upBoundaries)) && - (it->first >= result.newY); - it++) - { - // Check that the boundary is in range for the other axis. - if ((result.newX + transformable.w > it->second.lower) && - (result.newX < it->second.upper)) - { - // We have a collision! - boundaryCollision = true; + template + class Asc : public HorizVert { + public: - break; - } - } + inline static bool AtLeastInAxisSweep( + double boundaryAxis, + double entityAxis) + { + return (boundaryAxis <= entityAxis); + } - // Find a list of potential colliders, sorted so that the closest is - // first. - std::vector colliders; + inline static bool IsPastAxis( + double colliderAxis, + double entityAxis) + { + return (colliderAxis < entityAxis); + } - for (id_type collider : entities) - { - // Can't collide with self. - if (collider == entity) - { - continue; - } + inline static double OldAxis(const TransformableComponent& transformable) + { + return HorizVert::AxisOldUpper(transformable); + } - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + inline static double NewAxis( + const CollisionResult& result, + const TransformableComponent& transformable) + { + return HorizVert::AxisNewUpper(result, transformable); + } - // Only check objects that are active and collidable. - if (!colliderPonder.active || !colliderPonder.collidable) - { - continue; - } + inline static double ObjectAxis(const TransformableComponent& transformable) + { + return HorizVert::AxisOldLower(transformable); + } - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); - - // Check if the entity would move into the potential collider, - if ((colliderTrans.y + colliderTrans.h > result.newY) && - // that it wasn't already colliding, - (colliderTrans.y + colliderTrans.h <= oldY) && - // that the position on the other axis is in range, - (colliderTrans.x + colliderTrans.w > result.newX) && - (colliderTrans.x < result.newX + transformable.w) && - // and that the collider is not farther away than the environmental - // boundary. - (!boundaryCollision || - (colliderTrans.y + colliderTrans.h >= it->first))) - { - colliders.push_back(collider); - } - } + inline static bool Closer(double left, double right) + { + return left < right; + } + }; - std::sort( - std::begin(colliders), - std::end(colliders), - [&] (id_type left, id_type right) { - auto& leftTrans = game_.getEntityManager(). - getComponent(left); + class Horizontal { + public: - auto& rightTrans = game_.getEntityManager(). - getComponent(right); + inline static double AxisOldLower( + const TransformableComponent& transformable) + { + return transformable.x; + } - return (rightTrans.y < leftTrans.y); - }); + inline static double AxisOldUpper( + const TransformableComponent& transformable) + { + return transformable.x + transformable.w; + } - for (id_type collider : colliders) - { - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); + inline static double AxisNewLower(const CollisionResult& result) + { + return result.newX; + } - // Check if the entity would still move into the potential collider. - if (colliderTrans.y + colliderTrans.h <= result.newY) - { - break; - } + inline static double AxisNewUpper( + const CollisionResult& result, + const TransformableComponent& transformable) + { + return result.newX + transformable.w; + } - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + inline static double NonAxisOldLower( + const TransformableComponent& transformable) + { + return transformable.y; + } - processCollision( - entity, - collider, - Direction::up, - colliderPonder.colliderType, - colliderTrans.y + colliderTrans.h, - colliderTrans.x, - colliderTrans.x + colliderTrans.w, - result); + inline static double NonAxisOldUpper( + const TransformableComponent& transformable) + { + return transformable.y + transformable.h; + } - if (result.stopProcessing) - { - break; - } - } + inline static double NonAxisNewLower( + const CollisionResult& result, + const TransformableComponent& transformable) + { + return result.newY; + } - // If movement hasn't been stopped by an intermediary object, and - // collision checking hasn't been stopped, process the environmental - // boundaries closest to the entity. - if (!result.stopProcessing && !result.touchedWall && boundaryCollision) - { - double boundaryAxis = it->first; + inline static double NonAxisNewUpper( + const CollisionResult& result, + const TransformableComponent& transformable) + { + return result.newY + transformable.h; + } + }; - for (; - (it != std::end(mappable.upBoundaries)) && - (it->first == boundaryAxis); - it++) - { - if ((result.newX + transformable.w > it->second.lower) && - (result.newX < it->second.upper)) - { - processCollision( - entity, - mapEntity, - Direction::up, - it->second.type, - it->first, - it->second.lower, - it->second.upper, - result); - - if (result.stopProcessing) - { - break; - } - } - } - } - } else if (result.newY > oldY) + class Vertical { + public: + + inline static double AxisOldLower( + const TransformableComponent& transformable) { - bool boundaryCollision = false; - auto it = mappable.downBoundaries.lower_bound(oldBottom); + return transformable.y; + } - // Find the axis distance of the closest environmental boundary. - for (; - (it != std::end(mappable.downBoundaries)) - && (it->first <= (result.newY + transformable.h)); - it++) - { - // Check that the boundary is in range for the other axis. - if ((result.newX + transformable.w > it->second.lower) && - (result.newX < it->second.upper)) - { - // We have a collision! - boundaryCollision = true; + inline static double AxisOldUpper( + const TransformableComponent& transformable) + { + return transformable.y + transformable.h; + } - break; - } - } + inline static double AxisNewLower(const CollisionResult& result) + { + return result.newY; + } - // Find a list of potential colliders, sorted so that the closest is - // first. - std::vector colliders; + inline static double AxisNewUpper( + const CollisionResult& result, + const TransformableComponent& transformable) + { + return result.newY + transformable.h; + } - for (id_type collider : entities) - { - // Can't collide with self. - if (collider == entity) - { - continue; - } + inline static double NonAxisOldLower( + const TransformableComponent& transformable) + { + return transformable.x; + } - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + inline static double NonAxisOldUpper( + const TransformableComponent& transformable) + { + return transformable.x + transformable.w; + } - // Only check objects that are active and collidable. - if (!colliderPonder.active || !colliderPonder.collidable) - { - continue; - } + inline static double NonAxisNewLower( + const CollisionResult& result, + const TransformableComponent& transformable) + { + return result.newX; + } - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); - - // Check if the entity would move into the potential collider, - if ((colliderTrans.y < result.newY + transformable.h) && - // that it wasn't already colliding, - (colliderTrans.y >= oldBottom) && - // that the position on the other axis is in range, - (colliderTrans.x + colliderTrans.w > result.newX) && - (colliderTrans.x < result.newX + transformable.w) && - // and that the collider is not farther away than the environmental - // boundary. - (!boundaryCollision || (colliderTrans.y <= it->first))) - { - colliders.push_back(collider); - } - } + inline static double NonAxisNewUpper( + const CollisionResult& result, + const TransformableComponent& transformable) + { + return result.newX + transformable.w; + } + }; - std::sort( - std::begin(colliders), - std::end(colliders), - [&] (id_type left, id_type right) { - auto& leftTrans = game_.getEntityManager(). - getComponent(left); + template + class DetectCollisions : public AscDesc { + public: - auto& rightTrans = game_.getEntityManager(). - getComponent(right); + static const Direction Dir = dir; + }; - return (leftTrans.y < rightTrans.y); - }); + class Left : public DetectCollisions> { + public: - for (id_type collider : colliders) - { - auto& colliderTrans = game_.getEntityManager(). - getComponent(collider); + inline static const MappableComponent::desc_boundaries_type& MapBoundaries( + const MappableComponent& mappable) + { + return mappable.leftBoundaries; + } + }; - // Check if the entity would still move into the potential collider. - if (colliderTrans.y >= result.newY + transformable.h) - { - break; - } + class Right : public DetectCollisions> { + public: - auto& colliderPonder = game_.getEntityManager(). - getComponent(collider); + inline static const MappableComponent::asc_boundaries_type& MapBoundaries( + const MappableComponent& mappable) + { + return mappable.rightBoundaries; + } + }; - processCollision( - entity, - collider, - Direction::down, - colliderPonder.colliderType, - colliderTrans.y, - colliderTrans.x, - colliderTrans.x + colliderTrans.w, - result); + class Up : public DetectCollisions> { + public: - if (result.stopProcessing) - { - break; - } - } + inline static const MappableComponent::desc_boundaries_type& MapBoundaries( + const MappableComponent& mappable) + { + return mappable.upBoundaries; + } + }; - // If movement hasn't been stopped by an intermediary object, and - // collision checking hasn't been stopped, process the environmental - // boundaries closest to the entity. - if (!result.stopProcessing && !result.touchedWall && boundaryCollision) - { - double boundaryAxis = it->first; + class Down : public DetectCollisions> { + public: - for (; - (it != std::end(mappable.downBoundaries)) && - (it->first == boundaryAxis); - it++) - { - if ((result.newX + transformable.w > it->second.lower) && - (result.newX < it->second.upper)) - { - processCollision( - entity, - mapEntity, - Direction::down, - it->second.type, - it->first, - it->second.lower, - it->second.upper, - result); - - if (result.stopProcessing) - { - break; - } - } - } - } + inline static const MappableComponent::asc_boundaries_type& MapBoundaries( + const MappableComponent& mappable) + { + return mappable.downBoundaries; } - } + }; +}; - // Move - if (!ponderable.frozen) +CollisionResult PonderingSystem::detectCollisions( + id_type entity, + double x, + double y) +{ + auto& transformable = game_.getEntityManager(). + getComponent(entity); + + CollisionResult result; + result.newX = x; + result.newY = transformable.y; + + // Find horizontal collisions. + if (result.newX < transformable.x) { - transformable.x = result.newX; - transformable.y = result.newY; + detectCollisionsInDirection(entity, result); + } else if (result.newX > transformable.x) + { + detectCollisionsInDirection(entity, result); } - // Perform cleanup for orientable entites - if (game_.getEntityManager().hasComponent(entity)) + // Find vertical collisions + if (!result.stopProcessing) { - auto& orientable = game_.getEntityManager(). - getComponent(entity); + result.newY = y; + result.touchedWall = false; - // Handle changes in groundedness - if (ponderable.grounded != oldGrounded) + if (result.newY < transformable.y) { - if (ponderable.grounded) - { - game_.getSystemManager().getSystem().land(entity); - } else { - game_.getSystemManager(). - getSystem().startFalling(entity); - } + detectCollisionsInDirection(entity, result); + } else if (result.newY > transformable.y) + { + detectCollisionsInDirection(entity, result); } + } - // Complete dropping, if necessary - if (orientable.getDropState() == OrientableComponent::DropState::active) + return result; +} + +template +void PonderingSystem::detectCollisionsInDirection( + id_type entity, + CollisionResult& result) +{ + // Get map data. + auto& realizable = game_.getEntityManager(). + getComponent( + game_.getSystemManager().getSystem().getSingleton()); + + id_type mapEntity = realizable.activeMap; + + auto& mappable = game_.getEntityManager(). + getComponent(mapEntity); + + // Get old location. + auto& transformable = game_.getEntityManager(). + getComponent(entity); + + bool boundaryCollision = false; + + auto boundaries = Param::MapBoundaries(mappable); + auto it = boundaries.lower_bound(Param::OldAxis(transformable)); + + // Find the axis distance of the closest environmental boundary. + for (; + (it != std::end(boundaries)) && + Param::AtLeastInAxisSweep( + it->first, + Param::NewAxis(result, transformable)); + it++) + { + // Check that the boundary is in range for the other axis. + if ((Param::NonAxisNewUpper(result, transformable) > it->second.lower) && + (Param::NonAxisNewLower(result, transformable) < it->second.upper)) { - orientable.setDropState(OrientableComponent::DropState::none); + // We have a collision! + boundaryCollision = true; + + break; } } - // Ferry or unferry as necessary - if ((ponderable.type == PonderableComponent::Type::freefalling) && - (ponderable.grounded != oldGrounded)) + // Find a list of potential colliders, sorted so that the closest is + // first. + std::vector colliders; + + auto entities = game_.getEntityManager().getEntitiesWithComponents< + PonderableComponent, + TransformableComponent>(); + + for (id_type collider : entities) { - if (ponderable.grounded && - game_.getEntityManager(). - hasComponent(result.groundEntity)) + // Can't collide with self. + if (collider == entity) { - // The body is now being ferried - auto& ferryPonder = game_.getEntityManager(). - getComponent(result.groundEntity); + continue; + } - ponderable.ferried = true; - ponderable.ferry = result.groundEntity; + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - ferryPonder.passengers.insert(entity); - } else if (ponderable.ferried) + // Only check objects that are active and collidable. + if (!colliderPonder.active || !colliderPonder.collidable) { - // The body is no longer being ferried - unferry(entity); + continue; } - } - - // Update a ferry passenger's relative position - if (ponderable.ferried) - { - auto& ferryTrans = game_.getEntityManager(). - getComponent(ponderable.ferry); - ponderable.relX = transformable.x - ferryTrans.x; - ponderable.relY = transformable.y - ferryTrans.y; + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); + + // Check if the entity would move into the potential collider, + if (Param::IsPastAxis( + Param::ObjectAxis(colliderTrans), + Param::NewAxis(result, transformable)) && + // that it wasn't already colliding, + !Param::IsPastAxis( + Param::ObjectAxis(colliderTrans), + Param::OldAxis(transformable)) && + // that the position on the non-axis is in range, + (Param::NonAxisOldUpper(colliderTrans) > + Param::NonAxisNewLower(result, transformable)) && + (Param::NonAxisOldLower(colliderTrans) < + Param::NonAxisNewUpper(result, transformable)) && + // and that the collider is not farther away than the environmental + // boundary. + (!boundaryCollision || + Param::AtLeastInAxisSweep( + Param::ObjectAxis(colliderTrans), + it->first))) + { + colliders.push_back(collider); + } } - // Handle ferry passengers - std::set passengers = ponderable.passengers; + std::sort( + std::begin(colliders), + std::end(colliders), + [&] (id_type left, id_type right) { + auto& leftTrans = game_.getEntityManager(). + getComponent(left); - for (id_type passenger : passengers) - { - tickBody( - passenger, - dt, - entities); - } + auto& rightTrans = game_.getEntityManager(). + getComponent(right); - // Move to an adjacent map, if necessary - if (result.adjacentlyWarping) + return Param::Closer( + Param::ObjectAxis(leftTrans), + Param::ObjectAxis(rightTrans)); + }); + + for (id_type collider : colliders) { - double warpX = result.newX; - double warpY = result.newY; + auto& colliderTrans = game_.getEntityManager(). + getComponent(collider); - switch (result.adjWarpDir) + // Check if the entity would still move into the potential collider. + if (!Param::IsPastAxis( + Param::ObjectAxis(colliderTrans), + Param::NewAxis(result, transformable))) { - case Direction::left: - { - warpX = GAME_WIDTH + WALL_GAP - transformable.w; - - break; - } - - case Direction::right: - { - warpX = -WALL_GAP; + break; + } - break; - } + auto& colliderPonder = game_.getEntityManager(). + getComponent(collider); - case Direction::up: - { - warpY = MAP_HEIGHT * TILE_HEIGHT - transformable.h; + processCollision( + entity, + collider, + Param::Dir, + colliderPonder.colliderType, + Param::ObjectAxis(colliderTrans), + Param::NonAxisOldLower(colliderTrans), + Param::NonAxisOldUpper(colliderTrans), + result); + + if (result.stopProcessing) + { + break; + } + } - break; - } + // If movement hasn't been stopped by an intermediary object, and + // collision checking hasn't been stopped, process the environmental + // boundaries closest to the entity. + if (!result.stopProcessing && !result.touchedWall && boundaryCollision) + { + double boundaryAxis = it->first; - case Direction::down: + for (; + (it != std::end(boundaries)) && + (it->first == boundaryAxis); + it++) + { + if ((Param::NonAxisNewUpper(result, transformable) > it->second.lower) && + (Param::NonAxisNewLower(result, transformable) < it->second.upper)) { - warpY = -WALL_GAP; + processCollision( + entity, + mapEntity, + Param::Dir, + it->second.type, + it->first, + it->second.lower, + it->second.upper, + result); - break; + if (result.stopProcessing) + { + break; + } } } - - game_.getSystemManager().getSystem(). - changeMap( - entity, - result.adjWarpMapId, - warpX, - warpY); } } @@ -1012,7 +932,7 @@ void PonderingSystem::processCollision( result.newY = axis - transformable.h; result.groundEntity = collider; ponderable.velY = 0.0; - ponderable.grounded = true; + result.grounded = true; break; } diff --git a/src/systems/pondering.h b/src/systems/pondering.h index eed0d32..abc6db2 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -5,6 +5,19 @@ #include "components/ponderable.h" #include "direction.h" +struct CollisionResult +{ + double newX; + double newY; + bool stopProcessing = false; + bool touchedWall = false; + bool adjacentlyWarping = false; + Direction adjWarpDir; + size_t adjWarpMapId; + bool grounded = false; + EntityManager::id_type groundEntity; +}; + class PonderingSystem : public System { public: @@ -34,23 +47,28 @@ public: private: - struct CollisionResult - { - double newX; - double newY; - bool stopProcessing = false; - bool touchedWall = false; - bool adjacentlyWarping = false; - Direction adjWarpDir; - size_t adjWarpMapId; - id_type groundEntity; - }; + void tickBody( id_type entity, double dt, const std::set& entities); + CollisionResult moveBody( + id_type entity, + double x, + double y); + + CollisionResult detectCollisions( + id_type entity, + double x, + double y); + + template + void detectCollisionsInDirection( + id_type entity, + CollisionResult& result); + void processCollision( id_type entity, id_type collider, -- cgit 1.4.1 From 5c82f052c26303318e81ddd76475c1d188cc74f4 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Tue, 8 May 2018 21:09:36 -0400 Subject: Simplified positions/sizes with vectors Positions and sizes are now stored as vectors (of doubles and ints, respectively). This allows for at least minor code simplification in many places, and cleans up the CollisionParams code in PonderingSystem quite a bit. --- src/components/automatable.h | 4 +- src/components/playable.h | 4 +- src/components/ponderable.h | 10 +- src/components/realizable.h | 4 +- src/components/transformable.h | 13 +- src/systems/animating.cpp | 8 +- src/systems/automating.cpp | 3 +- src/systems/orienting.cpp | 14 +- src/systems/playing.cpp | 19 +-- src/systems/playing.h | 4 +- src/systems/pondering.cpp | 294 +++++++++++++++-------------------------- src/systems/pondering.h | 34 +++-- src/systems/realizing.cpp | 38 +++--- src/vector.h | 111 ++++++++++++++++ 14 files changed, 285 insertions(+), 275 deletions(-) create mode 100644 src/vector.h (limited to 'src') diff --git a/src/components/automatable.h b/src/components/automatable.h index b37945f..c1fd1a3 100644 --- a/src/components/automatable.h +++ b/src/components/automatable.h @@ -4,6 +4,7 @@ #include "component.h" #include #include +#include "vector.h" class AutomatableComponent : public Component { public: @@ -18,8 +19,7 @@ public: * The horizontal and vertical speed, in pixels/sec, that the entity should * move at. */ - double speedX; - double speedY; + vec2d speed; /** * The duration of the action in seconds. diff --git a/src/components/playable.h b/src/components/playable.h index 94d4326..b8af0f2 100644 --- a/src/components/playable.h +++ b/src/components/playable.h @@ -3,6 +3,7 @@ #include "component.h" #include "entity_manager.h" +#include "vector.h" class PlayableComponent : public Component { public: @@ -24,8 +25,7 @@ public: * @managed_by PlayingSystem */ size_t checkpointMapId; - double checkpointX; - double checkpointY; + vec2d checkpointPos; }; diff --git a/src/components/ponderable.h b/src/components/ponderable.h index eff20e9..c0312b4 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -4,6 +4,7 @@ #include #include "component.h" #include "entity_manager.h" +#include "vector.h" class PonderableComponent : public Component { public: @@ -45,14 +46,12 @@ public: /** * The velocity of the body. */ - double velX = 0.0; - double velY = 0.0; + vec2d vel = { 0.0, 0.0 }; /** * The acceleration of the body. */ - double accelX = 0.0; - double accelY = 0.0; + vec2d accel = { 0.0, 0.0 }; /** * The type of physical body that the entity is meant to assume. The body will @@ -89,8 +88,7 @@ public: * * @managed_by PonderingSystem */ - double relX; - double relY; + vec2d rel = { 0.0, 0.0 }; /** * The bodies that are being ferried by this body. diff --git a/src/components/realizable.h b/src/components/realizable.h index 0858e7a..b749aeb 100644 --- a/src/components/realizable.h +++ b/src/components/realizable.h @@ -5,6 +5,7 @@ #include #include #include "entity_manager.h" +#include "vector.h" class RealizableComponent : public Component { public: @@ -31,8 +32,7 @@ public: * @managed_by RealizingSystem */ int startingMapId; - int startingX; - int startingY; + vec2i startingPos; /** * The set of map entities loaded by this entity. It is only intended for diff --git a/src/components/transformable.h b/src/components/transformable.h index 6f3c2ef..bb21996 100644 --- a/src/components/transformable.h +++ b/src/components/transformable.h @@ -2,6 +2,7 @@ #define LOCATABLE_H_39E526CA #include "component.h" +#include "vector.h" class TransformableComponent : public Component { public: @@ -15,24 +16,20 @@ public: * so, use PonderingSystem::unferry on the body to ensure that it is not * ferried. */ - double x; - double y; + vec2d pos; /** * The size of the entity. */ - int w; - int h; + vec2i size; /** * For prototypes, the original coordinates and size of the entity. * * @managed_by RealizingSystem */ - double origX; - double origY; - int origW; - int origH; + vec2d origPos; + vec2i origSize; }; #endif /* end of include guard: LOCATABLE_H_39E526CA */ diff --git a/src/systems/animating.cpp b/src/systems/animating.cpp index 8543ba2..50a32fc 100644 --- a/src/systems/animating.cpp +++ b/src/systems/animating.cpp @@ -64,10 +64,10 @@ void AnimatingSystem::render(Texture& texture) } Rectangle dstrect { - static_cast(transform.x), - static_cast(transform.y), - transform.w, - transform.h}; + static_cast(transform.pos.x()), + static_cast(transform.pos.y()), + transform.size.w(), + transform.size.h()}; const AnimationSet& aset = sprite.animationSet; game_.getRenderer().blit( diff --git a/src/systems/automating.cpp b/src/systems/automating.cpp index 0d85957..61b97d9 100644 --- a/src/systems/automating.cpp +++ b/src/systems/automating.cpp @@ -54,8 +54,7 @@ void AutomatingSystem::tick(double dt) auto& ponderable = game_.getEntityManager(). getComponent(entity); - ponderable.velX = curAction.speedX; - ponderable.velY = curAction.speedY; + ponderable.vel = curAction.speed; automatable.remaining -= dt; } diff --git a/src/systems/orienting.cpp b/src/systems/orienting.cpp index 206ebf6..d73ddd2 100644 --- a/src/systems/orienting.cpp +++ b/src/systems/orienting.cpp @@ -24,27 +24,27 @@ void OrientingSystem::tick(double) { case OrientableComponent::WalkState::still: { - ponderable.velX = 0.0; + ponderable.vel.x() = 0.0; break; } case OrientableComponent::WalkState::left: { - ponderable.velX = -WALK_SPEED; + ponderable.vel.x() = -WALK_SPEED; break; } case OrientableComponent::WalkState::right: { - ponderable.velX = WALK_SPEED; + ponderable.vel.x() = WALK_SPEED; break; } } - if (orientable.isJumping() && (ponderable.velY > 0)) + if (orientable.isJumping() && (ponderable.vel.y() > 0)) { orientable.setJumping(false); } @@ -122,8 +122,8 @@ void OrientingSystem::jump(id_type entity) playSound("res/Randomize87.wav", 0.25); - ponderable.velY = JUMP_VELOCITY; - ponderable.accelY = JUMP_GRAVITY; + ponderable.vel.y() = JUMP_VELOCITY; + ponderable.accel.y() = JUMP_GRAVITY; auto& animating = game_.getSystemManager().getSystem(); if (orientable.isFacingRight()) @@ -147,7 +147,7 @@ void OrientingSystem::stopJumping(id_type entity) auto& ponderable = game_.getEntityManager(). getComponent(entity); - ponderable.accelY = NORMAL_GRAVITY; + ponderable.accel.y() = NORMAL_GRAVITY; } } diff --git a/src/systems/playing.cpp b/src/systems/playing.cpp index acec4e7..dabc9a5 100644 --- a/src/systems/playing.cpp +++ b/src/systems/playing.cpp @@ -42,10 +42,9 @@ void PlayingSystem::initPlayer() auto& transformable = game_.getEntityManager(). emplaceComponent(player); - transformable.x = realizable.startingX; - transformable.y = realizable.startingY; - transformable.w = 10; - transformable.h = 12; + transformable.pos = realizable.startingPos; + transformable.size.w() = 10; + transformable.size.h() = 12; game_.getSystemManager().getSystem().initializeBody( player, @@ -59,8 +58,7 @@ void PlayingSystem::initPlayer() playable.mapId = realizable.activeMap; playable.checkpointMapId = realizable.startingMapId; - playable.checkpointX = realizable.startingX; - playable.checkpointY = realizable.startingY; + playable.checkpointPos = realizable.startingPos; realizing.enterActiveMap(player); @@ -70,8 +68,7 @@ void PlayingSystem::initPlayer() void PlayingSystem::changeMap( id_type player, size_t mapId, - double x, - double y) + vec2d warpPos) { auto& playable = game_.getEntityManager(). getComponent(player); @@ -103,8 +100,7 @@ void PlayingSystem::changeMap( pondering.unferry(player); - transformable.x = x; - transformable.y = y; + transformable.pos = warpPos; if (realizable.activePlayer == player) { @@ -139,8 +135,7 @@ void PlayingSystem::die(id_type player) changeMap( player, playable.checkpointMapId, - playable.checkpointX, - playable.checkpointY); + playable.checkpointPos); animatable.frozen = false; animatable.flickering = false; diff --git a/src/systems/playing.h b/src/systems/playing.h index 9ba403b..31f79ab 100644 --- a/src/systems/playing.h +++ b/src/systems/playing.h @@ -2,6 +2,7 @@ #define PLAYING_H_70A54F7D #include "system.h" +#include "vector.h" class PlayingSystem : public System { public: @@ -15,8 +16,7 @@ public: void changeMap( id_type player, size_t mapId, - double x, - double y); + vec2d warpPos); void die(id_type player); diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index 7b3ab2d..ec83270 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -47,7 +47,7 @@ void PonderingSystem::initializeBody( if (type == PonderableComponent::Type::freefalling) { - ponderable.accelY = NORMAL_GRAVITY; + ponderable.accel.y() = NORMAL_GRAVITY; } } @@ -56,10 +56,10 @@ void PonderingSystem::initPrototype(id_type prototype) auto& ponderable = game_.getEntityManager(). getComponent(prototype); - ponderable.velX = 0.0; - ponderable.velY = 0.0; - ponderable.accelX = 0.0; - ponderable.accelY = 0.0; + ponderable.vel.x() = 0.0; + ponderable.vel.y() = 0.0; + ponderable.accel.x() = 0.0; + ponderable.accel.y() = 0.0; ponderable.grounded = false; ponderable.frozen = false; ponderable.collidable = true; @@ -102,19 +102,17 @@ void PonderingSystem::tickBody( // Accelerate if (!ponderable.frozen) { - ponderable.velX += ponderable.accelX * dt; - ponderable.velY += ponderable.accelY * dt; + ponderable.vel += ponderable.accel * dt; if ((ponderable.type == PonderableComponent::Type::freefalling) - && (ponderable.velY > TERMINAL_VELOCITY)) + && (ponderable.vel.y() > TERMINAL_VELOCITY)) { - ponderable.velY = TERMINAL_VELOCITY; + ponderable.vel.y() = TERMINAL_VELOCITY; } } // Move - double newX = transformable.x; - double newY = transformable.y; + vec2d newPos = transformable.pos; if (!ponderable.frozen) { @@ -123,19 +121,13 @@ void PonderingSystem::tickBody( auto& ferryTrans = game_.getEntityManager(). getComponent(ponderable.ferry); - newX = ferryTrans.x + ponderable.relX; - newY = ferryTrans.y + ponderable.relY; + newPos = ferryTrans.pos + ponderable.rel; } - newX += ponderable.velX * dt; - newY += ponderable.velY * dt; + newPos += ponderable.vel * dt; } - CollisionResult result = - moveBody( - entity, - newX, - newY); + CollisionResult result = moveBody(entity, newPos); // Perform cleanup for orientable entites bool groundedChanged = (ponderable.grounded != result.grounded); @@ -194,8 +186,7 @@ void PonderingSystem::tickBody( auto& ferryTrans = game_.getEntityManager(). getComponent(ponderable.ferry); - ponderable.relX = transformable.x - ferryTrans.x; - ponderable.relY = transformable.y - ferryTrans.y; + ponderable.rel = transformable.pos - ferryTrans.pos; } // Handle ferry passengers @@ -212,35 +203,34 @@ void PonderingSystem::tickBody( // Move to an adjacent map, if necessary if (result.adjacentlyWarping) { - double warpX = result.newX; - double warpY = result.newY; + vec2d warpPos = result.pos; switch (result.adjWarpDir) { case Direction::left: { - warpX = GAME_WIDTH + WALL_GAP - transformable.w; + warpPos.x() = GAME_WIDTH + WALL_GAP - transformable.size.w(); break; } case Direction::right: { - warpX = -WALL_GAP; + warpPos.x() = -WALL_GAP; break; } case Direction::up: { - warpY = MAP_HEIGHT * TILE_HEIGHT - transformable.h; + warpPos.y() = MAP_HEIGHT * TILE_HEIGHT - transformable.size.h(); break; } case Direction::down: { - warpY = -WALL_GAP; + warpPos.y() = -WALL_GAP; break; } @@ -250,15 +240,13 @@ void PonderingSystem::tickBody( changeMap( entity, result.adjWarpMapId, - warpX, - warpY); + warpPos); } } -CollisionResult PonderingSystem::moveBody( +PonderingSystem::CollisionResult PonderingSystem::moveBody( id_type entity, - double x, - double y) + vec2d newPos) { auto& ponderable = game_.getEntityManager(). getComponent(entity); @@ -266,26 +254,29 @@ CollisionResult PonderingSystem::moveBody( auto& transformable = game_.getEntityManager(). getComponent(entity); - const double oldX = transformable.x; - const double oldY = transformable.y; - const double oldRight = oldX + transformable.w; - const double oldBottom = oldY + transformable.h; - CollisionResult result; if (ponderable.collidable) { - result = detectCollisions(entity, x, y); + result = detectCollisions(entity, newPos); } else { - result.newX = x; - result.newY = y; + result.pos = newPos; } // Move if (!ponderable.frozen) { - transformable.x = result.newX; - transformable.y = result.newY; + transformable.pos = result.pos; + + if (result.blockedHoriz) + { + ponderable.vel.x() = 0.0; + } + + if (result.blockedVert) + { + ponderable.vel.y() = 0.0; + } } return result; @@ -311,21 +302,14 @@ namespace CollisionParams { return (colliderAxis > entityAxis); } - inline static double OldAxis(const TransformableComponent& transformable) + inline static double EntityAxis(const vec2d& pos, const vec2i& size) { - return HorizVert::AxisOldLower(transformable); + return HorizVert::AxisLower(pos); } - inline static double NewAxis( - const CollisionResult& result, - const TransformableComponent&) + inline static double ObjectAxis(const vec2d& pos, const vec2i& size) { - return HorizVert::AxisNewLower(result); - } - - inline static double ObjectAxis(const TransformableComponent& transformable) - { - return HorizVert::AxisOldUpper(transformable); + return HorizVert::AxisUpper(pos, size); } inline static bool Closer(double left, double right) @@ -352,21 +336,14 @@ namespace CollisionParams { return (colliderAxis < entityAxis); } - inline static double OldAxis(const TransformableComponent& transformable) + inline static double EntityAxis(const vec2d& pos, const vec2i& size) { - return HorizVert::AxisOldUpper(transformable); + return HorizVert::AxisUpper(pos, size); } - inline static double NewAxis( - const CollisionResult& result, - const TransformableComponent& transformable) + inline static double ObjectAxis(const vec2d& pos, const vec2i& size) { - return HorizVert::AxisNewUpper(result, transformable); - } - - inline static double ObjectAxis(const TransformableComponent& transformable) - { - return HorizVert::AxisOldLower(transformable); + return HorizVert::AxisLower(pos); } inline static bool Closer(double left, double right) @@ -375,121 +352,62 @@ namespace CollisionParams { } }; - class Horizontal { + template + class HorizVert { public: - inline static double AxisOldLower( - const TransformableComponent& transformable) + inline static double AxisLower(const vec2d& pos) { - return transformable.x; + return pos.coords[Axis]; } - inline static double AxisOldUpper( - const TransformableComponent& transformable) + inline static double AxisUpper(const vec2d& pos, const vec2i& size) { - return transformable.x + transformable.w; + return pos.coords[Axis] + size.coords[Axis]; } - inline static double AxisNewLower(const CollisionResult& result) + inline static double NonAxisLower(const vec2d& pos) { - return result.newX; + return pos.coords[NonAxis]; } - inline static double AxisNewUpper( - const CollisionResult& result, - const TransformableComponent& transformable) + inline static double NonAxisUpper(const vec2d& pos, const vec2i& size) { - return result.newX + transformable.w; + return pos.coords[NonAxis] + size.coords[NonAxis]; } - inline static double NonAxisOldLower( - const TransformableComponent& transformable) - { - return transformable.y; - } - - inline static double NonAxisOldUpper( - const TransformableComponent& transformable) - { - return transformable.y + transformable.h; - } - - inline static double NonAxisNewLower( - const CollisionResult& result, - const TransformableComponent& transformable) - { - return result.newY; - } - - inline static double NonAxisNewUpper( - const CollisionResult& result, - const TransformableComponent& transformable) - { - return result.newY + transformable.h; - } }; - class Vertical { - public: - - inline static double AxisOldLower( - const TransformableComponent& transformable) - { - return transformable.y; - } - - inline static double AxisOldUpper( - const TransformableComponent& transformable) - { - return transformable.y + transformable.h; - } + using Horizontal = HorizVert<0, 1>; + using Vertical = HorizVert<1, 0>; - inline static double AxisNewLower(const CollisionResult& result) - { - return result.newY; - } + template + class DetectCollisions : public AscDesc { + public: - inline static double AxisNewUpper( - const CollisionResult& result, - const TransformableComponent& transformable) - { - return result.newY + transformable.h; - } + static const Direction Dir = dir; - inline static double NonAxisOldLower( - const TransformableComponent& transformable) + inline static double EntityAxis(const vec2d& pos, const vec2i& size) { - return transformable.x; + return AscDesc::EntityAxis(pos, size); } - inline static double NonAxisOldUpper( - const TransformableComponent& transformable) + inline static double ObjectAxis(const vec2d& pos, const vec2i& size) { - return transformable.x + transformable.w; + return AscDesc::ObjectAxis(pos, size); } - inline static double NonAxisNewLower( - const CollisionResult& result, - const TransformableComponent& transformable) + inline static double EntityAxis(const TransformableComponent& transformable) { - return result.newX; + return AscDesc::EntityAxis(transformable.pos, transformable.size); } - inline static double NonAxisNewUpper( - const CollisionResult& result, - const TransformableComponent& transformable) + inline static double ObjectAxis(const TransformableComponent& transformable) { - return result.newX + transformable.w; + return AscDesc::ObjectAxis(transformable.pos, transformable.size); } }; - template - class DetectCollisions : public AscDesc { - public: - - static const Direction Dir = dir; - }; - class Left : public DetectCollisions> { public: @@ -531,23 +449,22 @@ namespace CollisionParams { }; }; -CollisionResult PonderingSystem::detectCollisions( +PonderingSystem::CollisionResult PonderingSystem::detectCollisions( id_type entity, - double x, - double y) + vec2d newPos) { auto& transformable = game_.getEntityManager(). getComponent(entity); CollisionResult result; - result.newX = x; - result.newY = transformable.y; + result.pos.x() = newPos.x(); + result.pos.y() = transformable.pos.y(); // Find horizontal collisions. - if (result.newX < transformable.x) + if (result.pos.x() < transformable.pos.x()) { detectCollisionsInDirection(entity, result); - } else if (result.newX > transformable.x) + } else if (result.pos.x() > transformable.pos.x()) { detectCollisionsInDirection(entity, result); } @@ -555,13 +472,13 @@ CollisionResult PonderingSystem::detectCollisions( // Find vertical collisions if (!result.stopProcessing) { - result.newY = y; + result.pos.y() = newPos.y(); result.touchedWall = false; - if (result.newY < transformable.y) + if (result.pos.y() < transformable.pos.y()) { detectCollisionsInDirection(entity, result); - } else if (result.newY > transformable.y) + } else if (result.pos.y() > transformable.pos.y()) { detectCollisionsInDirection(entity, result); } @@ -586,25 +503,25 @@ void PonderingSystem::detectCollisionsInDirection( getComponent(mapEntity); // Get old location. - auto& transformable = game_.getEntityManager(). + auto& transform = game_.getEntityManager(). getComponent(entity); bool boundaryCollision = false; auto boundaries = Param::MapBoundaries(mappable); - auto it = boundaries.lower_bound(Param::OldAxis(transformable)); + auto it = boundaries.lower_bound(Param::EntityAxis(transform)); // Find the axis distance of the closest environmental boundary. for (; (it != std::end(boundaries)) && Param::AtLeastInAxisSweep( it->first, - Param::NewAxis(result, transformable)); + Param::EntityAxis(result.pos, transform.size)); it++) { // Check that the boundary is in range for the other axis. - if ((Param::NonAxisNewUpper(result, transformable) > it->second.lower) && - (Param::NonAxisNewLower(result, transformable) < it->second.upper)) + if ((Param::NonAxisUpper(result.pos, transform.size) > it->second.lower) && + (Param::NonAxisLower(result.pos) < it->second.upper)) { // We have a collision! boundaryCollision = true; @@ -644,16 +561,16 @@ void PonderingSystem::detectCollisionsInDirection( // Check if the entity would move into the potential collider, if (Param::IsPastAxis( Param::ObjectAxis(colliderTrans), - Param::NewAxis(result, transformable)) && + Param::EntityAxis(result.pos, transform.size)) && // that it wasn't already colliding, !Param::IsPastAxis( Param::ObjectAxis(colliderTrans), - Param::OldAxis(transformable)) && + Param::EntityAxis(transform)) && // that the position on the non-axis is in range, - (Param::NonAxisOldUpper(colliderTrans) > - Param::NonAxisNewLower(result, transformable)) && - (Param::NonAxisOldLower(colliderTrans) < - Param::NonAxisNewUpper(result, transformable)) && + (Param::NonAxisUpper(colliderTrans.pos, colliderTrans.size) > + Param::NonAxisLower(result.pos)) && + (Param::NonAxisLower(colliderTrans.pos) < + Param::NonAxisUpper(result.pos, transform.size)) && // and that the collider is not farther away than the environmental // boundary. (!boundaryCollision || @@ -688,7 +605,7 @@ void PonderingSystem::detectCollisionsInDirection( // Check if the entity would still move into the potential collider. if (!Param::IsPastAxis( Param::ObjectAxis(colliderTrans), - Param::NewAxis(result, transformable))) + Param::EntityAxis(result.pos, transform.size))) { break; } @@ -702,8 +619,8 @@ void PonderingSystem::detectCollisionsInDirection( Param::Dir, colliderPonder.colliderType, Param::ObjectAxis(colliderTrans), - Param::NonAxisOldLower(colliderTrans), - Param::NonAxisOldUpper(colliderTrans), + Param::NonAxisLower(colliderTrans.pos), + Param::NonAxisUpper(colliderTrans.pos, colliderTrans.size), result); if (result.stopProcessing) @@ -724,8 +641,8 @@ void PonderingSystem::detectCollisionsInDirection( (it->first == boundaryAxis); it++) { - if ((Param::NonAxisNewUpper(result, transformable) > it->second.lower) && - (Param::NonAxisNewLower(result, transformable) < it->second.upper)) + if ((Param::NonAxisLower(result.pos) < it->second.upper) && + (Param::NonAxisUpper(result.pos, transform.size) > it->second.lower)) { processCollision( entity, @@ -756,9 +673,6 @@ void PonderingSystem::processCollision( double upper, CollisionResult& result) { - auto& ponderable = game_.getEntityManager(). - getComponent(entity); - auto& transformable = game_.getEntityManager(). getComponent(entity); @@ -823,29 +737,29 @@ void PonderingSystem::processCollision( { case Direction::left: { - result.newX = GAME_WIDTH + WALL_GAP - transformable.w; + result.pos.x() = GAME_WIDTH + WALL_GAP - transformable.size.w(); break; } case Direction::right: { - result.newX = -WALL_GAP; + result.pos.x() = -WALL_GAP; break; } case Direction::up: { - result.newY = - MAP_HEIGHT * TILE_HEIGHT + WALL_GAP - transformable.h; + result.pos.y() = + MAP_HEIGHT * TILE_HEIGHT + WALL_GAP - transformable.pos.h(); break; } case Direction::down: { - result.newY = -WALL_GAP; + result.pos.y() = -WALL_GAP; break; } @@ -905,33 +819,33 @@ void PonderingSystem::processCollision( { case Direction::left: { - result.newX = axis; - ponderable.velX = 0.0; + result.pos.x() = axis; + result.blockedHoriz = true; break; } case Direction::right: { - result.newX = axis - transformable.w; - ponderable.velX = 0.0; + result.pos.x() = axis - transformable.size.w(); + result.blockedHoriz = true; break; } case Direction::up: { - result.newY = axis; - ponderable.velY = 0.0; + result.pos.y() = axis; + result.blockedVert = true; break; } case Direction::down: { - result.newY = axis - transformable.h; + result.pos.y() = axis - transformable.size.h(); + result.blockedVert = true; result.groundEntity = collider; - ponderable.velY = 0.0; result.grounded = true; break; diff --git a/src/systems/pondering.h b/src/systems/pondering.h index abc6db2..273db67 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -4,19 +4,7 @@ #include "system.h" #include "components/ponderable.h" #include "direction.h" - -struct CollisionResult -{ - double newX; - double newY; - bool stopProcessing = false; - bool touchedWall = false; - bool adjacentlyWarping = false; - Direction adjWarpDir; - size_t adjWarpMapId; - bool grounded = false; - EntityManager::id_type groundEntity; -}; +#include "vector.h" class PonderingSystem : public System { public: @@ -47,7 +35,19 @@ public: private: - + struct CollisionResult + { + vec2d pos; + bool stopProcessing = false; + bool touchedWall = false; + bool blockedHoriz = false; + bool blockedVert = false; + bool adjacentlyWarping = false; + Direction adjWarpDir; + size_t adjWarpMapId; + bool grounded = false; + id_type groundEntity; + }; void tickBody( id_type entity, @@ -56,13 +56,11 @@ private: CollisionResult moveBody( id_type entity, - double x, - double y); + vec2d newPos); CollisionResult detectCollisions( id_type entity, - double x, - double y); + vec2d newPos); template void detectCollisionsInDirection( diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp index 8e670ac..f9285ad 100644 --- a/src/systems/realizing.cpp +++ b/src/systems/realizing.cpp @@ -93,20 +93,20 @@ void parseAI( if (direction == "left") { - action.speedX = -speed; - action.speedY = 0; + action.speed.x() = -speed; + action.speed.y() = 0; } else if (direction == "right") { - action.speedX = speed; - action.speedY = 0; + action.speed.x() = speed; + action.speed.y() = 0; } else if (direction == "up") { - action.speedX = 0; - action.speedY = -speed; + action.speed.x() = 0; + action.speed.y() = -speed; } else if (direction == "down") { - action.speedX = 0; - action.speedY = speed; + action.speed.x() = 0; + action.speed.y() = speed; } action.dur = length / speed; @@ -186,11 +186,11 @@ EntityManager::id_type RealizingSystem::initSingleton( } key = getProp(top, "startx"); - realizable.startingX = atoi(reinterpret_cast(key)); + realizable.startingPos.x() = atoi(reinterpret_cast(key)); xmlFree(key); key = getProp(top, "starty"); - realizable.startingY = atoi(reinterpret_cast(key)); + realizable.startingPos.y() = atoi(reinterpret_cast(key)); xmlFree(key); key = getProp(top, "startmap"); @@ -260,11 +260,11 @@ EntityManager::id_type RealizingSystem::initSingleton( emplaceComponent(mapObject); key = getProp(mapNode, "x"); - transformable.origX = atoi(reinterpret_cast(key)); + transformable.origPos.x() = atoi(reinterpret_cast(key)); xmlFree(key); key = getProp(mapNode, "y"); - transformable.origY = atoi(reinterpret_cast(key)); + transformable.origPos.y() = atoi(reinterpret_cast(key)); xmlFree(key); // Set the sprite and size using the prototype definition. @@ -273,17 +273,17 @@ EntityManager::id_type RealizingSystem::initSingleton( xmlFree(key); key = getProp(prototypeNode, "width"); - transformable.origW = atoi(reinterpret_cast(key)); + transformable.origSize.w() = atoi(reinterpret_cast(key)); xmlFree(key); key = getProp(prototypeNode, "height"); - transformable.origH = atoi(reinterpret_cast(key)); + transformable.origSize.h() = atoi(reinterpret_cast(key)); xmlFree(key); AnimationSet objectAnim( spritePath.c_str(), - transformable.origW, - transformable.origH, + transformable.origSize.w(), + transformable.origSize.h(), 1); objectAnim.emplaceAnimation("static", 0, 1, 1); @@ -503,10 +503,8 @@ void RealizingSystem::loadMap(id_type mapEntity) auto& transformable = game_.getEntityManager(). getComponent(prototype); - transformable.x = transformable.origX; - transformable.y = transformable.origY; - transformable.w = transformable.origW; - transformable.h = transformable.origH; + transformable.pos = transformable.origPos; + transformable.size = transformable.origSize; } if (game_.getEntityManager().hasComponent(prototype)) diff --git a/src/vector.h b/src/vector.h new file mode 100644 index 0000000..3abd98a --- /dev/null +++ b/src/vector.h @@ -0,0 +1,111 @@ +#ifndef COORDINATES_H_A45D34FB +#define COORDINATES_H_A45D34FB + +template +class vec2 { +public: + + T coords[2]; + + vec2() = default; + + vec2(double x, double y) : coords{x, y} + { + } + + inline T& x() + { + return coords[0]; + } + + inline const T& x() const + { + return coords[0]; + } + + inline T& w() + { + return coords[0]; + } + + inline const T& w() const + { + return coords[0]; + } + + inline T& y() + { + return coords[1]; + } + + inline const T& y() const + { + return coords[1]; + } + + inline T& h() + { + return coords[1]; + } + + inline const T& h() const + { + return coords[1]; + } + + template + operator vec2() const + { + return vec2(x(), y()); + } + + vec2 operator+(const vec2& other) const + { + return vec2(x() + other.x(), y() + other.y()); + } + + vec2& operator+=(const vec2& other) + { + x() += other.x(); + y() += other.y(); + + return *this; + } + + vec2 operator-(const vec2& other) const + { + return vec2(x() - other.x(), y() - other.y()); + } + + vec2 operator-=(const vec2& other) + { + x() -= other.x(); + y() -= other.y(); + + return *this; + } + + vec2 operator-() const + { + return vec2(-x(), -y()); + } + + vec2 operator*(double s) const + { + return vec2(x() * s, y() * s); + } + + vec2& operator*=(double s) + { + x() *= s; + y() *= s; + + return *this; + } + +}; + +using vec2d = vec2; +using vec2i = vec2; + +#endif /* end of include guard: COORDINATES_H_A45D34FB */ -- cgit 1.4.1 From 67b24a8ddd89371cfb944c5b441c852f0edc23b1 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Tue, 8 May 2018 21:47:57 -0400 Subject: Fixed ferries pushing passengers Ferries now pretend that their passengers have already moved by the appropriate delta when detecting collision in the direction of their passengers. This allows a ferry to move into the space where their passengers are when there is nothing else blocking it. It also allows for special behavior when a passenger is crushed between its ferry and a wall, but this is not yet implemented. This fixes the first issue described in 8f1c4f1 -- that ferries cannot push their passengers. With this fix, ferries are basically functional. --- src/components/ponderable.h | 5 +- src/systems/pondering.cpp | 222 +++++++++++++++++++++++++++----------------- src/systems/pondering.h | 3 +- 3 files changed, 141 insertions(+), 89 deletions(-) (limited to 'src') diff --git a/src/components/ponderable.h b/src/components/ponderable.h index c0312b4..e6aa976 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h @@ -5,6 +5,7 @@ #include "component.h" #include "entity_manager.h" #include "vector.h" +#include "direction.h" class PonderableComponent : public Component { public: @@ -84,11 +85,11 @@ public: id_type ferry; /** - * The location of the body relative to the location of its ferry. + * The side of the ferry that the body is resting on, if there is one. * * @managed_by PonderingSystem */ - vec2d rel = { 0.0, 0.0 }; + Direction ferrySide; /** * The bodies that are being ferried by this body. diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index ec83270..c806cc8 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp @@ -31,10 +31,7 @@ void PonderingSystem::tick(double dt) continue; } - tickBody( - entity, - dt, - entities); + tickBody(entity, dt); } } @@ -85,8 +82,7 @@ void PonderingSystem::unferry(id_type entity) void PonderingSystem::tickBody( id_type entity, - double dt, - const std::set& entities) + double dt) { auto& ponderable = game_.getEntityManager(). getComponent(entity); @@ -116,14 +112,6 @@ void PonderingSystem::tickBody( if (!ponderable.frozen) { - if (ponderable.ferried) - { - auto& ferryTrans = game_.getEntityManager(). - getComponent(ponderable.ferry); - - newPos = ferryTrans.pos + ponderable.rel; - } - newPos += ponderable.vel * dt; } @@ -171,6 +159,7 @@ void PonderingSystem::tickBody( ponderable.ferried = true; ponderable.ferry = result.groundEntity; + ponderable.ferrySide = Direction::up; ferryPonder.passengers.insert(entity); } else if (ponderable.ferried) @@ -180,67 +169,12 @@ void PonderingSystem::tickBody( } } - // Update a ferry passenger's relative position - if (ponderable.ferried) - { - auto& ferryTrans = game_.getEntityManager(). - getComponent(ponderable.ferry); - - ponderable.rel = transformable.pos - ferryTrans.pos; - } - // Handle ferry passengers std::set passengers = ponderable.passengers; for (id_type passenger : passengers) { - tickBody( - passenger, - dt, - entities); - } - - // Move to an adjacent map, if necessary - if (result.adjacentlyWarping) - { - vec2d warpPos = result.pos; - - switch (result.adjWarpDir) - { - case Direction::left: - { - warpPos.x() = GAME_WIDTH + WALL_GAP - transformable.size.w(); - - break; - } - - case Direction::right: - { - warpPos.x() = -WALL_GAP; - - break; - } - - case Direction::up: - { - warpPos.y() = MAP_HEIGHT * TILE_HEIGHT - transformable.size.h(); - - break; - } - - case Direction::down: - { - warpPos.y() = -WALL_GAP; - - break; - } - } - - game_.getSystemManager().getSystem(). - changeMap( - entity, - result.adjWarpMapId, - warpPos); + tickBody(passenger, dt); } } @@ -251,9 +185,6 @@ PonderingSystem::CollisionResult PonderingSystem::moveBody( auto& ponderable = game_.getEntityManager(). getComponent(entity); - auto& transformable = game_.getEntityManager(). - getComponent(entity); - CollisionResult result; if (ponderable.collidable) @@ -263,11 +194,17 @@ PonderingSystem::CollisionResult PonderingSystem::moveBody( result.pos = newPos; } - // Move if (!ponderable.frozen) { + auto& transformable = game_.getEntityManager(). + getComponent(entity); + + vec2d delta = result.pos - transformable.pos; + + // Move. transformable.pos = result.pos; + // Stop if the entity hit a wall. if (result.blockedHoriz) { ponderable.vel.x() = 0.0; @@ -277,6 +214,60 @@ PonderingSystem::CollisionResult PonderingSystem::moveBody( { ponderable.vel.y() = 0.0; } + + // Move ferry passengers by the appropriate amount. + auto passengers = ponderable.passengers; + + for (id_type passenger : passengers) + { + auto& passTrans = game_.getEntityManager(). + getComponent(passenger); + + moveBody(passenger, passTrans.pos + delta); + } + + // Move to an adjacent map, if necessary + if (result.adjacentlyWarping) + { + vec2d warpPos = result.pos; + + switch (result.adjWarpDir) + { + case Direction::left: + { + warpPos.x() = GAME_WIDTH + WALL_GAP - transformable.size.w(); + + break; + } + + case Direction::right: + { + warpPos.x() = -WALL_GAP; + + break; + } + + case Direction::up: + { + warpPos.y() = MAP_HEIGHT * TILE_HEIGHT - transformable.size.h(); + + break; + } + + case Direction::down: + { + warpPos.y() = -WALL_GAP; + + break; + } + } + + game_.getSystemManager().getSystem(). + changeMap( + entity, + result.adjWarpMapId, + warpPos); + } } return result; @@ -506,6 +497,9 @@ void PonderingSystem::detectCollisionsInDirection( auto& transform = game_.getEntityManager(). getComponent(entity); + auto& ponderable = game_.getEntityManager(). + getComponent(entity); + bool boundaryCollision = false; auto boundaries = Param::MapBoundaries(mappable); @@ -530,6 +524,26 @@ void PonderingSystem::detectCollisionsInDirection( } } + // Find the results of pretending to move the entity's passengers, if there + // are any. + vec2d delta = result.pos - transform.pos; + std::map passResults; + + for (id_type passenger : ponderable.passengers) + { + auto& passPonder = game_.getEntityManager(). + getComponent(passenger); + + if (passPonder.ferrySide == Param::Dir) + { + auto& passTrans = game_.getEntityManager(). + getComponent(passenger); + + passResults[passenger] = + detectCollisions(passenger, passTrans.pos + delta); + } + } + // Find a list of potential colliders, sorted so that the closest is // first. std::vector colliders; @@ -555,33 +569,46 @@ void PonderingSystem::detectCollisionsInDirection( continue; } + // If the collider is a passenger of the entity, pretend that it has already + // moved. auto& colliderTrans = game_.getEntityManager(). getComponent(collider); + vec2d colliderPos = colliderTrans.pos; + vec2i colliderSize = colliderTrans.size; + + if (passResults.count(collider)) + { + colliderPos = passResults[collider].pos; + } + // Check if the entity would move into the potential collider, if (Param::IsPastAxis( - Param::ObjectAxis(colliderTrans), + Param::ObjectAxis(colliderPos, colliderSize), Param::EntityAxis(result.pos, transform.size)) && // that it wasn't already colliding, !Param::IsPastAxis( - Param::ObjectAxis(colliderTrans), + Param::ObjectAxis(colliderPos, colliderSize), Param::EntityAxis(transform)) && // that the position on the non-axis is in range, - (Param::NonAxisUpper(colliderTrans.pos, colliderTrans.size) > + (Param::NonAxisUpper(colliderPos, colliderSize) > Param::NonAxisLower(result.pos)) && - (Param::NonAxisLower(colliderTrans.pos) < + (Param::NonAxisLower(colliderPos) < Param::NonAxisUpper(result.pos, transform.size)) && // and that the collider is not farther away than the environmental // boundary. (!boundaryCollision || Param::AtLeastInAxisSweep( - Param::ObjectAxis(colliderTrans), + Param::ObjectAxis(colliderPos, colliderSize), it->first))) { colliders.push_back(collider); } } + // Sort the potential colliders such that the closest to the axis of movement + // is first. When sorting, treat passengers of the entity as having already + // moved. std::sort( std::begin(colliders), std::end(colliders), @@ -589,12 +616,26 @@ void PonderingSystem::detectCollisionsInDirection( auto& leftTrans = game_.getEntityManager(). getComponent(left); + vec2d leftPos = leftTrans.pos; + + if (passResults.count(left)) + { + leftPos = passResults[left].pos; + } + auto& rightTrans = game_.getEntityManager(). getComponent(right); + vec2d rightPos = rightTrans.pos; + + if (passResults.count(right)) + { + rightPos = passResults[right].pos; + } + return Param::Closer( - Param::ObjectAxis(leftTrans), - Param::ObjectAxis(rightTrans)); + Param::ObjectAxis(leftPos, leftTrans.size), + Param::ObjectAxis(rightPos, rightTrans.size)); }); for (id_type collider : colliders) @@ -602,14 +643,25 @@ void PonderingSystem::detectCollisionsInDirection( auto& colliderTrans = game_.getEntityManager(). getComponent(collider); + // If the collider is a passenger of the entity, pretend that it has already + // moved. + vec2d colliderPos = colliderTrans.pos; + vec2i colliderSize = colliderTrans.size; + + if (passResults.count(collider)) + { + colliderPos = passResults[collider].pos; + } + // Check if the entity would still move into the potential collider. if (!Param::IsPastAxis( - Param::ObjectAxis(colliderTrans), + Param::ObjectAxis(colliderPos, colliderSize), Param::EntityAxis(result.pos, transform.size))) { break; } + // TODO: Check if the entity is moving into one of its passengers. auto& colliderPonder = game_.getEntityManager(). getComponent(collider); @@ -618,9 +670,9 @@ void PonderingSystem::detectCollisionsInDirection( collider, Param::Dir, colliderPonder.colliderType, - Param::ObjectAxis(colliderTrans), - Param::NonAxisLower(colliderTrans.pos), - Param::NonAxisUpper(colliderTrans.pos, colliderTrans.size), + Param::ObjectAxis(colliderPos, colliderSize), + Param::NonAxisLower(colliderPos), + Param::NonAxisUpper(colliderPos, colliderSize), result); if (result.stopProcessing) diff --git a/src/systems/pondering.h b/src/systems/pondering.h index 273db67..c79bbf6 100644 --- a/src/systems/pondering.h +++ b/src/systems/pondering.h @@ -51,8 +51,7 @@ private: void tickBody( id_type entity, - double dt, - const std::set& entities); + double dt); CollisionResult moveBody( id_type entity, -- cgit 1.4.1 From 4bbfeae42a1245b1b84e8847787d7643e6a6f2cf Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Thu, 10 May 2018 19:27:59 -0400 Subject: Started integrating Lua as a scripting engine Currently moving platforms are able to have their movement controlled by a script rather than by XML, which is probably a better implementation and scales better to other things. The scripts, instead of using the components as state, use the stack as state. In this way, they pretend to be multithreaded. For instance, the moving platform calls moveRight and then moveLeft. Both of those functions internally make calls that say to wait until the next tick. When the AutomatingSystem ticks, it continues execution of all scripts (sequentially, of course) until they ask for the next tick again. This is implemented using coroutines. --- CMakeLists.txt | 5 +- res/platform.lua | 27 + src/components/automatable.h | 81 +- src/components/realizable.h | 3 + src/systems/automating.cpp | 99 +- src/systems/automating.h | 3 + src/systems/realizing.cpp | 153 +- src/vector.h | 10 +- vendor/sol.hpp | 21575 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 21688 insertions(+), 268 deletions(-) create mode 100644 res/platform.lua create mode 100644 vendor/sol.hpp (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 04ca668..fbc843c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ find_package(GLEW REQUIRED) find_package(portaudio REQUIRED) find_package(libsndfile REQUIRED) find_package(libxml2 REQUIRED) +find_package(lua REQUIRED) IF(APPLE) FIND_LIBRARY(COCOA_LIBRARY Cocoa) @@ -32,6 +33,7 @@ set(ALL_LIBS ${PORTAUDIO_LIBRARIES} ${LIBSNDFILE_LIBRARY} ${LIBXML2_LIBRARIES} + ${LUA_LIBRARIES} ${EXTRA_LIBS} ) @@ -40,6 +42,7 @@ include_directories( ${GLFW_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIRS} ${GLEW_INCLUDE_DIRS} + ${LUA_INCLUDE_DIRS} src vendor ) @@ -71,6 +74,6 @@ add_executable(Aromatherapy vendor/stb_image.cpp ) -set_property(TARGET Aromatherapy PROPERTY CXX_STANDARD 11) +set_property(TARGET Aromatherapy PROPERTY CXX_STANDARD 17) set_property(TARGET Aromatherapy PROPERTY CXX_STANDARD_REQUIRED ON) target_link_libraries(Aromatherapy ${ALL_LIBS}) diff --git a/res/platform.lua b/res/platform.lua new file mode 100644 index 0000000..31a7cba --- /dev/null +++ b/res/platform.lua @@ -0,0 +1,27 @@ +function moveLeft(entity, len, speed) + local remaining = len / speed + + while (remaining > 0) do + print("no") + --entity:ponderable().vel:x(-speed) + remaining = remaining - coroutine.yield() + end +end + +function moveRight(entity, len, speed) + local remaining = len / speed + + while (remaining > 0) do + print("no2") + --entity:ponderable().vel:x(speed) + remaining = remaining - coroutine.yield() + end +end + +function run(entity) + print("yes") + while true do + moveRight(entity, 90, 30) + moveLeft(entity, 90, 30) + end +end \ No newline at end of file diff --git a/src/components/automatable.h b/src/components/automatable.h index c1fd1a3..d30340a 100644 --- a/src/components/automatable.h +++ b/src/components/automatable.h @@ -2,87 +2,16 @@ #define AUTOMATABLE_H_3D519131 #include "component.h" -#include -#include -#include "vector.h" +#include +#include class AutomatableComponent : public Component { public: - /** - * Helper class that defines an automatable action. - */ - class Action { - public: - - /** - * The horizontal and vertical speed, in pixels/sec, that the entity should - * move at. - */ - vec2d speed; - - /** - * The duration of the action in seconds. - */ - double dur; - }; - - /** - * Helper type that defines a behavior that an entity can exhibit, which is a - * list of actions that are stepped through in sequence. - */ - using Behavior = std::vector; - - /** - * A group of behaviors that the entity can exhibit, which are picked at - * random at the start of automation and whenever a behavior completes. - * - * @managed_by RealizingSystem - */ - std::vector behaviors; - - /** - * A random distribution over the above behaviors. - * - * @managed_by RealizingSystem - */ - std::discrete_distribution behaviorDist; - - /** - * A flag indicating whether a behavior is currently executing. - * - * @managed_by AutomatingSystem - */ - bool behaviorRunning = false; - - /** - * A flag indicating whether an action is currently executing. - * - * @managed_by AutomatingSystem - */ - bool actionRunning = false; - - /** - * The index of the currently executing behavior, if there is one. - * - * @managed_by AutomatingSystem - */ - size_t currentBehavior; + std::unique_ptr runner; + std::unique_ptr behavior; - /** - * The index of the currently executing action, if there is one. - * - * @managed_by AutomatingSystem - */ - size_t currentAction; - - /** - * The amount of time remaining, in seconds, of the currently executing - * action. - * - * @managed_by AutomatingSystem - */ - double remaining; + sol::environment origBehavior; /** * If this flag is disabled, the entity will be ignored by the automating diff --git a/src/components/realizable.h b/src/components/realizable.h index b749aeb..bc834a2 100644 --- a/src/components/realizable.h +++ b/src/components/realizable.h @@ -4,6 +4,7 @@ #include "component.h" #include #include +#include #include "entity_manager.h" #include "vector.h" @@ -69,6 +70,8 @@ public: * The entity ID of the currently active player. */ id_type activePlayer; + + sol::state scriptEngine; }; #endif /* end of include guard: REALIZABLE_H_36D8D71E */ diff --git a/src/systems/automating.cpp b/src/systems/automating.cpp index 61b97d9..6cec3bf 100644 --- a/src/systems/automating.cpp +++ b/src/systems/automating.cpp @@ -2,13 +2,24 @@ #include "game.h" #include "components/automatable.h" #include "components/ponderable.h" -#include "systems/pondering.h" +#include "components/realizable.h" +#include "systems/realizing.h" +#include "vector.h" + +struct script_entity { + using id_type = EntityManager::id_type; + + id_type id; + + script_entity(id_type id) : id(id) + { + } +}; void AutomatingSystem::tick(double dt) { auto entities = game_.getEntityManager().getEntitiesWithComponents< - AutomatableComponent, - PonderableComponent>(); + AutomatableComponent>(); for (id_type entity : entities) { @@ -20,43 +31,7 @@ void AutomatingSystem::tick(double dt) continue; } - if (automatable.behaviorRunning && - (automatable.remaining <= 0.0)) - { - automatable.currentAction++; - automatable.actionRunning = false; - - if (automatable.currentAction == - automatable.behaviors[automatable.currentBehavior].size()) - { - automatable.behaviorRunning = false; - } - } - - if (!automatable.behaviorRunning) - { - automatable.currentBehavior = automatable.behaviorDist(game_.getRng()); - automatable.currentAction = 0; - automatable.behaviorRunning = true; - } - - AutomatableComponent::Action& curAction = - automatable.behaviors - [automatable.currentBehavior] - [automatable.currentAction]; - - if (!automatable.actionRunning) - { - automatable.remaining = curAction.dur; - automatable.actionRunning = true; - } - - auto& ponderable = game_.getEntityManager(). - getComponent(entity); - - ponderable.vel = curAction.speed; - - automatable.remaining -= dt; + (*automatable.behavior)(dt); } } @@ -65,6 +40,46 @@ void AutomatingSystem::initPrototype(id_type prototype) auto& automatable = game_.getEntityManager(). getComponent(prototype); - automatable.behaviorRunning = false; - automatable.actionRunning = false; + auto& realizable = game_.getEntityManager(). + getComponent( + game_.getSystemManager().getSystem().getSingleton()); + automatable.behavior.reset(); + automatable.runner = std::unique_ptr(new sol::thread(sol::thread::create(realizable.scriptEngine.lua_state()))); + automatable.behavior = std::unique_ptr(new sol::coroutine(automatable.runner->state()["run"])); + (*automatable.behavior)(script_entity(prototype)); +} + +void AutomatingSystem::initScriptEngine(sol::state& scriptEngine) +{ + scriptEngine.open_libraries(sol::lib::base, sol::lib::coroutine); + scriptEngine.new_usertype( + "vec2d", + sol::constructors(), + "x", sol::property( + [] (vec2d& v) -> double { return v.x(); }, + [] (vec2d& v, double x) { v.x() = x; }), + "y", sol::property( + [] (vec2d& v) -> double { return v.y(); }, + [] (vec2d& v, double y) { v.y() = y; })); + + scriptEngine.new_usertype( + "vec2i", + sol::constructors(), + "x", [] (vec2i& v) -> int& { return v.x(); }, + "y", [] (vec2i& v) -> int& { return v.y(); }); + + scriptEngine.new_usertype( + "entity", + sol::constructors(), + "id", &script_entity::id, + "ponderable", + [&] (script_entity& entity) -> PonderableComponent& { + return game_.getEntityManager(). + getComponent(entity.id); + }); + + scriptEngine.new_usertype( + "ponderable", + "vel", &PonderableComponent::vel, + "accel", &PonderableComponent::accel); } diff --git a/src/systems/automating.h b/src/systems/automating.h index c78b7cf..117b622 100644 --- a/src/systems/automating.h +++ b/src/systems/automating.h @@ -2,6 +2,7 @@ #define AUTOMATING_H_E6E5D76E #include "system.h" +#include class AutomatingSystem : public System { public: @@ -14,6 +15,8 @@ public: void initPrototype(id_type prototype); + void initScriptEngine(sol::state& scriptEngine); + }; #endif /* end of include guard: AUTOMATING_H_E6E5D76E */ diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp index f9285ad..28e2279 100644 --- a/src/systems/realizing.cpp +++ b/src/systems/realizing.cpp @@ -29,92 +29,6 @@ inline xmlChar* getProp(xmlNodePtr node, const char* attr) return key; } -void parseAI( - xmlNodePtr node, - std::vector& behavior, - const std::map& items) -{ - xmlChar* key = nullptr; - - if (!xmlStrcmp( - node->name, - reinterpret_cast("switch"))) - { - key = getProp(node, "item"); - std::string switchItem = reinterpret_cast(key); - xmlFree(key); - - for (xmlNodePtr switchNode = node->xmlChildrenNode; - switchNode != nullptr; - switchNode = switchNode->next) - { - if (!xmlStrcmp( - switchNode->name, - reinterpret_cast("case"))) - { - key = getProp(switchNode, "value"); - int caseValue = atoi(reinterpret_cast(key)); - xmlFree(key); - - if (items.at(switchItem) == caseValue) - { - for (xmlNodePtr caseNode = switchNode->xmlChildrenNode; - caseNode != nullptr; - caseNode = caseNode->next) - { - parseAI( - caseNode, - behavior, - items); - } - } - } - } - } else if (!xmlStrcmp( - node->name, - reinterpret_cast("move"))) - { - key = getProp(node, "direction"); - std::string direction = reinterpret_cast(key); - xmlFree(key); - - key = getProp(node, "length-var"); - std::string lengthVar = reinterpret_cast(key); - xmlFree(key); - - key = getProp(node, "speed-var"); - std::string speedVar = reinterpret_cast(key); - xmlFree(key); - - double length = items.at(lengthVar); - double speed = items.at(speedVar); - - AutomatableComponent::Action action; - - if (direction == "left") - { - action.speed.x() = -speed; - action.speed.y() = 0; - } else if (direction == "right") - { - action.speed.x() = speed; - action.speed.y() = 0; - } else if (direction == "up") - { - action.speed.x() = 0; - action.speed.y() = -speed; - } else if (direction == "down") - { - action.speed.x() = 0; - action.speed.y() = speed; - } - - action.dur = length / speed; - - behavior.push_back(std::move(action)); - } -} - // TODO: neither the XML doc nor any of the emplaced entities are properly // destroyed if this method throws an exception. EntityManager::id_type RealizingSystem::initSingleton( @@ -126,6 +40,9 @@ EntityManager::id_type RealizingSystem::initSingleton( auto& realizable = game_.getEntityManager(). emplaceComponent(world); + game_.getSystemManager().getSystem(). + initScriptEngine(realizable.scriptEngine); + realizable.worldFile = worldFile; realizable.prototypeFile = prototypeFile; @@ -299,68 +216,14 @@ EntityManager::id_type RealizingSystem::initSingleton( game_.getSystemManager().getSystem(). initializeBody(mapObject, PonderableComponent::Type::vacuumed); - // Look for any object configuration. - std::map items; - - for (xmlNodePtr objectNode = mapNode->xmlChildrenNode; - objectNode != nullptr; - objectNode = objectNode->next) + if (prototypeId == "movplat") { - if (!xmlStrcmp( - objectNode->name, - reinterpret_cast("item"))) - { - key = getProp(objectNode, "id"); - std::string itemName = reinterpret_cast(key); - xmlFree(key); - - key = xmlNodeGetContent(objectNode); - int itemVal = atoi(reinterpret_cast(key)); - xmlFree(key); - - items[itemName] = itemVal; - } - } + auto& automatable = game_.getEntityManager(). + emplaceComponent(mapObject); - // Add any AI behaviors. - std::vector behaviorWeights; - for (xmlNodePtr protoSubNode = prototypeNode->xmlChildrenNode; - protoSubNode != nullptr; - protoSubNode = protoSubNode->next) - { - if (!xmlStrcmp( - protoSubNode->name, - reinterpret_cast("ai"))) - { - if (!game_.getEntityManager(). - hasComponent(mapObject)) - { - game_.getEntityManager(). - emplaceComponent(mapObject); - } - - auto& automatable = game_.getEntityManager(). - getComponent(mapObject); - - key = getProp(protoSubNode, "chance"); - behaviorWeights.push_back(atof(reinterpret_cast(key))); - xmlFree(key); - - std::vector behavior; - - for (xmlNodePtr aiNode = protoSubNode->xmlChildrenNode; - aiNode != nullptr; - aiNode = aiNode->next) - { - parseAI( - aiNode, - behavior, - items); - } - - automatable.behaviors.push_back(std::move(behavior)); - } + realizable.scriptEngine.script_file( + "res/platform.lua");//, } mappable.objects.push_back(mapObject); diff --git a/src/vector.h b/src/vector.h index 3abd98a..9355dd5 100644 --- a/src/vector.h +++ b/src/vector.h @@ -7,9 +7,11 @@ public: T coords[2]; - vec2() = default; + vec2() : coords{0, 0} + { + } - vec2(double x, double y) : coords{x, y} + vec2(T x, T y) : coords{x, y} { } @@ -90,12 +92,12 @@ public: return vec2(-x(), -y()); } - vec2 operator*(double s) const + vec2 operator*(T s) const { return vec2(x() * s, y() * s); } - vec2& operator*=(double s) + vec2& operator*=(T s) { x() *= s; y() *= s; diff --git a/vendor/sol.hpp b/vendor/sol.hpp new file mode 100644 index 0000000..d033cba --- /dev/null +++ b/vendor/sol.hpp @@ -0,0 +1,21575 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// This file was generated with a script. +// Generated 2018-04-18 00:12:41.772355 UTC +// This header was generated with sol v2.20.0 (revision 8b77411) +// https://github.com/ThePhD/sol2 + +#ifndef SOL_SINGLE_INCLUDE_HPP +#define SOL_SINGLE_INCLUDE_HPP + +// beginning of sol.hpp + +#ifndef SOL_HPP +#define SOL_HPP + +#if defined(UE_BUILD_DEBUG) || defined(UE_BUILD_DEVELOPMENT) || defined(UE_BUILD_TEST) || defined(UE_BUILD_SHIPPING) || defined(UE_SERVER) +#define SOL_INSIDE_UNREAL 1 +#endif // Unreal Engine 4 bullshit + +#if defined(SOL_INSIDE_UNREAL) && SOL_INSIDE_UNREAL +#ifdef check +#define SOL_INSIDE_UNREAL_REMOVED_CHECK +#undef check +#endif +#endif // Unreal Engine 4 Bullshit + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wconversion" +#if __GNUC__ > 6 +#pragma GCC diagnostic ignored "-Wnoexcept-type" +#endif +#elif defined(__clang__) +#elif defined _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4324 ) // structure was padded due to alignment specifier +#pragma warning( disable : 4503 ) // decorated name horse shit +#pragma warning( disable : 4702 ) // unreachable code +#pragma warning( disable: 4127 ) // 'conditional expression is constant' yeah that's the point your old compilers don't have `if constexpr` you jerk +#pragma warning( disable: 4505 ) // some other nonsense warning +#endif // clang++ vs. g++ vs. VC++ + +// beginning of sol/forward.hpp + +// beginning of sol/feature_test.hpp + +#if (defined(__cplusplus) && __cplusplus == 201703L) || (defined(_MSC_VER) && _MSC_VER > 1900 && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && (_MSVC_LANG > 201402L)))) +#ifndef SOL_CXX17_FEATURES +#define SOL_CXX17_FEATURES 1 +#endif // C++17 features macro +#endif // C++17 features check + +#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES +#if defined(__cpp_noexcept_function_type) || ((defined(_MSC_VER) && _MSC_VER > 1911) && (defined(_MSVC_LANG) && ((_MSVC_LANG >= 201403L)))) +#ifndef SOL_NOEXCEPT_FUNCTION_TYPE +#define SOL_NOEXCEPT_FUNCTION_TYPE 1 +#endif // noexcept is part of a function's type +#endif // compiler-specific checks +#if defined(__clang__) && defined(__APPLE__) +#if defined(__has_include) +#if __has_include() +#define SOL_STD_VARIANT 1 +#endif // has include nonsense +#endif // __has_include +#else +#define SOL_STD_VARIANT 1 +#endif // Clang screws up variant +#endif // C++17 only + +// beginning of sol/config.hpp + +#ifdef _MSC_VER + #if defined(_DEBUG) && !defined(NDEBUG) + + #ifndef SOL_IN_DEBUG_DETECTED + #define SOL_IN_DEBUG_DETECTED 1 + #endif + + #endif // VC++ Debug macros + + #ifndef _CPPUNWIND + #ifndef SOL_NO_EXCEPTIONS + #define SOL_NO_EXCEPTIONS 1 + #endif + #endif // Automatic Exceptions + + #ifndef _CPPRTTI + #ifndef SOL_NO_RTTI + #define SOL_NO_RTTI 1 + #endif + #endif // Automatic RTTI +#elif defined(__GNUC__) || defined(__clang__) + + #if !defined(NDEBUG) && !defined(__OPTIMIZE__) + + #ifndef SOL_IN_DEBUG_DETECTED + #define SOL_IN_DEBUG_DETECTED 1 + #endif + + #endif // Not Debug && g++ optimizer flag + + #ifndef __EXCEPTIONS + #ifndef SOL_NO_EXCEPTIONS + #define SOL_NO_EXCEPTIONS 1 + #endif + #endif // No Exceptions + + #ifndef __GXX_RTTI + #ifndef SOL_NO_RTII + #define SOL_NO_RTTI 1 + #endif + #endif // No RTTI + +#endif // vc++ || clang++/g++ + +#if defined(SOL_CHECK_ARGUMENTS) && SOL_CHECK_ARGUMENTS + + // Checks low-level getter function + // (and thusly, affects nearly entire framework) + #if !defined(SOL_SAFE_GETTER) + #define SOL_SAFE_GETTER 1 + #endif + + // Checks access on usertype functions + // local my_obj = my_type.new() + // my_obj.my_member_function() + // -- bad syntax and crash + #if !defined(SOL_SAFE_USERTYPE) + #define SOL_SAFE_USERTYPE 1 + #endif + + // Checks sol::reference derived boundaries + // sol::function ref(L, 1); + // sol::userdata sref(L, 2); + #if !defined(SOL_SAFE_REFERENCES) + #define SOL_SAFE_REFERENCES 1 + #endif + + // Changes all typedefs of sol::function to point to the + // protected_function version, instead of unsafe_function + #if !defined(SOL_SAFE_FUNCTION) + #define SOL_SAFE_FUNCTION 1 + #endif + + // Checks function parameters and + // returns upon call into/from Lua + // local a = 1 + // local b = "woof" + // my_c_function(a, b) + #if !defined(SOL_SAFE_FUNCTION_CALLS) + #define SOL_SAFE_FUNCTION_CALLS 1 + #endif + + // Checks conversions + // int v = lua["bark"]; + // int v2 = my_sol_function(); + #if !defined(SOL_SAFE_PROXIES) + #define SOL_SAFE_PROXIES 1 + #endif + + // Check overflowing number conversions + // for things like 64 bit integers that don't fit in a typical lua_Number + // for Lua 5.1 and 5.2 + #if !defined(SOL_SAFE_NUMERICS) + #define SOL_SAFE_NUMERICS 1 + #endif + + // Turn off Number Precision Checks + // if this is defined, we do not do range + // checks on integers / unsigned integers that might + // be bigger than what Lua can represent + #if !defined(SOL_NO_CHECK_NUMBER_PRECISION) + // off by default + #define SOL_NO_CHECK_NUMBER_PRECISION 0 + #endif + +#endif // Turn on Safety for all if top-level macro is defined + +#if defined(SOL_IN_DEBUG_DETECTED) && SOL_IN_DEBUG_DETECTED + + #if !defined(SOL_SAFE_REFERENCES) + // Ensure that references are forcefully type-checked upon construction + #define SOL_SAFE_REFERENCES 1 + #endif + + // Safe usertypes checks for errors such as + // obj = my_type.new() + // obj.f() -- note the '.' instead of ':' + // usertypes should be safe no matter what + #if !defined(SOL_SAFE_USERTYPE) + #define SOL_SAFE_USERTYPE 1 + #endif + + #if !defined(SOL_SAFE_FUNCTION_CALLS) + // Function calls from Lua should be automatically safe in debug mode + #define SOL_SAFE_FUNCTION_CALLS 1 + #endif + + // Print any exceptions / errors that occur + // in debug mode to the default error stream / console + #if !defined(SOL_PRINT_ERRORS) + #define SOL_PRINT_ERRORS 1 + #endif + +#endif // DEBUG: Turn on all debug safety features for VC++ / g++ / clang++ and similar + +#if !defined(SOL_PRINT_ERRORS) +#define SOL_PRINT_ERRORS 0 +#endif + +#if !defined(SOL_DEFAULT_PASS_ON_ERROR) +#define SOL_DEFAULT_PASS_ON_ERROR 0 +#endif + +#if !defined(SOL_ENABLE_INTEROP) +#define SOL_ENABLE_INTEROP 0 +#endif + +#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) || defined(__OBJC__) || defined(nil) +#if !defined(SOL_NO_NIL) +#define SOL_NO_NIL 1 +#endif +#endif // avoiding nil defines / keywords + +#if defined(SOL_USE_BOOST) && SOL_USE_BOOST +#ifndef SOL_UNORDERED_MAP_COMPATIBLE_HASH +#define SOL_UNORDERED_MAP_COMPATIBLE_HASH 1 +#endif // SOL_UNORDERED_MAP_COMPATIBLE_HASH +#endif + +#ifndef SOL_STACK_STRING_OPTIMIZATION_SIZE +#define SOL_STACK_STRING_OPTIMIZATION_SIZE 1024 +#endif // Optimized conversion routines using a KB or so off the stack + +// end of sol/config.hpp + +// end of sol/feature_test.hpp + +namespace sol { + + template + class basic_reference; + using reference = basic_reference; + using main_reference = basic_reference; + class stack_reference; + + struct proxy_base_tag; + template + struct proxy_base; + template + struct proxy; + + template + class usertype; + template + class simple_usertype; + template + class basic_table_core; + template + using table_core = basic_table_core; + template + using main_table_core = basic_table_core; + template + using stack_table_core = basic_table_core; + template + using basic_table = basic_table_core; + typedef table_core table; + typedef table_core global_table; + typedef main_table_core main_table; + typedef main_table_core main_global_table; + typedef stack_table_core stack_table; + typedef stack_table_core stack_global_table; + template + struct basic_environment; + using environment = basic_environment; + using main_environment = basic_environment; + using stack_environment = basic_environment; + template + class basic_function; + template + class basic_protected_function; + using unsafe_function = basic_function; + using safe_function = basic_protected_function; + using main_unsafe_function = basic_function; + using main_safe_function = basic_protected_function; + using stack_unsafe_function = basic_function; + using stack_safe_function = basic_protected_function; + using stack_aligned_unsafe_function = basic_function; + using stack_aligned_safe_function = basic_protected_function; + using protected_function = safe_function; + using main_protected_function = main_safe_function; + using stack_protected_function = stack_safe_function; + using stack_aligned_protected_function = stack_aligned_safe_function; +#if defined(SOL_SAFE_FUNCTION) && SOL_SAFE_FUNCTION + using function = protected_function; + using main_function = main_protected_function; + using stack_function = stack_protected_function; +#else + using function = unsafe_function; + using main_function = main_unsafe_function; + using stack_function = stack_unsafe_function; +#endif + using stack_aligned_function = stack_aligned_unsafe_function; + using stack_aligned_stack_handler_function = basic_protected_function; + + struct unsafe_function_result; + struct protected_function_result; + using safe_function_result = protected_function_result; +#if defined(SOL_SAFE_FUNCTION) && SOL_SAFE_FUNCTION + using function_result = safe_function_result; +#else + using function_result = unsafe_function_result; +#endif + + template + class basic_object; + template + class basic_userdata; + template + class basic_lightuserdata; + template + class basic_coroutine; + template + class basic_thread; + + using object = basic_object; + using userdata = basic_userdata; + using lightuserdata = basic_lightuserdata; + using thread = basic_thread; + using coroutine = basic_coroutine; + using main_object = basic_object; + using main_userdata = basic_userdata; + using main_lightuserdata = basic_lightuserdata; + using main_coroutine = basic_coroutine; + using stack_object = basic_object; + using stack_userdata = basic_userdata; + using stack_lightuserdata = basic_lightuserdata; + using stack_thread = basic_thread; + using stack_coroutine = basic_coroutine; + + struct stack_proxy_base; + struct stack_proxy; + struct variadic_args; + struct variadic_results; + struct stack_count; + struct this_state; + struct this_main_state; + struct this_environment; + + template + struct as_table_t; + template + struct as_container_t; + template + struct nested; + template + struct light; + template + struct user; + template + struct as_args_t; + template + struct protect_t; + template + struct filter_wrapper; +} // namespace sol + +// end of sol/forward.hpp + +// beginning of sol/state.hpp + +// beginning of sol/state_view.hpp + +// beginning of sol/error.hpp + +#include +#include + +namespace sol { + namespace detail { + struct direct_error_tag {}; + const auto direct_error = direct_error_tag{}; + } // namespace detail + + class error : public std::runtime_error { + private: + // Because VC++ is upsetting, most of the time! + std::string w; + + public: + error(const std::string& str) + : error(detail::direct_error, "lua: error: " + str) { + } + error(std::string&& str) + : error(detail::direct_error, "lua: error: " + std::move(str)) { + } + error(detail::direct_error_tag, const std::string& str) + : std::runtime_error(""), w(str) { + } + error(detail::direct_error_tag, std::string&& str) + : std::runtime_error(""), w(std::move(str)) { + } + + error(const error& e) = default; + error(error&& e) = default; + error& operator=(const error& e) = default; + error& operator=(error&& e) = default; + + virtual const char* what() const noexcept override { + return w.c_str(); + } + }; + +} // namespace sol + +// end of sol/error.hpp + +// beginning of sol/table.hpp + +// beginning of sol/table_core.hpp + +// beginning of sol/proxy.hpp + +// beginning of sol/traits.hpp + +// beginning of sol/tuple.hpp + +#include +#include + +namespace sol { + namespace detail { + using swallow = std::initializer_list; + } // namespace detail + + template + struct types { + typedef std::make_index_sequence indices; + static constexpr std::size_t size() { + return sizeof...(Args); + } + }; + namespace meta { + namespace detail { + template + struct tuple_types_ { typedef types type; }; + + template + struct tuple_types_> { typedef types type; }; + } // namespace detail + + template + using unqualified = std::remove_cv>; + + template + using unqualified_t = typename unqualified::type; + + template + using tuple_types = typename detail::tuple_types_::type; + + template + struct pop_front_type; + + template + using pop_front_type_t = typename pop_front_type::type; + + template + struct pop_front_type> { + typedef void front_type; + typedef types type; + }; + + template + struct pop_front_type> { + typedef Arg front_type; + typedef types type; + }; + + template + using tuple_element = std::tuple_element>; + + template + using tuple_element_t = std::tuple_element_t>; + + template + using unqualified_tuple_element = unqualified>; + + template + using unqualified_tuple_element_t = unqualified_t>; + + } // namespace meta +} // namespace sol + +// end of sol/tuple.hpp + +// beginning of sol/bind_traits.hpp + +namespace sol { +namespace meta { + namespace meta_detail { + + template + struct check_deducible_signature { + struct nat {}; + template + static auto test(int) -> decltype(&G::operator(), void()); + template + static auto test(...) -> nat; + + using type = std::is_void(0))>; + }; + } // namespace meta_detail + + template + struct has_deducible_signature : meta_detail::check_deducible_signature::type {}; + + namespace meta_detail { + + template + struct void_tuple_element : meta::tuple_element {}; + + template + struct void_tuple_element> { typedef void type; }; + + template + using void_tuple_element_t = typename void_tuple_element::type; + + template + struct basic_traits { + private: + typedef std::conditional_t::value, int, T>& first_type; + + public: + static const bool is_noexcept = it_is_noexcept; + static const bool is_member_function = std::is_void::value; + static const bool has_c_var_arg = has_c_variadic; + static const std::size_t arity = sizeof...(Args); + static const std::size_t free_arity = sizeof...(Args) + static_cast(!std::is_void::value); + typedef types args_list; + typedef std::tuple args_tuple; + typedef T object_type; + typedef R return_type; + typedef tuple_types returns_list; + typedef R(function_type)(Args...); + typedef std::conditional_t::value, args_list, types> free_args_list; + typedef std::conditional_t::value, R(Args...), R(first_type, Args...)> free_function_type; + typedef std::conditional_t::value, R (*)(Args...), R (*)(first_type, Args...)> free_function_pointer_type; + typedef std::remove_pointer_t signature_type; + template + using arg_at = void_tuple_element_t; + }; + + template ::value> + struct fx_traits : basic_traits {}; + + // Free Functions + template + struct fx_traits : basic_traits { + typedef R (*function_pointer_type)(Args...); + }; + + template + struct fx_traits : basic_traits { + typedef R (*function_pointer_type)(Args...); + }; + + template + struct fx_traits : basic_traits { + typedef R (*function_pointer_type)(Args..., ...); + }; + + template + struct fx_traits : basic_traits { + typedef R (*function_pointer_type)(Args..., ...); + }; + + // Member Functions + /* C-Style Variadics */ + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...); + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...); + }; + + /* Const Volatile */ + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) const; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) const; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) const volatile; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) const volatile; + }; + + /* Member Function Qualifiers */ + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) &; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) &; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) const&; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) const&; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) const volatile&; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) const volatile&; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) &&; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) &&; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) const&&; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) const&&; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) const volatile&&; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) const volatile&&; + }; + +#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE + + template + struct fx_traits : basic_traits { + typedef R (*function_pointer_type)(Args...) noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (*function_pointer_type)(Args...) noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (*function_pointer_type)(Args..., ...) noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (*function_pointer_type)(Args..., ...) noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) noexcept; + }; + + /* Const Volatile */ + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) const noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) const noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) const volatile noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) const volatile noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) & noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) & noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) const& noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) const& noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) const volatile& noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) const volatile& noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) && noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) && noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) const&& noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) const&& noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args...) const volatile&& noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R (T::*function_pointer_type)(Args..., ...) const volatile&& noexcept; + }; + +#endif // noexcept is part of a function's type + +#if defined(_MSC_VER) && defined(_M_IX86) + template + struct fx_traits : basic_traits { + typedef R(__stdcall* function_pointer_type)(Args...); + }; + + template + struct fx_traits : basic_traits { + typedef R(__stdcall* function_pointer_type)(Args...); + }; + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...); + }; + + /* Const Volatile */ + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) const; + }; + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile; + }; + + /* Member Function Qualifiers */ + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) &; + }; + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) const&; + }; + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&; + }; + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) &&; + }; + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) const&&; + }; + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&&; + }; + +#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE + + template + struct fx_traits : basic_traits { + typedef R(__stdcall* function_pointer_type)(Args...) noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(__stdcall* function_pointer_type)(Args...) noexcept; + }; + + /* __stdcall cannot be applied to functions with varargs*/ + /*template + struct fx_traits<__stdcall R(Args..., ...) noexcept, false> : basic_traits { + typedef R(__stdcall* function_pointer_type)(Args..., ...) noexcept; + }; + + template + struct fx_traits : basic_traits { + typedef R(__stdcall* function_pointer_type)(Args..., ...) noexcept; + };*/ + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) noexcept; + };*/ + + /* Const Volatile */ + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) const noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const noexcept; + };*/ + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile noexcept; + };*/ + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) & noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) & noexcept; + };*/ + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) const& noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const& noexcept; + };*/ + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile& noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile& noexcept; + };*/ + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) && noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) && noexcept; + };*/ + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) const&& noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const&& noexcept; + };*/ + + template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args...) const volatile&& noexcept; + }; + + /* __stdcall does not work with varargs */ + /*template + struct fx_traits : basic_traits { + typedef R (__stdcall T::*function_pointer_type)(Args..., ...) const volatile&& noexcept; + };*/ +#endif // noexcept is part of a function's type +#endif // __stdcall x86 VC++ bug + + template + struct fx_traits : fx_traits::function_type, false> {}; + + template ::value> + struct callable_traits : fx_traits> { + }; + + template + struct callable_traits { + typedef std::conditional_t::value, std::add_lvalue_reference_t, R> return_type; + typedef return_type Arg; + typedef T object_type; + using signature_type = R(T::*); + static const bool is_noexcept = false; + static const bool is_member_function = false; + static const std::size_t arity = 1; + static const std::size_t free_arity = 2; + typedef std::tuple args_tuple; + typedef types args_list; + typedef types free_args_list; + typedef meta::tuple_types returns_list; + typedef return_type(function_type)(T&, return_type); + typedef return_type(*function_pointer_type)(T&, Arg); + typedef return_type(*free_function_pointer_type)(T&, Arg); + template + using arg_at = void_tuple_element_t; + }; + + } // namespace meta_detail + + template + struct bind_traits : meta_detail::callable_traits {}; + + template + using function_args_t = typename bind_traits::args_list; + + template + using function_signature_t = typename bind_traits::signature_type; + + template + using function_return_t = typename bind_traits::return_type; +} +} // namespace sol::meta + +// end of sol/bind_traits.hpp + +// beginning of sol/string_view.hpp + +#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES +#include +#endif // C++17 features +#include +#if defined(SOL_USE_BOOST) && SOL_USE_BOOST +#include +#endif + +namespace sol { +#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES + template > + using basic_string_view = std::basic_string_view; + typedef std::string_view string_view; + typedef std::wstring_view wstring_view; + typedef std::u16string_view u16string_view; + typedef std::u32string_view u32string_view; + typedef std::hash string_view_hash; +#else + template > + struct basic_string_view { + std::size_t s; + const Char* p; + + basic_string_view(const std::string& r) + : basic_string_view(r.data(), r.size()) { + } + basic_string_view(const Char* ptr) + : basic_string_view(ptr, Traits::length(ptr)) { + } + basic_string_view(const Char* ptr, std::size_t sz) + : s(sz), p(ptr) { + } + + static int compare(const Char* lhs_p, std::size_t lhs_sz, const Char* rhs_p, std::size_t rhs_sz) { + int result = Traits::compare(lhs_p, rhs_p, lhs_sz < rhs_sz ? lhs_sz : rhs_sz); + if (result != 0) + return result; + if (lhs_sz < rhs_sz) + return -1; + if (lhs_sz > rhs_sz) + return 1; + return 0; + } + + const Char* begin() const { + return p; + } + + const Char* end() const { + return p + s; + } + + const Char* cbegin() const { + return p; + } + + const Char* cend() const { + return p + s; + } + + const Char* data() const { + return p; + } + + std::size_t size() const { + return s; + } + + std::size_t length() const { + return size(); + } + + operator std::basic_string() const { + return std::basic_string(data(), size()); + } + + bool operator==(const basic_string_view& r) const { + return compare(p, s, r.data(), r.size()) == 0; + } + + bool operator==(const Char* r) const { + return compare(r, Traits::length(r), p, s) == 0; + } + + bool operator==(const std::basic_string& r) const { + return compare(r.data(), r.size(), p, s) == 0; + } + + bool operator!=(const basic_string_view& r) const { + return !(*this == r); + } + + bool operator!=(const char* r) const { + return !(*this == r); + } + + bool operator!=(const std::basic_string& r) const { + return !(*this == r); + } + }; + + template > + struct basic_string_view_hash { + typedef basic_string_view argument_type; + typedef std::size_t result_type; + + template + result_type operator()(const std::basic_string& r) const { + return (*this)(argument_type(r.c_str(), r.size())); + } + + result_type operator()(const argument_type& r) const { +#if defined(SOL_USE_BOOST) && SOL_USE_BOOST + return boost::hash_range(r.begin(), r.end()); +#else + // Modified, from libstdc++ + // An implementation attempt at Fowler No Voll, 1a. + // Supposedly, used in MSVC, + // GCC (libstdc++) uses MurmurHash of some sort for 64-bit though...? + // But, well. Can't win them all, right? + // This should normally only apply when NOT using boost, + // so this should almost never be tapped into... + std::size_t hash = 0; + const unsigned char* cptr = reinterpret_cast(r.data()); + for (std::size_t sz = r.size(); sz != 0; --sz) { + hash ^= static_cast(*cptr++); + hash *= static_cast(1099511628211ULL); + } + return hash; +#endif + } + }; +} // namespace sol + +namespace std { + template + struct hash< ::sol::basic_string_view > : ::sol::basic_string_view_hash {}; +} // namespace std + +namespace sol { + using string_view = basic_string_view; + using wstring_view = basic_string_view; + using u16string_view = basic_string_view; + using u32string_view = basic_string_view; + using string_view_hash = std::hash; +#endif // C++17 Support +} // namespace sol + +// end of sol/string_view.hpp + +#include +#include +#include +#include +#include + +namespace sol { + template + using index_value = std::integral_constant; + + namespace meta { + template + struct identity { typedef T type; }; + + template + using identity_t = typename identity::type; + + template + struct is_tuple : std::false_type {}; + + template + struct is_tuple> : std::true_type {}; + + template + struct is_builtin_type : std::integral_constant::value || std::is_pointer::value || std::is_array::value> {}; + + template + struct unwrapped { + typedef T type; + }; + + template + struct unwrapped> { + typedef T type; + }; + + template + using unwrapped_t = typename unwrapped::type; + + template + struct unwrap_unqualified : unwrapped> {}; + + template + using unwrap_unqualified_t = typename unwrap_unqualified::type; + + template + struct remove_member_pointer; + + template + struct remove_member_pointer { + typedef R type; + }; + + template + struct remove_member_pointer { + typedef R type; + }; + + template + using remove_member_pointer_t = remove_member_pointer; + + namespace meta_detail { + template class Templ> + struct is_specialization_of : std::false_type {}; + template class Templ> + struct is_specialization_of, Templ> : std::true_type {}; + } + + template class Templ> + using is_specialization_of = meta_detail::is_specialization_of, Templ>; + + template + struct all_same : std::true_type {}; + + template + struct all_same : std::integral_constant::value && all_same::value> {}; + + template + struct any_same : std::false_type {}; + + template + struct any_same : std::integral_constant::value || any_same::value> {}; + + template + using boolean = std::integral_constant; + + template + using invoke_t = typename T::type; + + template + using invoke_b = boolean; + + template + using neg = boolean; + + template + using condition = std::conditional_t; + + template + struct all : boolean {}; + + template + struct all : condition, boolean> {}; + + template + struct any : boolean {}; + + template + struct any : condition, any> {}; + + enum class enable_t { + _ + }; + + constexpr const auto enabler = enable_t::_; + + template + using disable_if_t = std::enable_if_t; + + template + using enable = std::enable_if_t::value, enable_t>; + + template + using disable = std::enable_if_t>::value, enable_t>; + + template + using enable_any = std::enable_if_t::value, enable_t>; + + template + using disable_any = std::enable_if_t>::value, enable_t>; + + template + struct find_in_pack_v : boolean {}; + + template + struct find_in_pack_v : any, find_in_pack_v> {}; + + namespace meta_detail { + template + struct index_in_pack : std::integral_constant {}; + + template + struct index_in_pack : std::conditional_t::value, std::integral_constant, index_in_pack> {}; + } // namespace meta_detail + + template + struct index_in_pack : meta_detail::index_in_pack<0, T, Args...> {}; + + template + struct index_in : meta_detail::index_in_pack<0, T, List> {}; + + template + struct index_in> : meta_detail::index_in_pack<0, T, Args...> {}; + + template + struct at_in_pack {}; + + template + using at_in_pack_t = typename at_in_pack::type; + + template + struct at_in_pack : std::conditional> {}; + + template + struct at_in_pack<0, Arg, Args...> { typedef Arg type; }; + + namespace meta_detail { + template class Pred, typename... Ts> + struct count_for_pack : std::integral_constant {}; + template class Pred, typename T, typename... Ts> + struct count_for_pack : std::conditional_t < sizeof...(Ts) + == 0 + || Limit<2, + std::integral_constant(Limit != 0 && Pred::value)>, + count_for_pack(Pred::value), Pred, Ts...>> {}; + template class Pred, typename... Ts> + struct count_2_for_pack : std::integral_constant {}; + template class Pred, typename T, typename U, typename... Ts> + struct count_2_for_pack : std::conditional_t(Pred::value)>, + count_2_for_pack(Pred::value), Pred, Ts...>> {}; + } // namespace meta_detail + + template