|
1 #include "engine_instance.h" |
|
2 |
|
3 #include <QDebug> |
|
4 #include <QLibrary> |
|
5 #include <QOpenGLFunctions> |
|
6 #include <QSurface> |
|
7 |
|
8 static QOpenGLContext* currentOpenglContext = nullptr; |
|
9 extern "C" void (*getProcAddress(const char* fn))() { |
|
10 if (!currentOpenglContext) |
|
11 return nullptr; |
|
12 else |
|
13 return currentOpenglContext->getProcAddress(fn); |
|
14 } |
|
15 |
|
16 EngineInstance::EngineInstance(const QString& libraryPath, QObject* parent) |
|
17 : QObject(parent) { |
|
18 QLibrary hwlib(libraryPath); |
|
19 |
|
20 if (!hwlib.load()) |
|
21 qWarning() << "Engine library not found" << hwlib.errorString(); |
|
22 |
|
23 hedgewars_engine_protocol_version = |
|
24 reinterpret_cast<Engine::hedgewars_engine_protocol_version_t*>( |
|
25 hwlib.resolve("hedgewars_engine_protocol_version")); |
|
26 start_engine = |
|
27 reinterpret_cast<Engine::start_engine_t*>(hwlib.resolve("start_engine")); |
|
28 generate_preview = reinterpret_cast<Engine::generate_preview_t*>( |
|
29 hwlib.resolve("generate_preview")); |
|
30 dispose_preview = reinterpret_cast<Engine::dispose_preview_t*>( |
|
31 hwlib.resolve("dispose_preview")); |
|
32 cleanup = reinterpret_cast<Engine::cleanup_t*>(hwlib.resolve("cleanup")); |
|
33 |
|
34 send_ipc = reinterpret_cast<Engine::send_ipc_t*>(hwlib.resolve("send_ipc")); |
|
35 read_ipc = reinterpret_cast<Engine::read_ipc_t*>(hwlib.resolve("read_ipc")); |
|
36 |
|
37 setup_current_gl_context = |
|
38 reinterpret_cast<Engine::setup_current_gl_context_t*>( |
|
39 hwlib.resolve("setup_current_gl_context")); |
|
40 render_frame = |
|
41 reinterpret_cast<Engine::render_frame_t*>(hwlib.resolve("render_frame")); |
|
42 advance_simulation = reinterpret_cast<Engine::advance_simulation_t*>( |
|
43 hwlib.resolve("advance_simulation")); |
|
44 move_camera = |
|
45 reinterpret_cast<Engine::move_camera_t*>(hwlib.resolve("move_camera")); |
|
46 simple_event = |
|
47 reinterpret_cast<Engine::simple_event_t*>(hwlib.resolve("simple_event")); |
|
48 long_event = |
|
49 reinterpret_cast<Engine::long_event_t*>(hwlib.resolve("long_event")); |
|
50 positioned_event = reinterpret_cast<Engine::positioned_event_t*>( |
|
51 hwlib.resolve("positioned_event")); |
|
52 |
|
53 m_isValid = hedgewars_engine_protocol_version && start_engine && |
|
54 generate_preview && dispose_preview && cleanup && send_ipc && |
|
55 read_ipc && setup_current_gl_context && render_frame && |
|
56 advance_simulation && move_camera && simple_event && long_event && |
|
57 positioned_event; |
|
58 |
|
59 emit isValidChanged(m_isValid); |
|
60 |
|
61 if (isValid()) { |
|
62 qDebug() << "Loaded engine library with protocol version" |
|
63 << hedgewars_engine_protocol_version(); |
|
64 |
|
65 m_instance = start_engine(); |
|
66 } else { |
|
67 qDebug("Engine library load failed"); |
|
68 } |
|
69 } |
|
70 |
|
71 EngineInstance::~EngineInstance() { |
|
72 if (m_isValid) cleanup(m_instance); |
|
73 } |
|
74 |
|
75 void EngineInstance::sendConfig(const GameConfig& config) { |
|
76 for (auto b : config.config()) { |
|
77 send_ipc(m_instance, reinterpret_cast<uint8_t*>(b.data()), |
|
78 static_cast<size_t>(b.size())); |
|
79 } |
|
80 } |
|
81 |
|
82 void EngineInstance::advance(quint32 ticks) { |
|
83 advance_simulation(m_instance, ticks); |
|
84 } |
|
85 |
|
86 void EngineInstance::moveCamera(const QPoint& delta) { |
|
87 move_camera(m_instance, delta.x(), delta.y()); |
|
88 } |
|
89 |
|
90 void EngineInstance::simpleEvent(Engine::SimpleEventType event_type) { |
|
91 simple_event(m_instance, event_type); |
|
92 } |
|
93 |
|
94 void EngineInstance::longEvent(Engine::LongEventType event_type, |
|
95 Engine::LongEventState state) { |
|
96 long_event(m_instance, event_type, state); |
|
97 } |
|
98 |
|
99 void EngineInstance::positionedEvent(Engine::PositionedEventType event_type, |
|
100 qint32 x, qint32 y) { |
|
101 positioned_event(m_instance, event_type, x, y); |
|
102 } |
|
103 |
|
104 void EngineInstance::renderFrame() { render_frame(m_instance); } |
|
105 |
|
106 void EngineInstance::setOpenGLContext(QOpenGLContext* context) { |
|
107 currentOpenglContext = context; |
|
108 |
|
109 auto size = context->surface()->size(); |
|
110 setup_current_gl_context(m_instance, static_cast<quint16>(size.width()), |
|
111 static_cast<quint16>(size.height()), |
|
112 &getProcAddress); |
|
113 } |
|
114 |
|
115 QImage EngineInstance::generatePreview() { |
|
116 Engine::PreviewInfo pinfo; |
|
117 |
|
118 generate_preview(m_instance, &pinfo); |
|
119 |
|
120 QVector<QRgb> colorTable; |
|
121 colorTable.resize(256); |
|
122 for (int i = 0; i < 256; ++i) colorTable[i] = qRgba(255, 255, 0, i); |
|
123 |
|
124 QImage previewImage(pinfo.land, static_cast<int>(pinfo.width), |
|
125 static_cast<int>(pinfo.height), QImage::Format_Indexed8); |
|
126 previewImage.setColorTable(colorTable); |
|
127 |
|
128 // Cannot use it here, since QImage refers to original bytes |
|
129 // dispose_preview(m_instance); |
|
130 |
|
131 return previewImage; |
|
132 } |
|
133 |
|
134 bool EngineInstance::isValid() const { return m_isValid; } |