qmlfrontend/engine_instance.cpp
author Wuzzy <Wuzzy2@mail.ru>
Mon, 16 Sep 2019 17:33:49 +0200
changeset 15410 8504fee3b601
parent 15217 b32c52c76977
child 15891 d52f5d8e75e6
permissions -rw-r--r--
Racer: Fix weird water splashes after waypoint placement Does not affect official racer, as only waypoint placement is touched. The reason was that the air attack gear sometimes was not deleted fast enough so it might occassionally drop some air bombs (these are deleted now). Also, the airplane position was set to water level, which caused another water splash.

#include "engine_instance.h"

#include <QDebug>
#include <QLibrary>
#include <QOpenGLFunctions>
#include <QSurface>

static QOpenGLContext* currentOpenglContext = nullptr;
extern "C" void (*getProcAddress(const char* fn))() {
  if (!currentOpenglContext)
    return nullptr;
  else
    return currentOpenglContext->getProcAddress(fn);
}

EngineInstance::EngineInstance(const QString& libraryPath, QObject* parent)
    : QObject(parent) {
  QLibrary hwlib(libraryPath);

  if (!hwlib.load())
    qWarning() << "Engine library not found" << hwlib.errorString();

  hedgewars_engine_protocol_version =
      reinterpret_cast<Engine::hedgewars_engine_protocol_version_t*>(
          hwlib.resolve("hedgewars_engine_protocol_version"));
  start_engine =
      reinterpret_cast<Engine::start_engine_t*>(hwlib.resolve("start_engine"));
  generate_preview = reinterpret_cast<Engine::generate_preview_t*>(
      hwlib.resolve("generate_preview"));
  dispose_preview = reinterpret_cast<Engine::dispose_preview_t*>(
      hwlib.resolve("dispose_preview"));
  cleanup = reinterpret_cast<Engine::cleanup_t*>(hwlib.resolve("cleanup"));

  send_ipc = reinterpret_cast<Engine::send_ipc_t*>(hwlib.resolve("send_ipc"));
  read_ipc = reinterpret_cast<Engine::read_ipc_t*>(hwlib.resolve("read_ipc"));

  setup_current_gl_context =
      reinterpret_cast<Engine::setup_current_gl_context_t*>(
          hwlib.resolve("setup_current_gl_context"));
  render_frame =
      reinterpret_cast<Engine::render_frame_t*>(hwlib.resolve("render_frame"));
  advance_simulation = reinterpret_cast<Engine::advance_simulation_t*>(
      hwlib.resolve("advance_simulation"));
  move_camera =
      reinterpret_cast<Engine::move_camera_t*>(hwlib.resolve("move_camera"));
  simple_event =
      reinterpret_cast<Engine::simple_event_t*>(hwlib.resolve("simple_event"));
  long_event =
      reinterpret_cast<Engine::long_event_t*>(hwlib.resolve("long_event"));
  positioned_event = reinterpret_cast<Engine::positioned_event_t*>(
      hwlib.resolve("positioned_event"));

  m_isValid = hedgewars_engine_protocol_version && start_engine &&
              generate_preview && dispose_preview && cleanup && send_ipc &&
              read_ipc && setup_current_gl_context && render_frame &&
              advance_simulation && move_camera && simple_event && long_event &&
              positioned_event;

  emit isValidChanged(m_isValid);

  if (isValid()) {
    qDebug() << "Loaded engine library with protocol version"
             << hedgewars_engine_protocol_version();

    m_instance = start_engine();
  } else {
    qDebug("Engine library load failed");
  }
}

EngineInstance::~EngineInstance() {
  if (m_isValid) cleanup(m_instance);
}

void EngineInstance::sendConfig(const GameConfig& config) {
  for (auto b : config.config()) {
    send_ipc(m_instance, reinterpret_cast<uint8_t*>(b.data()),
             static_cast<size_t>(b.size()));
  }
}

void EngineInstance::advance(quint32 ticks) {
  advance_simulation(m_instance, ticks);
}

void EngineInstance::moveCamera(const QPoint& delta) {
  move_camera(m_instance, delta.x(), delta.y());
}

void EngineInstance::simpleEvent(Engine::SimpleEventType event_type) {
  simple_event(m_instance, event_type);
}

void EngineInstance::longEvent(Engine::LongEventType event_type,
                               Engine::LongEventState state) {
  long_event(m_instance, event_type, state);
}

void EngineInstance::positionedEvent(Engine::PositionedEventType event_type,
                                     qint32 x, qint32 y) {
  positioned_event(m_instance, event_type, x, y);
}

void EngineInstance::renderFrame() { render_frame(m_instance); }

void EngineInstance::setOpenGLContext(QOpenGLContext* context) {
  currentOpenglContext = context;

  auto size = context->surface()->size();
  setup_current_gl_context(m_instance, static_cast<quint16>(size.width()),
                           static_cast<quint16>(size.height()),
                           &getProcAddress);
}

QImage EngineInstance::generatePreview() {
  Engine::PreviewInfo pinfo;

  generate_preview(m_instance, &pinfo);

  QVector<QRgb> colorTable;
  colorTable.resize(256);
  for (int i = 0; i < 256; ++i) colorTable[i] = qRgba(255, 255, 0, i);

  QImage previewImage(pinfo.land, static_cast<int>(pinfo.width),
                      static_cast<int>(pinfo.height), QImage::Format_Indexed8);
  previewImage.setColorTable(colorTable);

  // Cannot use it here, since QImage refers to original bytes
  // dispose_preview(m_instance);

  return previewImage;
}

bool EngineInstance::isValid() const { return m_isValid; }