#include <cstdio>
#include <irrlicht/irrlicht.h>

class Main {
public:
  int start(int argc, char *argv[]);

private:
  static void dumpSceneNode(const irr::scene::ISceneNode *const node);
  static void dumpMesh(const irr::scene::IMesh *const mesh);
};

void Main::dumpSceneNode(const irr::scene::ISceneNode *const node) {
  const irr::core::vector3df &p = node->getPosition();
  std::printf("position: %f %f %f\n", p.X, p.Y, p.Z);
  const irr::core::vector3df &r = node->getRotation();
  std::printf("rotation: %f %f %f\n", r.X, r.Y, r.Z);
  const irr::core::vector3df &s = node->getScale();
  std::printf("scale: %f %f %f\n", s.X, s.Y, s.Z);
}

void Main::dumpMesh(const irr::scene::IMesh *const mesh) {
  for (unsigned int i = 0; i < mesh->getMeshBufferCount(); ++i) {
    irr::scene::IMeshBuffer *mb = mesh->getMeshBuffer(i);
    std::printf("mesh:%d  vertex type:%d\n", i, mb->getVertexType());
    irr::video::S3DVertex *v =
        (irr::video::S3DVertex *)mesh->getMeshBuffer(i)->getVertices();
    for (unsigned int j = 0; j < mb->getVertexCount(); ++j) {
      irr::core::vector3df &p = v[j].Pos;
      std::printf("vertex %d: pos (%f %f %f)  color 0x%08x\n", j, p.X, p.Y, p.Z,
                  v[j].Color.color);
    }
  }
}

int Main::start(int argc, char *argv[]) {
  // irrlicht device
  const irr::video::E_DRIVER_TYPE deviceType = irr::video::EDT_OPENGL;
  // const irr::video::E_DRIVER_TYPE deviceType = irr::video::EDT_SOFTWARE;
  irr::IrrlichtDevice *const device =
      irr::createDevice(deviceType, irr::core::dimension2d<irr::u32>(480, 640),
                        16, false, false, false, nullptr);
  if (!device) {
    std::printf("failed to create device\n");
    return 0;
  }

  irr::scene::ISceneManager *const sceneManager = device->getSceneManager();

  // create root node
  irr::scene::ISceneNode *const rootNode = sceneManager->addEmptySceneNode();

  { // add a cube
    irr::scene::IMeshSceneNode *const n = sceneManager->addCubeSceneNode(1.0, rootNode);
    for (float a = 0 ; a < 1000; a++) {
      int x = rand()%3-1;
      int y = rand()%3-1;
      n->setPosition(irr::core::vector3df(x, y, 0));
    }
    // n->setPosition(irr::core::vector3df(0, 0, 0));
    // n->setRotation(irr::core::vector3df(0, 0, 0));
    // n->setScale(irr::core::vector3df(1, 1, 1));
    irr::scene::IMesh *const m = n->getMesh();
    m->setMaterialFlag(irr::video::EMF_LIGHTING, false);
    irr::video::S3DVertex *const v =
        (irr::video::S3DVertex *)m->getMeshBuffer(0)->getVertices();
    for (int i = m->getMeshBuffer(0)->getVertexCount() - 1; i >= 0; --i) {
      v[i].Color = irr::video::SColor(255, (i & 4) * 255 / 4, (i & 2) * 255 / 2,
                                      (i & 1) * 255);
    }

    dumpSceneNode(n);
    dumpMesh(m);
  }
  // camer
  irr::scene::ICameraSceneNode *const camera = sceneManager->addCameraSceneNode(
      rootNode, irr::core::vector3df(0, 0, -10), irr::core::vector3df(0, 0, 0));
  camera->setNearValue(0.1);
  camera->setFarValue(1000);

  irr::video::IVideoDriver *const driver = device->getVideoDriver();

  const irr::video::SColor backColor{255, 100, 101, 140};
  int lastfps = -1;
  while (device->run()) {
    driver->beginScene(true, true, backColor);
    sceneManager->drawAll();
    driver->endScene();

    int fps = driver->getFPS();
    if (lastfps != fps) {
      std::printf("%d\n", fps);
      lastfps = fps;
    }
  }

  device->drop();

  return 0;
}

int main(int argc, char *argv[]) {
  Main main;
  return main.start(argc, argv);
}
