feat(framework/examples): add doom example
This commit is contained in:
parent
fcb686ac0c
commit
d515d522a5
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[submodule "example/ultimate-artblock/3rdparty/libdoom"]
|
||||||
|
path = example/ultimate-artblock/3rdparty/libdoom
|
||||||
|
url = https://git.tablet.sh/tablet/libdoom
|
||||||
|
branch = master
|
||||||
@ -36,4 +36,5 @@ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
|
|||||||
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Gui Core5Compat Xml QUIET)
|
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Gui Core5Compat Xml QUIET)
|
||||||
|
|
||||||
add_subdirectory(simple)
|
add_subdirectory(simple)
|
||||||
|
add_subdirectory(ultimate-artblock)
|
||||||
add_subdirectory(_all)
|
add_subdirectory(_all)
|
||||||
@ -21,4 +21,5 @@ set_target_properties(all-examples PROPERTIES
|
|||||||
AUTORCC ON
|
AUTORCC ON
|
||||||
)
|
)
|
||||||
target_link_libraries(all-examples PUBLIC libtoonboom_static)
|
target_link_libraries(all-examples PUBLIC libtoonboom_static)
|
||||||
|
target_link_libraries(all-examples PRIVATE doom-example)
|
||||||
target_link_libraries(all-examples PRIVATE simple-example)
|
target_link_libraries(all-examples PRIVATE simple-example)
|
||||||
32
example/_all/include/defs/doom.hpp
Normal file
32
example/_all/include/defs/doom.hpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "./base.hpp"
|
||||||
|
#include <doom_view.hpp>
|
||||||
|
|
||||||
|
class DoomExample : public BaseExample {
|
||||||
|
public:
|
||||||
|
DoomExample() : BaseExample() {
|
||||||
|
}
|
||||||
|
~DoomExample() {}
|
||||||
|
|
||||||
|
std::function<QScriptValue(QScriptContext *, QScriptEngine *)>
|
||||||
|
run() override {
|
||||||
|
return
|
||||||
|
[this](QScriptContext *context, QScriptEngine *engine) -> QScriptValue {
|
||||||
|
auto lm = PLUG_Services::getLayoutManager();
|
||||||
|
if(doomView == nullptr) {
|
||||||
|
doomView = new DoomView();
|
||||||
|
lm->addArea("DoomView", doomView->displayName(), doomView, true, true, false, QSize(320, 200), true, false, true, true);
|
||||||
|
}
|
||||||
|
lm->raiseArea("DoomView", nullptr, true, QPoint(2020, 100));
|
||||||
|
auto widget =
|
||||||
|
dynamic_cast<ToonDoomWidget *>(doomView->getWidget());
|
||||||
|
widget->start();
|
||||||
|
return engine->undefinedValue();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
QString jsName() override { return "runDoom"; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
DoomView *doomView = nullptr;
|
||||||
|
};
|
||||||
@ -7,12 +7,14 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include "./defs/base.hpp"
|
#include "./defs/base.hpp"
|
||||||
#include "./defs/simple.hpp"
|
#include "./defs/simple.hpp"
|
||||||
|
#include "./defs/doom.hpp"
|
||||||
|
|
||||||
class ToonBoomExamples {
|
class ToonBoomExamples {
|
||||||
public:
|
public:
|
||||||
ToonBoomExamples() {
|
ToonBoomExamples() {
|
||||||
addExample(new SimpleExample());
|
addExample(new SimpleExample());
|
||||||
addExample(new ToolbarExample());
|
addExample(new ToolbarExample());
|
||||||
|
addExample(new DoomExample());
|
||||||
}
|
}
|
||||||
void addExample(BaseExample *example) { examples.push_back(example); }
|
void addExample(BaseExample *example) { examples.push_back(example); }
|
||||||
QScriptValue getExamples(QScriptEngine *engine) {
|
QScriptValue getExamples(QScriptEngine *engine) {
|
||||||
|
|||||||
1
example/ultimate-artblock/3rdparty/libdoom
vendored
Submodule
1
example/ultimate-artblock/3rdparty/libdoom
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 6e975919c8c04f299aec7b06409f7f2222c5b2b7
|
||||||
37
example/ultimate-artblock/CMakeLists.txt
Normal file
37
example/ultimate-artblock/CMakeLists.txt
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# include(../common.cmake)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE DOOM_EXAMPLE_HEADERS CONFIGURE_DEPENDS
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/include/*.hpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE DOOM_EXAMPLE_SOURCES CONFIGURE_DEPENDS
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cc"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cxx"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
list(FILTER DOOM_EXAMPLE_SOURCES EXCLUDE REGEX "/(out|build|cmake-build-|CMakeFiles|doom_proxy)/")
|
||||||
|
list(FILTER DOOM_EXAMPLE_HEADERS EXCLUDE REGEX "/(out|build|cmake-build-|CMakeFiles|doom_proxy)/")
|
||||||
|
message(STATUS "DOOM_EXAMPLE_SOURCES: ${DOOM_EXAMPLE_SOURCES}")
|
||||||
|
# add_library(libdoom OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/libdoom/doom.c" )
|
||||||
|
|
||||||
|
add_library(libdoom OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/src/doom_proxy.c")
|
||||||
|
set_target_properties(libdoom PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
|
target_compile_definitions(libdoom PUBLIC "APP_WINDOWS" "__BYTEBOOL__=1" "ALLOW_MOUSE=0")
|
||||||
|
target_include_directories(libdoom PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/libdoom/linuxdoom-1.10)
|
||||||
|
target_include_directories(libdoom PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/libdoom/libs_win32)
|
||||||
|
target_compile_options(libdoom PUBLIC "/Zc:gotoScope-" "/Zc:strictStrings-" "/wd4244" "/wd4267" "/wd4838" "/wd4430" "/wd4996" "/wd4311" "/wd4113" "/showIncludes")
|
||||||
|
|
||||||
|
add_library(doom-example STATIC ${DOOM_EXAMPLE_SOURCES} ${DOOM_EXAMPLE_HEADERS} $<TARGET_OBJECTS:libdoom>)
|
||||||
|
target_compile_definitions(doom-example PRIVATE "APP_WINDOWS" "__BYTEBOOL__=1")
|
||||||
|
target_compile_options(doom-example PUBLIC "/std:c++20" "/Zc:gotoScope-" "/showIncludes")
|
||||||
|
target_include_directories(doom-example PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/include)
|
||||||
|
target_include_directories(doom-example PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/libdoom/libs_win32)
|
||||||
|
target_include_directories(doom-example PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/libdoom/linuxdoom-1.10)
|
||||||
|
target_link_libraries(doom-example PRIVATE libtoonboom_static)
|
||||||
|
set_target_properties(doom-example PROPERTIES
|
||||||
|
AUTOMOC ON
|
||||||
|
AUTOUIC ON
|
||||||
|
AUTORCC ON
|
||||||
|
)
|
||||||
189
example/ultimate-artblock/src/doom_proxy.c
Normal file
189
example/ultimate-artblock/src/doom_proxy.c
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
// typedef enum {false, true} boolean;
|
||||||
|
#define false 0
|
||||||
|
#define true 1
|
||||||
|
typedef unsigned char byte;
|
||||||
|
#endif
|
||||||
|
#define MY_APP_FATAL_ERROR(ctx, message) { printf( "FATAL ERROR: %s\n", message ); MessageBoxA( 0, message, "Fatal Error!", MB_OK | MB_ICONSTOP ); _flushall(); }
|
||||||
|
|
||||||
|
#define APP_LOG(ctx, level, message) printf( "%s\n", message )
|
||||||
|
// #include <app.h>
|
||||||
|
// #undef APP_IMPLEMENTATION
|
||||||
|
#define APP_IMPLEMENTATION
|
||||||
|
#include <app.h>
|
||||||
|
#undef APP_IMPLEMENTATION
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define strcasecmp stricmp
|
||||||
|
#define strncasecmp strnicmp
|
||||||
|
#else
|
||||||
|
#include <strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CONCAT_IMPL( x, y ) x##y
|
||||||
|
#define CONCAT( x, y ) CONCAT_IMPL( x, y )
|
||||||
|
#define rcsid CONCAT( rcsid, __COUNTER__ )
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
int doom_access( char const* _FileName, int _AccessMode ) {
|
||||||
|
FILE* f = fopen( _FileName, "rb" );
|
||||||
|
if( f ) {
|
||||||
|
fclose(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <unistd.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef access
|
||||||
|
#define access doom_access
|
||||||
|
|
||||||
|
#define open doom_open
|
||||||
|
#define close doom_close
|
||||||
|
|
||||||
|
#undef LoadMenu
|
||||||
|
#include <am_map.c>
|
||||||
|
#include <doomdef.c>
|
||||||
|
#include <doomstat.c>
|
||||||
|
#include <dstrings.c>
|
||||||
|
#include <d_items.c>
|
||||||
|
#include <d_main.c>
|
||||||
|
#include <d_net.c>
|
||||||
|
#include <f_finale.c>
|
||||||
|
#include <f_wipe.c>
|
||||||
|
#include <g_game.c>
|
||||||
|
#include <hu_lib.c>
|
||||||
|
#include <hu_stuff.c>
|
||||||
|
#include <info.c>
|
||||||
|
#include <m_argv.c>
|
||||||
|
#include <m_bbox.c>
|
||||||
|
#include <m_cheat.c>
|
||||||
|
#include <m_fixed.c>
|
||||||
|
#include <m_random.c>
|
||||||
|
#include <m_swap.c>
|
||||||
|
#include <p_ceilng.c>
|
||||||
|
#include <p_doors.c>
|
||||||
|
#include <p_enemy.c>
|
||||||
|
#include <p_floor.c>
|
||||||
|
#include <p_inter.c>
|
||||||
|
#include <p_lights.c>
|
||||||
|
#include <p_map.c>
|
||||||
|
#include <p_maputl.c>
|
||||||
|
#include <p_mobj.c>
|
||||||
|
#include <p_plats.c>
|
||||||
|
#include <p_pspr.c>
|
||||||
|
#include <p_saveg.c>
|
||||||
|
#include <p_setup.c>
|
||||||
|
#include <p_sight.c>
|
||||||
|
#include <p_spec.c>
|
||||||
|
#include <p_switch.c>
|
||||||
|
#include <p_telept.c>
|
||||||
|
#include <p_tick.c>
|
||||||
|
#include <p_user.c>
|
||||||
|
#include <r_bsp.c>
|
||||||
|
#include <r_data.c>
|
||||||
|
#include <r_draw.c>
|
||||||
|
#include <r_main.c>
|
||||||
|
#include <r_plane.c>
|
||||||
|
#include <r_segs.c>
|
||||||
|
#include <r_sky.c>
|
||||||
|
#include <r_things.c>
|
||||||
|
#include <sounds.c>
|
||||||
|
#undef BG
|
||||||
|
#include <st_lib.c>
|
||||||
|
#include <st_stuff.c>
|
||||||
|
#define channels xchannels
|
||||||
|
#include <s_sound.c>
|
||||||
|
#undef channels
|
||||||
|
#include <tables.c>
|
||||||
|
#include <v_video.c>
|
||||||
|
#define anim_t wi_anim_t
|
||||||
|
#define anims wi_anims
|
||||||
|
#define time wi_time
|
||||||
|
#include <wi_stuff.c>
|
||||||
|
#undef anims
|
||||||
|
#undef anim_t
|
||||||
|
#undef time
|
||||||
|
#include <z_zone.c>
|
||||||
|
|
||||||
|
#undef open
|
||||||
|
#undef close
|
||||||
|
|
||||||
|
#include <m_menu.c>
|
||||||
|
#include <m_misc.c>
|
||||||
|
#define strupr xstrupr
|
||||||
|
#include <w_wad.c>
|
||||||
|
#undef strupr
|
||||||
|
|
||||||
|
#include <i_net.c>
|
||||||
|
|
||||||
|
#undef MAXCHAR
|
||||||
|
#undef MAXSHORT
|
||||||
|
#undef MAXINT
|
||||||
|
#undef MAXLONG
|
||||||
|
#undef MINCHAR
|
||||||
|
#undef MINSHORT
|
||||||
|
#undef MININT
|
||||||
|
#undef MINLONG
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <time.h>
|
||||||
|
#ifdef __wasm__
|
||||||
|
#define APP_WASM
|
||||||
|
#define WA_CORO_IMPLEMENT_NANOSLEEP
|
||||||
|
#else
|
||||||
|
#define APP_WINDOWS
|
||||||
|
#endif
|
||||||
|
#define boolean HACK_TO_MAKE_BOOLEAN_NOT_BE_DEFINED
|
||||||
|
|
||||||
|
#define FRAMETIMER_IMPLEMENTATION
|
||||||
|
#include <frametimer.h>
|
||||||
|
|
||||||
|
#define CRTEMU_IMPLEMENTATION
|
||||||
|
#include <crtemu.h>
|
||||||
|
|
||||||
|
#ifndef __wasm__
|
||||||
|
#define THREAD_IMPLEMENTATION
|
||||||
|
#if defined( __TINYC__ )
|
||||||
|
typedef struct _RTL_CONDITION_VARIABLE { PVOID Ptr; } RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE;
|
||||||
|
typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE;
|
||||||
|
static VOID (*InitializeConditionVariable)( PCONDITION_VARIABLE );
|
||||||
|
static VOID (*WakeConditionVariable)( PCONDITION_VARIABLE );
|
||||||
|
static BOOL (*SleepConditionVariableCS)( PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD );
|
||||||
|
#endif
|
||||||
|
#include <thread.h>
|
||||||
|
#undef THREAD_IMPLEMENTATION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef boolean
|
||||||
|
|
||||||
|
#define MUS_IMPLEMENTATION
|
||||||
|
#include <mus.h>
|
||||||
|
|
||||||
|
#define TSF_IMPLEMENTATION
|
||||||
|
#define TSF_POW pow
|
||||||
|
#define TSF_POWF (float)pow
|
||||||
|
#define TSF_EXPF (float)exp
|
||||||
|
#define TSF_LOG log
|
||||||
|
#define TSF_TAN tan
|
||||||
|
#define TSF_LOG10 log10
|
||||||
|
#define TSF_SQRT (float)sqrt
|
||||||
|
#define TSF_SQRTF (float)sqrt
|
||||||
|
#include <math.h>
|
||||||
|
#include <tsf.h>
|
||||||
|
|
||||||
|
#include <soundfont.c>
|
||||||
|
|
||||||
|
#include <i_sound.c>
|
||||||
|
#include <i_video.c>
|
||||||
|
#include <i_system.c>
|
||||||
|
|
||||||
32
example/ultimate-artblock/src/doom_view.cpp
Normal file
32
example/ultimate-artblock/src/doom_view.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "./include/doom_view.hpp"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
DoomView::DoomView() : TUWidgetLayoutViewBase<ToonDoomWidget>() {}
|
||||||
|
|
||||||
|
DoomView::~DoomView() {}
|
||||||
|
|
||||||
|
QString DoomView::displayName() const { return "Doom!?"; }
|
||||||
|
|
||||||
|
ToonDoomWidget *DoomView::createWidget() { return new ToonDoomWidget(); }
|
||||||
|
|
||||||
|
app_proc_t real_app_proc = app_proc;
|
||||||
|
|
||||||
|
namespace toon_doom {
|
||||||
|
int app_proc(app_t *app, void *user_data) {
|
||||||
|
APP_U32 canvas[320 * 200];
|
||||||
|
memset(canvas, 0xc0, sizeof(canvas));
|
||||||
|
auto asDoomThread = reinterpret_cast<DoomThread *>(user_data);
|
||||||
|
asDoomThread->setApp(app);
|
||||||
|
// return 0;
|
||||||
|
auto result = real_app_proc(app, user_data);
|
||||||
|
thread_atomic_int_store(&app_running, 0);
|
||||||
|
std::cout << "exiting app_proc" << std::endl;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
int app_proc_thread(void *user_data) {
|
||||||
|
auto asDoomThread = reinterpret_cast<DoomThread *>(user_data);
|
||||||
|
asDoomThread->setId(GetCurrentThreadId());
|
||||||
|
auto result = app_run(app_proc, user_data, nullptr, nullptr, nullptr);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} // namespace toon_doom
|
||||||
54
example/ultimate-artblock/src/include/common.h
Normal file
54
example/ultimate-artblock/src/include/common.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef COMMON_H
|
||||||
|
#define COMMON_H
|
||||||
|
#pragma warning(disable : 4113)
|
||||||
|
#pragma warning(disable : 4311)
|
||||||
|
#pragma warning(disable : 4047)
|
||||||
|
#pragma warning(disable : 4024)
|
||||||
|
#pragma warning(disable : 4312)
|
||||||
|
#pragma warning(disable : 4020)
|
||||||
|
#pragma warning(disable : 4700)
|
||||||
|
#pragma warning(disable : 4133)
|
||||||
|
#pragma warning(disable : 4142)
|
||||||
|
#pragma warning(disable : 4005)
|
||||||
|
#pragma warning(disable : 4244)
|
||||||
|
#pragma warning(disable : 4267)
|
||||||
|
#pragma warning(disable : 4838)
|
||||||
|
#pragma warning(disable : 4430)
|
||||||
|
#pragma warning(disable : 4996)
|
||||||
|
#define APP_WINDOWS
|
||||||
|
#if defined(__BYTEBOOL__)
|
||||||
|
typedef unsigned char boolean;
|
||||||
|
typedef unsigned char byte;
|
||||||
|
#endif
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
#endif
|
||||||
|
#define MY_APP_FATAL_ERROR(ctx, message) { printf( "FATAL ERROR: %s\n", message ); MessageBoxA( 0, message, "Fatal Error!", MB_OK | MB_ICONSTOP ); _flushall(); }
|
||||||
|
|
||||||
|
#define APP_LOG(ctx, level, message) printf( "%s\n", message )
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
void D_DoomMain(void);
|
||||||
|
#include <app_funcs.h>
|
||||||
|
#undef APP_FATAL_ERROR
|
||||||
|
#define APP_FATAL_ERROR MY_APP_FATAL_ERROR
|
||||||
|
#include <thread.h>
|
||||||
|
extern thread_mutex_t mus_mutex;
|
||||||
|
extern thread_signal_t vblank_signal;
|
||||||
|
extern thread_atomic_int_t app_running;
|
||||||
|
extern int maketic;
|
||||||
|
extern int gametic;
|
||||||
|
void M_StartControlPanel (void);
|
||||||
|
extern char** myargv;
|
||||||
|
extern int myargc;
|
||||||
|
int app_proc(app_t *app, void *user_data);
|
||||||
|
void M_QuitResponse(int ch);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include <app_funcs.h>
|
||||||
|
#undef APP_FATAL_ERROR
|
||||||
|
#define APP_FATAL_ERROR MY_APP_FATAL_ERROR
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
10
example/ultimate-artblock/src/include/doom_view.hpp
Normal file
10
example/ultimate-artblock/src/include/doom_view.hpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "./toon_doom.hpp"
|
||||||
|
class DoomView : public TUWidgetLayoutViewBase<ToonDoomWidget> {
|
||||||
|
public:
|
||||||
|
DoomView();
|
||||||
|
~DoomView() override;
|
||||||
|
QString displayName() const override;
|
||||||
|
protected:
|
||||||
|
ToonDoomWidget *createWidget() override;
|
||||||
|
};
|
||||||
269
example/ultimate-artblock/src/include/toon_doom.hpp
Normal file
269
example/ultimate-artblock/src/include/toon_doom.hpp
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <QtCore/QPointer>
|
||||||
|
#include <QtCore/qnamespace.h>
|
||||||
|
|
||||||
|
#include <QtCore/QEvent>
|
||||||
|
#include <QtCore/QThread>
|
||||||
|
#include <QtGui/QtGui>
|
||||||
|
#include <QtWidgets/QtWidgets>
|
||||||
|
#include <set>
|
||||||
|
#include <toon_boom/ext/layout.hpp>
|
||||||
|
#include <toon_boom/ext/util.hpp>
|
||||||
|
|
||||||
|
#include "./common.h"
|
||||||
|
#include "./util.hpp"
|
||||||
|
|
||||||
|
typedef int (*app_proc_t)(app_t *, void *);
|
||||||
|
|
||||||
|
namespace toon_doom {
|
||||||
|
int app_proc(app_t *app, void *user_data);
|
||||||
|
int app_proc_thread(void *user_data);
|
||||||
|
}; // namespace toon_doom
|
||||||
|
class ToonDoomWidget;
|
||||||
|
|
||||||
|
class DoomThread : public QThread {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
DoomThread(ToonDoomWidget *widget, QObject *parent = nullptr)
|
||||||
|
: QThread(parent) {
|
||||||
|
m_widget = widget;
|
||||||
|
}
|
||||||
|
~DoomThread() {
|
||||||
|
M_QuitResponse('y');
|
||||||
|
thread_atomic_int_store(&app_running, 0);
|
||||||
|
maketic = 0;
|
||||||
|
gametic = 0;
|
||||||
|
if (isRunning()) {
|
||||||
|
terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void startGame(app_t *app) { emit gameStarted(m_widget, app); }
|
||||||
|
void setApp(app_t *app) { this->app = app; }
|
||||||
|
DWORD getId() { return tid; }
|
||||||
|
void setId(DWORD tid) { this->tid = tid; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
signals:
|
||||||
|
void gameStarted(ToonDoomWidget *widget, app_t *app);
|
||||||
|
void gameExited(const int &result);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QPointer<ToonDoomWidget> m_widget;
|
||||||
|
void run() override {
|
||||||
|
tid = GetCurrentThreadId();
|
||||||
|
myargc = 0;
|
||||||
|
myargv = nullptr;
|
||||||
|
thread_signal_init(&vblank_signal);
|
||||||
|
thread_mutex_init(&mus_mutex);
|
||||||
|
thread_atomic_int_store(&app_running, 1);
|
||||||
|
threadPtr = thread_create(&toon_doom::app_proc_thread, this,
|
||||||
|
THREAD_STACK_SIZE_DEFAULT);
|
||||||
|
int result =
|
||||||
|
thread_signal_wait(&vblank_signal, THREAD_SIGNAL_WAIT_INFINITE);
|
||||||
|
startGame(app);
|
||||||
|
D_DoomMain();
|
||||||
|
emit gameExited(result);
|
||||||
|
}
|
||||||
|
thread_ptr_t threadPtr = nullptr;
|
||||||
|
DWORD tid = 0;
|
||||||
|
app_t *app = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ToonDoomWidget : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ToonDoomWidget(QWidget *parent = nullptr) : QWidget(parent) {
|
||||||
|
setPalette(QPalette(QColor(0, 0, 0)));
|
||||||
|
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||||
|
setAutoFillBackground(true);
|
||||||
|
setMinimumSize(320, 200);
|
||||||
|
setWindowTitle("Doom!?");
|
||||||
|
m_layout = new QVBoxLayout(this);
|
||||||
|
m_layout->setAlignment(Qt::AlignCenter);
|
||||||
|
m_layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
m_layout->setSpacing(0);
|
||||||
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
|
}
|
||||||
|
~ToonDoomWidget() {
|
||||||
|
QObject::disconnect(static_cast<QApplication *>(QApplication::instance()),
|
||||||
|
&QApplication::focusChanged, this,
|
||||||
|
&ToonDoomWidget::focusChanged);
|
||||||
|
auto inp =
|
||||||
|
AttachThreadInput(GetCurrentThreadId(), doomThread->getId(), false);
|
||||||
|
util::debug::out << "~ToonDoomWidget AttachThreadInput: " << inp
|
||||||
|
<< std::endl;
|
||||||
|
delete doomThread;
|
||||||
|
}
|
||||||
|
void setApp(app_t *app) {
|
||||||
|
this->app = app;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
app_t *getApp() const { return app; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void start() {
|
||||||
|
if (doomThread != nullptr && doomThread->isRunning()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
doomThread = new DoomThread(this, this);
|
||||||
|
connect(doomThread, &DoomThread::gameExited, this,
|
||||||
|
&ToonDoomWidget::gameExited);
|
||||||
|
connect(doomThread, &DoomThread::gameStarted, this,
|
||||||
|
&ToonDoomWidget::gameStarted);
|
||||||
|
doomThread->start();
|
||||||
|
}
|
||||||
|
void gameStarted(ToonDoomWidget *widget, app_t *app) { widget->setApp(app); }
|
||||||
|
void gameExited(const int &result) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWidget *doomWidget = nullptr;
|
||||||
|
app_t *app = nullptr;
|
||||||
|
QWindow *m_window = nullptr;
|
||||||
|
DoomThread *doomThread = nullptr;
|
||||||
|
QVBoxLayout *m_layout = nullptr;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent *event) override {
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
void moveEvent(QMoveEvent *event) override {
|
||||||
|
QWidget::moveEvent(event);
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
void focusInEvent(QFocusEvent *event) override {
|
||||||
|
util::debug::out << "focusInEvent: " << event->type() << std::endl;
|
||||||
|
if (app) {
|
||||||
|
app->has_focus = true;
|
||||||
|
SetFocus(app->hwnd);
|
||||||
|
}
|
||||||
|
QWidget::focusInEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eventFilter(QObject *obj, QEvent *event) override {
|
||||||
|
QMetaEnum metaEnum = QMetaEnum::fromType<QEvent::Type>();
|
||||||
|
util::debug::out << "eventFilter: " << metaEnum.valueToKey(event->type())
|
||||||
|
<< " obj: " << obj->metaObject()->className() << std::endl;
|
||||||
|
if (event->type() == QEvent::WindowActivate ||
|
||||||
|
(event->type() == QEvent::FocusIn && obj != this)) {
|
||||||
|
this->setFocus(Qt::OtherFocusReason);
|
||||||
|
}
|
||||||
|
if (obj == this && (event->type() == QEvent::FocusOut ||
|
||||||
|
event->type() == QEvent::FocusAboutToChange)) {
|
||||||
|
event->ignore();
|
||||||
|
setFocus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return QWidget::eventFilter(obj, event);
|
||||||
|
}
|
||||||
|
bool event(QEvent *event) override {
|
||||||
|
if (event->type() == QEvent::FocusOut ||
|
||||||
|
event->type() == QEvent::FocusAboutToChange) {
|
||||||
|
util::debug::out << "focus out" << std::endl;
|
||||||
|
setEnabled(true);
|
||||||
|
if (event->type() == QEvent::FocusOut) {
|
||||||
|
auto asFocusEvent = static_cast<QFocusEvent *>(event);
|
||||||
|
util::debug::out << "focus out reason: " << asFocusEvent->reason()
|
||||||
|
<< std::endl;
|
||||||
|
if (asFocusEvent->reason() == Qt::OtherFocusReason) {
|
||||||
|
event->ignore();
|
||||||
|
setFocus();
|
||||||
|
QApplication::processEvents();
|
||||||
|
}
|
||||||
|
} else if (event->type() == QEvent::FocusAboutToChange) {
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return QWidget::event(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::pair<QKeyEvent *, QKeyEvent *> createEscapeKeyEvents() {
|
||||||
|
return std::pair<QKeyEvent *, QKeyEvent *>(
|
||||||
|
new QKeyEvent(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier),
|
||||||
|
new QKeyEvent(QEvent::KeyRelease, Qt::Key_Escape, Qt::NoModifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isMouseMoveEvent(QEvent *event) {
|
||||||
|
return event->type() == QEvent::MouseMove ||
|
||||||
|
event->type() == QEvent::Enter || event->type() == QEvent::Leave ||
|
||||||
|
event->type() == QEvent::TabletMove ||
|
||||||
|
event->type() == QEvent::NonClientAreaMouseMove ||
|
||||||
|
event->type() == QEvent::GrabMouse ||
|
||||||
|
event->type() == QEvent::HoverMove ||
|
||||||
|
event->type() == QEvent::HoverEnter ||
|
||||||
|
event->type() == QEvent::HoverLeave ||
|
||||||
|
event->type() == QEvent::GraphicsSceneHoverMove ||
|
||||||
|
event->type() == QEvent::GraphicsSceneHoverEnter ||
|
||||||
|
event->type() == QEvent::GraphicsSceneHoverLeave ||
|
||||||
|
event->type() == QEvent::GraphicsSceneMouseMove ||
|
||||||
|
event->type() == QEvent::GraphicsSceneLeave;
|
||||||
|
}
|
||||||
|
std::set<QWidget *> m_ancestors;
|
||||||
|
private slots:
|
||||||
|
void updateGeometry() {
|
||||||
|
if (m_window != nullptr) {
|
||||||
|
doomWidget->setGeometry(this->rect());
|
||||||
|
m_window->setGeometry(doomWidget->rect());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void windowClosed() {
|
||||||
|
util::debug::out << "window closed" << std::endl;
|
||||||
|
delete doomThread;
|
||||||
|
doomThread = nullptr;
|
||||||
|
}
|
||||||
|
void init() {
|
||||||
|
m_window = QWindow::fromWinId(WId(app->hwnd));
|
||||||
|
Qt::WindowFlags nflags = Qt::WindowType::Window | Qt::WindowType::Widget |
|
||||||
|
Qt::WindowType::FramelessWindowHint |
|
||||||
|
Qt::CustomizeWindowHint;
|
||||||
|
const auto dpr = m_window->devicePixelRatio();
|
||||||
|
// m_window->setFlags(m_window->flags() | nflags);
|
||||||
|
m_window->setGeometry(this->rect());
|
||||||
|
connect(m_window, &QWindow::close, this, &ToonDoomWidget::windowClosed);
|
||||||
|
doomWidget =
|
||||||
|
QWidget::createWindowContainer(m_window, this, Qt::WindowType::Widget);
|
||||||
|
doomWidget->setSizePolicy(QSizePolicy::MinimumExpanding,
|
||||||
|
QSizePolicy::MinimumExpanding);
|
||||||
|
util::debug::out << "doomwidget == window: "
|
||||||
|
<< (doomWidget->windowHandle() == m_window) << std::endl;
|
||||||
|
auto flags = doomWidget->windowFlags();
|
||||||
|
|
||||||
|
doomWidget->hide();
|
||||||
|
m_layout->addWidget(doomWidget, 1);
|
||||||
|
util::debug::out << "doom thread id: " << doomThread->getId() << std::endl;
|
||||||
|
auto inp =
|
||||||
|
AttachThreadInput(GetCurrentThreadId(), doomThread->getId(), true);
|
||||||
|
util::debug::out << "AttachThreadInput: " << inp << std::endl;
|
||||||
|
doomWidget->show();
|
||||||
|
auto parentWindow = window();
|
||||||
|
updateGeometry();
|
||||||
|
|
||||||
|
{
|
||||||
|
// add widget hierarchy to a set for focus tracking
|
||||||
|
QWidget *p = doomWidget;
|
||||||
|
while (p != nullptr) {
|
||||||
|
util::debug::out << "widget @ " << util::debug::addrToHex(p) << ": "
|
||||||
|
<< p->metaObject()->className() << " parent: "
|
||||||
|
<< util::debug::addrToHex(p->parentWidget())
|
||||||
|
<< std::endl;
|
||||||
|
m_ancestors.insert(p);
|
||||||
|
|
||||||
|
p = p->parentWidget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
installEventFilter(this);
|
||||||
|
doomWidget->setFocusPolicy(Qt::StrongFocus);
|
||||||
|
QObject::connect(static_cast<QApplication *>(QApplication::instance()),
|
||||||
|
&QApplication::focusChanged, this,
|
||||||
|
&ToonDoomWidget::focusChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
void focusChanged(QWidget *old, QWidget *now) {
|
||||||
|
if (m_ancestors.contains(old) && !m_ancestors.contains(now)) {
|
||||||
|
app->has_focus = false;
|
||||||
|
M_StartControlPanel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
3
example/ultimate-artblock/src/include/util.hpp
Normal file
3
example/ultimate-artblock/src/include/util.hpp
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
void sendEscapeKeyToWindow(HWND hwnd);
|
||||||
22
example/ultimate-artblock/src/util.cpp
Normal file
22
example/ultimate-artblock/src/util.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "./include/util.hpp"
|
||||||
|
#include <toon_boom/ext/util.hpp>
|
||||||
|
using namespace util;
|
||||||
|
void sendEscapeKeyToWindow(HWND hwnd) {
|
||||||
|
{
|
||||||
|
SetForegroundWindow(hwnd);
|
||||||
|
INPUT inputs[2] = {};
|
||||||
|
ZeroMemory(inputs, sizeof(inputs));
|
||||||
|
|
||||||
|
inputs[0].type = INPUT_KEYBOARD;
|
||||||
|
inputs[0].ki.wVk = VK_ESCAPE;
|
||||||
|
|
||||||
|
inputs[1].type = INPUT_KEYBOARD;
|
||||||
|
inputs[1].ki.wVk = VK_ESCAPE;
|
||||||
|
inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||||
|
|
||||||
|
UINT uSent = SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
|
||||||
|
|
||||||
|
debug::out << "SendInput: " << uSent << std::endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user