#pragma once

#include <tms/cpp.hh>

enum {
    MODEL_PLANK1,
    MODEL_PLANK2,
    MODEL_PLANK3,
    MODEL_PLANK4,
    MODEL_THINPLANK1,
    MODEL_THINPLANK2,
    MODEL_THINPLANK3,
    MODEL_THINPLANK4,
    MODEL_SPLANK0,
    MODEL_SPLANK1,
    MODEL_SPLANK2,
    MODEL_SPLANK3,
    MODEL_SPLANK_FRONT,
    MODEL_SPLANK_BACK,
    MODEL_IMPACT0,
    MODEL_IMPACT1,
    MODEL_IMPACT2,
    MODEL_IMPACT3,
    MODEL_FIELD0,
    MODEL_FIELD1,
    MODEL_FIELD2,
    MODEL_FIELD3,
    MODEL_ROOM_BG,
    MODEL_ROOM0,
    MODEL_ROOM1,
    MODEL_ROOM2,
    MODEL_ROOM3,
    MODEL_ARM_SHOTGUN,
    MODEL_ARM_BOMBER,
    MODEL_ARM_BOMBER_CHAMBER,
    MODEL_ARM_RAILGUN,
    MODEL_DIAMOND,
    MODEL_RUBY,
    MODEL_STONE,
    MODEL_WEIGHT,
    MODEL_SEPARATOR,
    MODEL_ROBOT,
    MODEL_ROBOT_GUNARM,
    MODEL_ROBOT_DRAGARM,
    MODEL_ROBOT_HEAD,
    MODEL_ROBOT_BODY,
    MODEL_ROBOT_BACK,
    MODEL_ROBOT_FRONT,
    MODEL_FEET_FRAME,
    MODEL_BOT,
    MODEL_SPIKEBOT,
    MODEL_MINIBOT,
    MODEL_BOMBER,
    MODEL_SPHERE,
    MODEL_SPHERE2,
    MODEL_SPHERE3,
    MODEL_GENERATOR,
    MODEL_BATTERY3V,
    MODEL_WMOTOR,
    MODEL_FLATMOTOR,
    MODEL_SIMPLEMOTOR,
    MODEL_GEAR0,
    MODEL_GEAR1,
    MODEL_GEAR2,
    MODEL_GEAR3,
    MODEL_TRAMPOLINE_BASE,
    MODEL_TRAMPOLINE_PAD,
    MODEL_PLUG_SIMPLE,
    MODEL_PLUG_SIMPLE_LOW,
    MODEL_PLUG_MALE,
    MODEL_PLUG_FEMALE,
    MODEL_PLUG_TRANSMITTER,
    MODEL_IFPLUG_MALE,
    MODEL_IFPLUG_FEMALE,
    MODEL_SCRIPT,
    MODEL_STICKY,
    MODEL_BREADBOARD,
    MODEL_DMOTOR,
    MODEL_WHEEL,
    MODEL_CUP,
    MODEL_CYLINDER05,
    MODEL_CYLINDER1,
    MODEL_CYLINDER15,
    MODEL_CYLINDER2,
    MODEL_WALLTHING00,
    MODEL_WALLTHING0,
    MODEL_WALLTHING1,
    MODEL_WALLTHING2,
    MODEL_WELDJOINT,
    MODEL_PLATEJOINT,
    MODEL_PLATEJOINT_DAMAGED,
    MODEL_PIVOTJOINT,
    MODEL_CORNER,
    MODEL_PANEL_BIG,
    MODEL_PANEL_MEDIUM,
    MODEL_PANEL_SMALL,
    MODEL_SWITCHER,
    MODEL_ROBOTMAN,
    MODEL_MAGNET,
    MODEL_RAILSTRAIGHT,
    MODEL_RAILTURN,
    MODEL_RAILSKEWED,
    MODEL_RAILSKEWED2,
    MODEL_GYROSCOPE,
    MODEL_TILTMETER,
    MODEL_LMOTOR0,
    MODEL_LMOTOR1,
    MODEL_LMOTOR2,
    MODEL_LMOTOR3,
    MODEL_LMOTOR0_R,
    MODEL_LMOTOR1_R,
    MODEL_LMOTOR2_R,
    MODEL_LMOTOR3_R,
    MODEL_MAGPLUG,
    MODEL_MAGSOCK,
    MODEL_FIFO,
    MODEL_SEESAW,
    MODEL_PIVOT,
    MODEL_ANCHOR,
    MODEL_LIMB,
    MODEL_BULLET,
    MODEL_MISSILE,
    MODEL_ROPEEND,
    MODEL_PIPELINE,
    MODEL_PIPELINE_PISTON,
    MODEL_PIPELINE_HOUSE,
    MODEL_CLIP,
    MODEL_CCLIP,
    MODEL_LANDMINE,
    MODEL_GEARBOX,
    MODEL_BOX_NOTEX,
    MODEL_BOX_TEX,
    MODEL_TRIBOX_TEX0,
    MODEL_TRIBOX_TEX1,
    MODEL_TRIBOX_TEX2,
    MODEL_TRIBOX_TEX3,
    MODEL_GB_AXLE,
    MODEL_GB0,
    MODEL_GB1,
    MODEL_GB2,
    MODEL_GB3,
    MODEL_GB4,
    MODEL_CTRLMINI,
    MODEL_CTRLPASS,
    MODEL_CTRLSERVO,
    MODEL_CTRLFPLUS,
    MODEL_DAMPER_0,
    MODEL_DAMPER_1,
    MODEL_DISPLAY,
    MODEL_DISPLAY_ACTIVE,
    MODEL_CRANE,
    MODEL_BORDER,
    MODEL_SCANNER,
    MODEL_MIRROR,
    MODEL_LASERSENSOR,
    MODEL_ROCKET,
    MODEL_THRUSTER,
    MODEL_BOMB,
    MODEL_PLASMA_GUN_INNER,
    MODEL_PLASMA_GUN,
    MODEL_TESLA_GUN,
    MODEL_MEGA_BUSTER,
    MODEL_ROCKET_LAUNCHER,
    MODEL_BUTTON,
    MODEL_BUTTON_SWITCH,
    MODEL_PROXIMITY,
    MODEL_GAMEMAN,
    MODEL_DEBRIS,
    MODEL_BOX0,
    MODEL_BOX1,
    MODEL_DEBUGGER0,
    MODEL_DEBUGGER1,
    MODEL_GRAPHER,
    MODEL_STABILIZER,
    MODEL_FACTORY_GENERIC,
    MODEL_FACTORY_ROBOT,
    MODEL_FACTORY_ARMORY,
    MODEL_FACTORY_OIL_MIXER,
    MODEL_REPAIR_STATION,
    MODEL_LADDER,
    MODEL_JETPACK,
    MODEL_ADVANCED_JETPACK,
    MODEL_PIG,
    MODEL_COW,
    MODEL_COW_HEAD,
    MODEL_PIG_HEAD,
    MODEL_LEAVES0,
    MODEL_EMITTER,
    MODEL_EMITTER_FRAME,
    MODEL_MINIEMITTER,
    MODEL_RUBBEREND,
    MODEL_I0O1,
    MODEL_I0O2,
    MODEL_I0O3,
    MODEL_I1O0,
    MODEL_I1O2,
    MODEL_I1O3,
    MODEL_I1O4,
    MODEL_I1O8,
    MODEL_I2O0,
    MODEL_I2O2,
    MODEL_I3O1,
    MODEL_I4O0,
    MODEL_I4O1,
    MODEL_POINTER_BODY,
    MODEL_POINTER_ARROW,
    MODEL_DRAGFIELD,
    MODEL_GRAVITYMAN,
    MODEL_GRAVITYSET,
    MODEL_SPIKES,
    MODEL_BACKPACK,
    MODEL_ADAMPER,
    MODEL_CHECKPOINT,
    MODEL_FAN,
    MODEL_FAN_BLADES,
    MODEL_TRANSMITTER,
    MODEL_BARREL,
    MODEL_HAT,
    MODEL_WIZARDHAT,
    MODEL_NINJAHELMET,
    MODEL_ROBE,
    MODEL_SUCTIONCUP,
    MODEL_CANISTER,
    MODEL_OILRIG,
    MODEL_CONVEYOR0,
    MODEL_CONVEYOR1,
    MODEL_CONVEYOR2,
    MODEL_CONVEYOR3,
    MODEL_CONVEYOR4,
    MODEL_CONVEYOR5,
    MODEL_ROBOT_HEAD_INSIDE,
    MODEL_CONICALHAT,
    MODEL_OSTRICH,
    MODEL_OSTRICH_HEAD,
    MODEL_POLICEHAT,
    MODEL_CIRCUIT,
    MODEL_OILBARREL,
    MODEL_CANISTER_ARMOUR,
    MODEL_CANISTER_SPEED,
    MODEL_CANISTER_JUMP,
    MODEL_ORE,
    MODEL_ORE_INSIDE,
    MODEL_ORE2,
    MODEL_ORE2_INSIDE,
    MODEL_VENDOR,
    MODEL_TREASURE_CHEST,
    MODEL_BUILDER,
    MODEL_MINER,
    MODEL_FACTIONWAND,
    MODEL_BOLTSET_STEEL,
    MODEL_BOLTSET_WOOD,
    MODEL_BOLTSET_TITANIUM,
    MODEL_BOLTSET_DIAMOND,
    MODEL_LOBBER,
    MODEL_SPIKEBALL,
    MODEL_GUARDPOINT,
    MODEL_STONE1,
    MODEL_STONE2,
    MODEL_STONE3,
    MODEL_STONE4,
    MODEL_STONE5,
    MODEL_STONE6,
    MODEL_MUSHROOM1,
    MODEL_MUSHROOM2,
    MODEL_MUSHROOM3,
    MODEL_MUSHROOM4,
    MODEL_MUSHROOM5,
    MODEL_MUSHROOM6,
    MODEL_LEAVES2,
    MODEL_LEAVES3,
    MODEL_SIGN1,
    MODEL_SIGN2,
    MODEL_SIGN3,
    MODEL_SIGN4,
    MODEL_WOOD,
    MODEL_FENCE_WOOD,
    MODEL_TOPHAT,
    MODEL_COMPRESSOR,
    MODEL_COMPRESSOR_LAMP1,
    MODEL_COMPRESSOR_LAMP2,
    MODEL_COMPRESSOR_LAMP3,
    MODEL_COMPRESSOR_LAMP4,
    MODEL_LADDER_STEP,
    MODEL_KINGSCROWN,
    MODEL_DUMMY_HEAD,
    MODEL_STATUE_HEAD,
    MODEL_JESTERHAT,
    MODEL_WOODSWORD,
    MODEL_HAMMER,
    MODEL_WITCH_HAT,
    MODEL_SIMPLE_AXE,
    MODEL_SAW1,
    MODEL_SAW,
    MODEL_SAW_BLADE,
    MODEL_SPIKED_CLUB,
    MODEL_STEEL_SWORD,
    MODEL_BASEBALLBAT,
    MODEL_SPEAR,
    MODEL_PLANT1,
    MODEL_PLANT2,
    MODEL_PLANT3,
    MODEL_PLANT4,
    MODEL_WAR_AXE,
    MODEL_PIXEL_SWORD,
    MODEL_HARD_HAT,
    MODEL_SERPENT_SWORD,
    MODEL_PIONEER_FRONT,
    MODEL_PIONEER_BACK,
    MODEL_VIKING_HELMET,
    MODEL_PICKAXE,

    MODEL_I1O1_EMPTY,
    MODEL_I1O1_INTEGER,
    MODEL_I1O1_SQUARE,
    MODEL_I1O1_SQRT,
    MODEL_I1O1_SPARSIFY,
    MODEL_I1O1_BESSERWISSER,
    MODEL_I1O1_EPSILON,
    MODEL_I1O1_INVERT,

    MODEL_I2O1_EMPTY,
    MODEL_I2O1_AND,
    MODEL_I2O1_OR,
    MODEL_I2O1_XOR,
    MODEL_I2O1_NAND,
    MODEL_I2O1_EQUAL,
    MODEL_I2O1_LESS,
    MODEL_I2O1_LESS_EQUAL,
    MODEL_I2O1_SUM,
    MODEL_I2O1_WRAP_ADD,
    MODEL_I2O1_WRAP_SUB,
    MODEL_I2O1_UNUSED,

    MODEL_CPAD,
    MODEL_CPAD_1,
    MODEL_CPAD_2,
    MODEL_CPAD_3,
    MODEL_CPAD_4,
    MODEL_CPAD_5,
    MODEL_CPAD_6,
    MODEL_CPAD_7,
    MODEL_CPAD_8,
    MODEL_CPAD_9,
    MODEL_CPAD_10,
    MODEL_CPAD_11,
    MODEL_CPAD_12,
    MODEL_CPAD_13,
    MODEL_CPAD_14,
    MODEL_CPAD_15,
    MODEL_CPAD_16,

    NUM_MODELS
};

struct model_load_data {
    const char *path;
    int base_id;
    tvec2 offset;
    struct tms_mesh *mesh;
    struct tms_model *model;
};

class lvlbuf;

class mesh_factory {
  private:
    static char cache_path[512];
    static bool use_cache;
    static bool open_cache(lvlbuf *lb);
    static bool read_cache(lvlbuf *lb);
    static bool write_cache(lvlbuf *lb);
    static bool save_cache(lvlbuf *lb);

  public:
    static struct model_load_data models[NUM_MODELS];
    static int cur_mesh;

    static inline struct tms_mesh *get_mesh(int model) {
        return mesh_factory::models[model].mesh;
    }

    /// Initialise models, loading cached model data if it exists
    static void init_models();

    /// Load the next model, return false if there are no more models to load
    static bool load_next();

    /// Upload all loaded models to the GPU
    static void upload_models();
};
