chore: initial commit

This commit is contained in:
fallenoak 2023-01-02 13:17:18 -06:00
commit 70b00c5c38
No known key found for this signature in database
GPG key ID: 7628F8E61AEA070D
965 changed files with 264882 additions and 0 deletions

13
src/CMakeLists.txt Normal file
View file

@ -0,0 +1,13 @@
add_subdirectory(app)
add_subdirectory(async)
add_subdirectory(client)
add_subdirectory(event)
add_subdirectory(glue)
add_subdirectory(gx)
add_subdirectory(math)
add_subdirectory(model)
add_subdirectory(net)
add_subdirectory(sound)
add_subdirectory(ui)
add_subdirectory(util)
add_subdirectory(world)

48
src/app/CMakeLists.txt Normal file
View file

@ -0,0 +1,48 @@
if(WHOA_SYSTEM_MAC)
file(GLOB PRIVATE_SOURCES "mac/*.cpp" "mac/*.mm")
set_source_files_properties(${PRIVATE_SOURCES}
PROPERTIES COMPILE_FLAGS "-x objective-c++"
)
add_executable(Whoa ${PRIVATE_SOURCES})
target_link_libraries(Whoa
PRIVATE
client
event
gx
net
util
"-framework AppKit"
"-framework Carbon"
"-framework IOKit"
)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/mac/MainMenu.nib DESTINATION "bin")
endif()
if(WHOA_SYSTEM_LINUX)
file(GLOB PRIVATE_SOURCES "linux/*.cpp")
add_executable(Whoa ${PRIVATE_SOURCES})
target_link_libraries(Whoa
PRIVATE
client
event
gx
net
util
)
endif()
target_include_directories(Whoa
PRIVATE
${CMAKE_SOURCE_DIR}/src
)
# Windows executables yet to be done
if(WHOA_SYSTEM_MAC OR WHOA_SYSTEM_LINUX)
install(TARGETS Whoa DESTINATION "bin")
endif()

11
src/app/linux/Wowre.cpp Normal file
View file

@ -0,0 +1,11 @@
#include "client/Client.hpp"
int main(int argc, char* argv[]) {
// TODO
CommonMain();
// TODO
return 0;
}

View file

@ -0,0 +1,16 @@
#ifndef APP_MAC_ENGINE_GL_LAYER_VIEW_H
#define APP_MAC_ENGINE_GL_LAYER_VIEW_H
#include "gx/gll/GLLayerView.h"
#include <AppKit/AppKit.h>
#include <Foundation/Foundation.h>
@interface EngineGLLayerView : GLLayerView
- (void)insertText:(id)string;
- (void)keyDown:(NSEvent*)event;
@end
#endif

View file

@ -0,0 +1,41 @@
#include "app/mac/EngineGLLayerView.h"
#include "app/mac/MacClient.h"
#include "event/Input.hpp"
#include <Carbon/Carbon.h>
@implementation EngineGLLayerView
- (void)insertText:(id)string {
// TODO
}
- (void)keyDown:(NSEvent*)event {
uint32_t keyCode = event.keyCode;
MacClient::CheckKeyboardLayout();
if (keyCode <= 0x7F) {
uint32_t key = MacClient::s_keyConversion[keyCode];
if (key != KEY_NONE) {
OsQueuePut(OS_INPUT_KEY_DOWN, key, 0, 0, 0);
}
}
if (MacClient::GetTextInputEnabled()) {
auto events = [NSArray arrayWithObject:event];
[self interpretKeyEvents:events];
} else {
EventRef eventRef = static_cast<EventRef>(const_cast<void*>([event eventRef]));
uint8_t chr;
if (GetEventParameter(eventRef, 'kchr', 'TEXT', 0, 1, 0, &chr) == noErr) {
if (chr > 0x1F && chr <= 0x7E) {
OsQueuePut(OS_INPUT_CHAR, chr, 1, 0, 0);
}
}
}
}
@end

30
src/app/mac/MacClient.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef APP_MAC_MAC_CLIENT_H
#define APP_MAC_MAC_CLIENT_H
#include "event/Event.hpp"
#include <cstdint>
class MacClient {
public:
enum ClipboardAction {
ClipboardUndo = 1,
ClipboardCut = 2,
ClipboardCopy = 3,
ClipboardPaste = 4,
ClipboardSelectAll = 5
};
static void* s_currentKeyboardLayout;
static KEY s_specialKeyConversion[128];
static KEY s_keyConversion[128];
static void CheckKeyboardLayout(void);
static double GetMouseSpeed(void);
static bool GetTextInputEnabled(void);
static void InitializeKeyConversion(void);
static bool IsUsingGLLayer(void);
static void PostClipboardKeyEvents(MacClient::ClipboardAction);
static void SetMouseCoalescingEnabled(bool);
};
#endif

375
src/app/mac/MacClient.mm Normal file
View file

@ -0,0 +1,375 @@
#include "app/mac/MacClient.h"
#include "event/Input.hpp"
#include "os/Compat.hpp"
#include <AppKit/AppKit.h>
#include <Carbon/Carbon.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/hidsystem/event_status_driver.h>
#include <IOKit/hidsystem/IOHIDLib.h>
#include <IOKit/hidsystem/IOHIDParameter.h>
void* MacClient::s_currentKeyboardLayout = nullptr;
KEY MacClient::s_specialKeyConversion[128] = {
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_1, // kVK_ANSI_1 (0x12)
KEY_2, // kVK_ANSI_2 (0x13)
KEY_3, // kVK_ANSI_3 (0x14)
KEY_4, // kVK_ANSI_4 (0x15)
KEY_6, // kVK_ANSI_6 (0x16)
KEY_5, // kVK_ANSI_5 (0x17)
KEY_NONE,
KEY_9, // kVK_ANSI_9 (0x19)
KEY_7, // kVK_ANSI_7 (0x1A)
KEY_NONE,
KEY_8, // kVK_ANSI_8 (0x1C)
KEY_0, // kVK_ANSI_0 (0x1D)
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_ENTER, // kVK_Return (0x24)
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_TAB, // kVK_Tab (0x30)
KEY_SPACE, // kVK_Space (0x31)
KEY_NONE,
KEY_BACKSPACE, // kVK_Delete (0x33)
KEY_NONE,
KEY_ESCAPE, // kVK_Escape (0x35)
KEY_NONE,
KEY_NONE,
KEY_LSHIFT, // kVK_Shift (0x38)
KEY_CAPSLOCK, // kVK_CapsLock (0x39)
KEY_LALT, // kVK_Option (0x3A)
KEY_LCONTROL, // kVK_Control (0x3B)
KEY_RSHIFT, // kVK_RightShift (0x3C)
KEY_RALT, // kVK_RightOption (0x3D)
KEY_RCONTROL, // kVK_RightControl (0x3E)
KEY_NONE,
KEY_F17, // kVK_F17 (0x40)
KEY_NUMPAD_DECIMAL, // kVK_ANSI_KeypadDecimal (0x41)
KEY_NONE,
KEY_NUMPAD_MULTIPLY, // kVK_ANSI_KeypadMultiply (0x43)
KEY_NONE,
KEY_NUMPAD_PLUS, // kVK_ANSI_KeypadPlus (0x45)
KEY_NONE,
KEY_NUMLOCK, // kVK_ANSI_KeypadClear (0x47)
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_NUMPAD_DIVIDE, // kVK_ANSI_KeypadDivide (0x4B)
KEY_ENTER, // kVK_ANSI_KeypadEnter (0x4C)
KEY_NONE,
KEY_NUMPAD_MINUS, // kVK_ANSI_KeypadMinus (0x4E)
KEY_F18, // kVK_F18 (0x4F)
KEY_F19, // kVK_F19 (0x50)
KEY_NUMPAD_EQUALS, // kVK_ANSI_KeypadEquals (0x51)
KEY_NUMPAD0, // kVK_ANSI_Keypad0 (0x52)
KEY_NUMPAD1, // kVK_ANSI_Keypad1 (0x53)
KEY_NUMPAD2, // kVK_ANSI_Keypad2 (0x54)
KEY_NUMPAD3, // kVK_ANSI_Keypad3 (0x55)
KEY_NUMPAD4, // kVK_ANSI_Keypad4 (0x56)
KEY_NUMPAD5, // kVK_ANSI_Keypad5 (0x57)
KEY_NUMPAD6, // kVK_ANSI_Keypad6 (0x58)
KEY_NUMPAD7, // kVK_ANSI_Keypad7 (0x59)
KEY_NONE,
KEY_NUMPAD8, // kVK_ANSI_Keypad8 (0x5B)
KEY_NUMPAD9, // kVK_ANSI_Keypad9 (0x5C)
KEY_NONE,
KEY_NONE,
KEY_NONE,
KEY_F5, // kVK_F5 (0x60)
KEY_F6, // kVK_F6 (0x61)
KEY_F7, // kVK_F7 (0x62)
KEY_F3, // kVK_F3 (0x63)
KEY_F8, // kVK_F8 (0x64)
KEY_F9, // kVK_F9 (0x65)
KEY_NONE,
KEY_F11, // kVK_F11 (0x67)
KEY_NONE,
KEY_F13, // kVK_F13 (0x69)
KEY_F16, // kVK_F16 (0x6A)
KEY_F14, // kVK_F14 (0x6B)
KEY_NONE,
KEY_F10, // kVK_F10 (0x6D)
KEY_NONE,
KEY_F12, // kVK_F12 (0x6F)
KEY_NONE,
KEY_F15, // kVK_F15 (0x71)
KEY_INSERT, // kVK_Help (0x72)
KEY_HOME, // kVK_Home (0x73)
KEY_PAGEUP, // kVK_PageUp (0x74)
KEY_DELETE, // kVK_ForwardDelete (0x75)
KEY_F4, // kVK_F4 (0x76)
KEY_END, // kVK_End (0x77)
KEY_F2, // kVK_F2 (0x78)
KEY_PAGEDOWN, // kVK_PageDown (0x79)
KEY_F1, // kVK_F1 (0x7A)
KEY_LEFT, // kVK_LeftArrow (0x7B)
KEY_RIGHT, // kVK_RightArrow (0x7C)
KEY_DOWN, // kVK_DownArrow (0x7D)
KEY_UP, // kVK_UpArrow (0x7E)
KEY_NONE
};
KEY MacClient::s_keyConversion[128];
void MacClient::CheckKeyboardLayout() {
#if WHOA_SYSTEM_VERSION < WHOA_MACOS_10_6
void* KCHR = reinterpret_cast<void*>(GetScriptManagerVariable(smKCHRCache));
if (MacClient::s_currentKeyboardLayout != KCHR) {
MacClient::InitializeKeyConversion();
MacClient::s_currentKeyboardLayout = KCHR;
}
#endif
#if WHOA_SYSTEM_VERSION >= WHOA_MACOS_10_6
TISInputSourceRef inputSrc = TISCopyCurrentKeyboardLayoutInputSource();
CFDataRef layoutData = static_cast<CFDataRef>(TISGetInputSourceProperty(inputSrc, kTISPropertyUnicodeKeyLayoutData));
const UCKeyboardLayout* keyboardLayout = reinterpret_cast<const UCKeyboardLayout*>(CFDataGetBytePtr(layoutData));
if (MacClient::s_currentKeyboardLayout != keyboardLayout) {
MacClient::InitializeKeyConversion();
MacClient::s_currentKeyboardLayout = const_cast<UCKeyboardLayout*>(keyboardLayout);
}
#endif
}
double MacClient::GetMouseSpeed() {
#if WHOA_SYSTEM_VERSION < WHOA_MACOS_10_12
double mouseSpeed = 1.0;
NXEventHandle handle = NXOpenEventStatus();
if (handle) {
IOHIDGetAccelerationWithKey(handle, CFSTR(kIOHIDMouseAccelerationType), &mouseSpeed);
NXCloseEventStatus(handle);
}
return mouseSpeed;
#endif
#if WHOA_SYSTEM_VERSION >= WHOA_MACOS_10_12
double mouseSpeed = 1.0;
io_service_t service = IORegistryEntryFromPath(kIOMasterPortDefault, kIOServicePlane ":/IOResources/IOHIDSystem");
if (service != MACH_PORT_NULL) {
CFDictionaryRef parameters = static_cast<CFDictionaryRef>(IORegistryEntryCreateCFProperty(service, CFSTR(kIOHIDParametersKey), kCFAllocatorDefault, kNilOptions));
CFNumberRef speedParameter = static_cast<CFNumberRef>(CFDictionaryGetValue(parameters, CFSTR(kIOHIDMouseAccelerationType)));
if (speedParameter) {
int32_t number;
if (CFNumberGetValue(static_cast<CFNumberRef>(speedParameter), kCFNumberSInt32Type, &number)) {
mouseSpeed = static_cast<double>(number) / 65536.0;
}
}
CFRelease(parameters);
IOObjectRelease(service);
}
return mouseSpeed;
#endif
}
bool MacClient::GetTextInputEnabled() {
// TODO
return false;
}
void MacClient::InitializeKeyConversion() {
memcpy(MacClient::s_keyConversion, MacClient::s_specialKeyConversion, sizeof(MacClient::s_specialKeyConversion));
#if WHOA_SYSTEM_VERSION < WHOA_MACOS_10_6
void* KCHR = reinterpret_cast<void*>(GetScriptManagerVariable(smKCHRCache));
if (KCHR) {
for (uint16_t i = 0; i < 128; i++) {
if (MacClient::s_keyConversion[i] == KEY_NONE) {
uint16_t translate = i | (1 << 7);
uint32_t state = 0;
uint32_t value = KeyTranslate(KCHR, translate, &state);
if (state) {
value = KeyTranslate(KCHR, translate, &state);
}
if (value) {
value = value - 97 <= 25 ? value - 32 : value;
auto string = CFStringCreateWithBytes(
nullptr,
reinterpret_cast<uint8_t*>(&value),
1,
0,
false
);
if (string) {
CFIndex len;
CFRange range = CFRangeMake(0, 1);
CFStringGetBytes(
string,
range,
kCFStringEncodingISOLatin1,
0,
0,
reinterpret_cast<uint8_t*>(&value),
1,
&len
);
if (len && value) {
MacClient::s_keyConversion[i] = static_cast<KEY>(value);
}
}
}
}
}
}
#endif
#if WHOA_SYSTEM_VERSION >= WHOA_MACOS_10_6
TISInputSourceRef inputSrc = TISCopyCurrentKeyboardLayoutInputSource();
CFDataRef layoutData = static_cast<CFDataRef>(TISGetInputSourceProperty(inputSrc, kTISPropertyUnicodeKeyLayoutData));
const UCKeyboardLayout* keyboardLayout = reinterpret_cast<const UCKeyboardLayout*>(CFDataGetBytePtr(layoutData));
const uint32_t keyboardType = LMGetKbdType();
if (keyboardLayout) {
for (uint16_t i = 0; i < 128; i++) {
if (MacClient::s_keyConversion[i] == KEY_NONE) {
uint16_t vkey = i;
uint32_t state = 0;
UniChar buf[1];
UniCharCount len;
OSStatus res = UCKeyTranslate(
keyboardLayout,
vkey,
kUCKeyActionUp,
0,
keyboardType,
0,
&state,
1,
&len,
buf
);
if (res != noErr) {
continue;
}
if (state) {
res = UCKeyTranslate(
keyboardLayout,
vkey,
kUCKeyActionUp,
0,
keyboardType,
0,
&state,
1,
&len,
buf
);
if (res != noErr) {
continue;
}
}
uint16_t value = buf[0];
if (len && value) {
value = value >= 97 && value <= 122 ? value - 32 : value;
MacClient::s_keyConversion[i] = static_cast<KEY>(value);
}
}
}
}
#endif
}
bool MacClient::IsUsingGLLayer() {
return true;
}
void MacClient::PostClipboardKeyEvents(MacClient::ClipboardAction action) {
int32_t v1;
switch (action) {
case ClipboardUndo:
v1 = 90;
break;
case ClipboardCut:
v1 = 88;
break;
case ClipboardCopy:
v1 = 67;
break;
case ClipboardPaste:
v1 = 86;
break;
case ClipboardSelectAll:
v1 = 65;
break;
default:
return;
}
OsInputPostEvent(OS_INPUT_KEY_DOWN, 2, 0, 0, 0);
OsInputPostEvent(OS_INPUT_KEY_DOWN, v1, 0, 0, 0);
OsInputPostEvent(OS_INPUT_KEY_UP, v1, 0, 0, 0);
OsInputPostEvent(OS_INPUT_KEY_UP, 2, 0, 0, 0);
}
void MacClient::SetMouseCoalescingEnabled(bool enabled) {
#if WHOA_SYSTEM_VERSION < WHOA_MACOS_10_5
bool prevEnabled = false;
SetMouseCoalescingEnabled(true, &prevEnabled);
#endif
#if WHOA_SYSTEM_VERSION >= WHOA_MACOS_10_5
[NSEvent setMouseCoalescingEnabled: enabled];
#endif
}

8
src/app/mac/Main.nib/classes.nib generated Executable file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBVersion</key>
<string>1</string>
</dict>
</plist>

18
src/app/mac/Main.nib/info.nib generated Executable file
View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBFramework Version</key>
<string>677</string>
<key>IBLastKnownRelativeProjectPath</key>
<string>../../../WoW.xcodeproj</string>
<key>IBOldestOS</key>
<integer>3</integer>
<key>IBOpenObjects</key>
<array/>
<key>IBSystem Version</key>
<string>9J61</string>
<key>targetFramework</key>
<string>IBCarbonFramework</string>
</dict>
</plist>

131
src/app/mac/Main.nib/objects.xib Executable file
View file

@ -0,0 +1,131 @@
<?xml version="1.0" standalone="yes"?>
<object class="NSIBObjectData">
<object name="rootObject" class="NSCustomObject" id="1">
</object>
<array count="17" name="allObjects">
<object class="IBCarbonMenuItem" id="144">
<string name="title">Paste</string>
<string name="keyEquivalent">v</string>
<ostype name="command">past</ostype>
</object>
<object class="IBCarbonMenuItem" id="142">
<boolean name="separator">TRUE</boolean>
</object>
<object class="IBCarbonMenuItem" id="149">
<string name="title">Copy</string>
<string name="keyEquivalent">c</string>
<ostype name="command">copy</ostype>
</object>
<object class="IBCarbonMenuItem" id="183">
<string name="title">About World of Warcraft...</string>
<int name="keyEquivalentModifier">0</int>
<ostype name="command">abou</ostype>
</object>
<object class="IBCarbonMenu" id="181">
<string name="title">World of Warcraft</string>
<string name="name">_NSAppleMenu</string>
<array count="3" name="items">
<reference idRef="183"/>
<object class="IBCarbonMenuItem" id="186">
<boolean name="separator">TRUE</boolean>
</object>
<object class="IBCarbonMenuItem" id="187">
<string name="title">Switch To Full Screen Mode</string>
<string name="keyEquivalent">m</string>
<ostype name="command">Full</ostype>
</object>
</array>
</object>
<object class="IBCarbonMenuItem" id="152">
<string name="title">Edit</string>
<object name="submenu" class="IBCarbonMenu" id="147">
<string name="title">Edit</string>
<int name="menuID">128</int>
<array count="6" name="items">
<object class="IBCarbonMenuItem" id="141">
<string name="title">Undo</string>
<string name="keyEquivalent">z</string>
<ostype name="command">undo</ostype>
</object>
<reference idRef="142"/>
<object class="IBCarbonMenuItem" id="143">
<string name="title">Cut</string>
<string name="keyEquivalent">x</string>
<ostype name="command">cut </ostype>
</object>
<reference idRef="149"/>
<reference idRef="144"/>
<object class="IBCarbonMenuItem" id="148">
<string name="title">Select All</string>
<string name="keyEquivalent">a</string>
<ostype name="command">sall</ostype>
</object>
</array>
</object>
</object>
<object class="IBCarbonMenu" id="29">
<string name="title">Untitled</string>
<string name="name">_NSMainMenu</string>
<array count="2" name="items">
<object class="IBCarbonMenuItem" id="182">
<string name="title">World of Warcraft</string>
<reference name="submenu" idRef="181"/>
</object>
<reference idRef="152"/>
</array>
</object>
<reference idRef="141"/>
<reference idRef="143"/>
<object class="IBCarbonMenuItem" id="198">
<string name="title">Show BatchViewer</string>
<boolean name="notPreviousAlternate">TRUE</boolean>
<ostype name="command">BVwr</ostype>
</object>
<reference idRef="187"/>
<reference idRef="182"/>
<object class="IBCarbonMenuItem" id="199">
<string name="title">Show GL Layer Setup</string>
<boolean name="notPreviousAlternate">TRUE</boolean>
<ostype name="command">GLLs</ostype>
</object>
<object class="IBCarbonMenu" id="197">
<string name="title">Batch Viewer</string>
<array count="2" name="items">
<reference idRef="198"/>
<reference idRef="199"/>
</array>
</object>
<reference idRef="186"/>
<reference idRef="147"/>
<reference idRef="148"/>
</array>
<array count="17" name="allParents">
<reference idRef="147"/>
<reference idRef="147"/>
<reference idRef="147"/>
<reference idRef="181"/>
<reference idRef="182"/>
<reference idRef="29"/>
<reference idRef="1"/>
<reference idRef="147"/>
<reference idRef="147"/>
<reference idRef="197"/>
<reference idRef="181"/>
<reference idRef="29"/>
<reference idRef="197"/>
<reference idRef="1"/>
<reference idRef="181"/>
<reference idRef="152"/>
<reference idRef="147"/>
</array>
<dictionary count="3" name="nameTable">
<string>BatchViewerMenu</string>
<reference idRef="197"/>
<string>File&apos;s Owner</string>
<reference idRef="1"/>
<string>MenuBar</string>
<reference idRef="29"/>
</dictionary>
<string name="targetFramework">IBCarbonFramework</string>
<unsigned_int name="nextObjectID">200</unsigned_int>
</object>

597
src/app/mac/Main.xib Normal file
View file

@ -0,0 +1,597 @@
<?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.Carbon.XIB" version="8.00">
<data>
<int key="IBDocument.SystemTarget">1030</int>
<string key="IBDocument.SystemVersion">15G19009</string>
<string key="IBDocument.InterfaceBuilderVersion">11000</string>
<string key="IBDocument.AppKitVersion">1404.47</string>
<string key="IBDocument.HIToolboxVersion">807.20</string>
<dictionary class="NSMutableDictionary" key="IBDocument.PluginVersions"/>
<array class="NSMutableArray" key="IBDocument.EditedObjectIDs"/>
<array key="IBDocument.PluginDependencies" id="0"/>
<dictionary class="NSMutableDictionary" key="IBDocument.Metadata"/>
<array class="NSMutableArray" key="IBDocument.RootObjects" id="234250886">
<object class="IBHIMenu" id="783341525">
<string key="NSTitle">Untitled</string>
<array class="NSMutableArray" key="NSMenuItems">
<object class="IBHIMenuItem" id="374205419">
<reference key="NSMenu" ref="783341525"/>
<string key="NSTitle">World of Warcraft</string>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<object class="NSImage" key="NSOnImage" id="678796781">
<string key="NSName">NSMenuCheckmark</string>
<int key="NSImageFlags">-1396703232</int>
</object>
<object class="NSImage" key="NSMixedImage" id="788635175">
<string key="NSName">NSMenuMixedState</string>
<int key="NSImageFlags">-1396703232</int>
</object>
<string key="NSAction">submenuAction:</string>
<reference key="NSTarget" ref="273282363"/>
<object class="IBHIMenu" key="NSSubmenu" id="273282363">
<string key="NSTitle">World of Warcraft</string>
<array class="NSMutableArray" key="NSMenuItems">
<object class="IBHIMenuItem" id="962291476">
<reference key="NSMenu" ref="273282363"/>
<string key="NSTitle">About World of Warcraft...</string>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="678796781"/>
<reference key="NSMixedImage" ref="788635175"/>
<string key="title">About World of Warcraft...</string>
<string key="keyEquivalent"/>
<integer value="0" key="disabled"/>
<integer value="0" key="checked"/>
<integer value="0" key="submenuParentChoosable"/>
<integer value="0" key="dynamic"/>
<integer value="0" key="notPreviousAlternate"/>
<integer value="0" key="hidden"/>
<integer value="0" key="ignoreMeta"/>
<integer value="0" key="sectionHeader"/>
<integer value="0" key="customDraw"/>
<integer value="0" key="autoRepeat"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="updateSingleItem"/>
<integer value="0" key="includeInCmdKeyMatching"/>
<integer value="0" key="keyEquivalentModifierMask"/>
<integer value="1633841013" key="command"/>
<nil key="helpTagText"/>
<nil key="helpTagExtendedText"/>
<integer value="0" key="helpTagDisplaySide"/>
</object>
<object class="IBHIMenuItem" id="28259413">
<reference key="NSMenu" ref="273282363"/>
<bool key="NSIsSeparator">YES</bool>
<string key="NSTitle"/>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="678796781"/>
<reference key="NSMixedImage" ref="788635175"/>
<string key="title"/>
<string key="keyEquivalent"/>
<integer value="0" key="disabled"/>
<integer value="0" key="checked"/>
<integer value="0" key="submenuParentChoosable"/>
<integer value="0" key="dynamic"/>
<integer value="0" key="notPreviousAlternate"/>
<integer value="0" key="hidden"/>
<integer value="0" key="ignoreMeta"/>
<integer value="0" key="sectionHeader"/>
<integer value="0" key="customDraw"/>
<integer value="0" key="autoRepeat"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="updateSingleItem"/>
<integer value="0" key="includeInCmdKeyMatching"/>
<integer value="1048576" key="keyEquivalentModifierMask"/>
<integer value="0" key="command"/>
<nil key="helpTagText"/>
<nil key="helpTagExtendedText"/>
<integer value="0" key="helpTagDisplaySide"/>
</object>
<object class="IBHIMenuItem" id="716945557">
<reference key="NSMenu" ref="273282363"/>
<string key="NSTitle">Switch To Full Screen Mode</string>
<string key="NSKeyEquiv">m</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="678796781"/>
<reference key="NSMixedImage" ref="788635175"/>
<string key="title">Switch To Full Screen Mode</string>
<string key="keyEquivalent">m</string>
<integer value="0" key="disabled"/>
<integer value="0" key="checked"/>
<integer value="0" key="submenuParentChoosable"/>
<integer value="0" key="dynamic"/>
<integer value="0" key="notPreviousAlternate"/>
<integer value="0" key="hidden"/>
<integer value="0" key="ignoreMeta"/>
<integer value="0" key="sectionHeader"/>
<integer value="0" key="customDraw"/>
<integer value="0" key="autoRepeat"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="updateSingleItem"/>
<integer value="0" key="includeInCmdKeyMatching"/>
<integer value="1048576" key="keyEquivalentModifierMask"/>
<integer value="1182100588" key="command"/>
<nil key="helpTagText"/>
<nil key="helpTagExtendedText"/>
<integer value="0" key="helpTagDisplaySide"/>
</object>
</array>
<string key="name">_NSAppleMenu</string>
<string key="title">World of Warcraft</string>
<integer value="0" key="menuID"/>
<integer value="0" key="excludesMarkColumn"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="usePencilGlyph"/>
<integer value="0" key="hidden"/>
<integer value="0" key="condenseSeparators"/>
</object>
<string key="title">World of Warcraft</string>
<string key="keyEquivalent"/>
<integer value="0" key="disabled"/>
<integer value="0" key="checked"/>
<integer value="0" key="submenuParentChoosable"/>
<integer value="0" key="dynamic"/>
<integer value="0" key="notPreviousAlternate"/>
<integer value="0" key="hidden"/>
<integer value="0" key="ignoreMeta"/>
<integer value="0" key="sectionHeader"/>
<integer value="0" key="customDraw"/>
<integer value="0" key="autoRepeat"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="updateSingleItem"/>
<integer value="0" key="includeInCmdKeyMatching"/>
<integer value="1048576" key="keyEquivalentModifierMask"/>
<integer value="0" key="command"/>
<nil key="helpTagText"/>
<nil key="helpTagExtendedText"/>
<integer value="0" key="helpTagDisplaySide"/>
</object>
<object class="IBHIMenuItem" id="832277564">
<reference key="NSMenu" ref="783341525"/>
<string key="NSTitle">Edit</string>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="678796781"/>
<reference key="NSMixedImage" ref="788635175"/>
<string key="NSAction">submenuAction:</string>
<reference key="NSTarget" ref="775244329"/>
<object class="IBHIMenu" key="NSSubmenu" id="775244329">
<string key="NSTitle">Edit</string>
<array class="NSMutableArray" key="NSMenuItems">
<object class="IBHIMenuItem" id="525595591">
<reference key="NSMenu" ref="775244329"/>
<string key="NSTitle">Undo</string>
<string key="NSKeyEquiv">z</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="678796781"/>
<reference key="NSMixedImage" ref="788635175"/>
<string key="title">Undo</string>
<string key="keyEquivalent">z</string>
<integer value="0" key="disabled"/>
<integer value="0" key="checked"/>
<integer value="0" key="submenuParentChoosable"/>
<integer value="0" key="dynamic"/>
<integer value="0" key="notPreviousAlternate"/>
<integer value="0" key="hidden"/>
<integer value="0" key="ignoreMeta"/>
<integer value="0" key="sectionHeader"/>
<integer value="0" key="customDraw"/>
<integer value="0" key="autoRepeat"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="updateSingleItem"/>
<integer value="0" key="includeInCmdKeyMatching"/>
<integer value="1048576" key="keyEquivalentModifierMask"/>
<integer value="1970168943" key="command"/>
<nil key="helpTagText"/>
<nil key="helpTagExtendedText"/>
<integer value="0" key="helpTagDisplaySide"/>
</object>
<object class="IBHIMenuItem" id="348288318">
<reference key="NSMenu" ref="775244329"/>
<bool key="NSIsSeparator">YES</bool>
<string key="NSTitle"/>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="678796781"/>
<reference key="NSMixedImage" ref="788635175"/>
<string key="title"/>
<string key="keyEquivalent"/>
<integer value="0" key="disabled"/>
<integer value="0" key="checked"/>
<integer value="0" key="submenuParentChoosable"/>
<integer value="0" key="dynamic"/>
<integer value="0" key="notPreviousAlternate"/>
<integer value="0" key="hidden"/>
<integer value="0" key="ignoreMeta"/>
<integer value="0" key="sectionHeader"/>
<integer value="0" key="customDraw"/>
<integer value="0" key="autoRepeat"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="updateSingleItem"/>
<integer value="0" key="includeInCmdKeyMatching"/>
<integer value="1048576" key="keyEquivalentModifierMask"/>
<integer value="0" key="command"/>
<nil key="helpTagText"/>
<nil key="helpTagExtendedText"/>
<integer value="0" key="helpTagDisplaySide"/>
</object>
<object class="IBHIMenuItem" id="504943467">
<reference key="NSMenu" ref="775244329"/>
<string key="NSTitle">Cut</string>
<string key="NSKeyEquiv">x</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="678796781"/>
<reference key="NSMixedImage" ref="788635175"/>
<string key="title">Cut</string>
<string key="keyEquivalent">x</string>
<integer value="0" key="disabled"/>
<integer value="0" key="checked"/>
<integer value="0" key="submenuParentChoosable"/>
<integer value="0" key="dynamic"/>
<integer value="0" key="notPreviousAlternate"/>
<integer value="0" key="hidden"/>
<integer value="0" key="ignoreMeta"/>
<integer value="0" key="sectionHeader"/>
<integer value="0" key="customDraw"/>
<integer value="0" key="autoRepeat"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="updateSingleItem"/>
<integer value="0" key="includeInCmdKeyMatching"/>
<integer value="1048576" key="keyEquivalentModifierMask"/>
<integer value="1668641824" key="command"/>
<nil key="helpTagText"/>
<nil key="helpTagExtendedText"/>
<integer value="0" key="helpTagDisplaySide"/>
</object>
<object class="IBHIMenuItem" id="1036249919">
<reference key="NSMenu" ref="775244329"/>
<string key="NSTitle">Copy</string>
<string key="NSKeyEquiv">c</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="678796781"/>
<reference key="NSMixedImage" ref="788635175"/>
<string key="title">Copy</string>
<string key="keyEquivalent">c</string>
<integer value="0" key="disabled"/>
<integer value="0" key="checked"/>
<integer value="0" key="submenuParentChoosable"/>
<integer value="0" key="dynamic"/>
<integer value="0" key="notPreviousAlternate"/>
<integer value="0" key="hidden"/>
<integer value="0" key="ignoreMeta"/>
<integer value="0" key="sectionHeader"/>
<integer value="0" key="customDraw"/>
<integer value="0" key="autoRepeat"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="updateSingleItem"/>
<integer value="0" key="includeInCmdKeyMatching"/>
<integer value="1048576" key="keyEquivalentModifierMask"/>
<integer value="1668247673" key="command"/>
<nil key="helpTagText"/>
<nil key="helpTagExtendedText"/>
<integer value="0" key="helpTagDisplaySide"/>
</object>
<object class="IBHIMenuItem" id="780439468">
<reference key="NSMenu" ref="775244329"/>
<string key="NSTitle">Paste</string>
<string key="NSKeyEquiv">v</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="678796781"/>
<reference key="NSMixedImage" ref="788635175"/>
<string key="title">Paste</string>
<string key="keyEquivalent">v</string>
<integer value="0" key="disabled"/>
<integer value="0" key="checked"/>
<integer value="0" key="submenuParentChoosable"/>
<integer value="0" key="dynamic"/>
<integer value="0" key="notPreviousAlternate"/>
<integer value="0" key="hidden"/>
<integer value="0" key="ignoreMeta"/>
<integer value="0" key="sectionHeader"/>
<integer value="0" key="customDraw"/>
<integer value="0" key="autoRepeat"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="updateSingleItem"/>
<integer value="0" key="includeInCmdKeyMatching"/>
<integer value="1048576" key="keyEquivalentModifierMask"/>
<integer value="1885434740" key="command"/>
<nil key="helpTagText"/>
<nil key="helpTagExtendedText"/>
<integer value="0" key="helpTagDisplaySide"/>
</object>
<object class="IBHIMenuItem" id="270786867">
<reference key="NSMenu" ref="775244329"/>
<string key="NSTitle">Select All</string>
<string key="NSKeyEquiv">a</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="678796781"/>
<reference key="NSMixedImage" ref="788635175"/>
<string key="title">Select All</string>
<string key="keyEquivalent">a</string>
<integer value="0" key="disabled"/>
<integer value="0" key="checked"/>
<integer value="0" key="submenuParentChoosable"/>
<integer value="0" key="dynamic"/>
<integer value="0" key="notPreviousAlternate"/>
<integer value="0" key="hidden"/>
<integer value="0" key="ignoreMeta"/>
<integer value="0" key="sectionHeader"/>
<integer value="0" key="customDraw"/>
<integer value="0" key="autoRepeat"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="updateSingleItem"/>
<integer value="0" key="includeInCmdKeyMatching"/>
<integer value="1048576" key="keyEquivalentModifierMask"/>
<integer value="1935764588" key="command"/>
<nil key="helpTagText"/>
<nil key="helpTagExtendedText"/>
<integer value="0" key="helpTagDisplaySide"/>
</object>
</array>
<string key="title">Edit</string>
<integer value="128" key="menuID"/>
<integer value="0" key="excludesMarkColumn"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="usePencilGlyph"/>
<integer value="0" key="hidden"/>
<integer value="0" key="condenseSeparators"/>
</object>
<string key="title">Edit</string>
<string key="keyEquivalent"/>
<integer value="0" key="disabled"/>
<integer value="0" key="checked"/>
<integer value="0" key="submenuParentChoosable"/>
<integer value="0" key="dynamic"/>
<integer value="0" key="notPreviousAlternate"/>
<integer value="0" key="hidden"/>
<integer value="0" key="ignoreMeta"/>
<integer value="0" key="sectionHeader"/>
<integer value="0" key="customDraw"/>
<integer value="0" key="autoRepeat"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="updateSingleItem"/>
<integer value="0" key="includeInCmdKeyMatching"/>
<integer value="1048576" key="keyEquivalentModifierMask"/>
<integer value="0" key="command"/>
<nil key="helpTagText"/>
<nil key="helpTagExtendedText"/>
<integer value="0" key="helpTagDisplaySide"/>
</object>
</array>
<string key="name">_NSMainMenu</string>
<string key="title">Untitled</string>
<integer value="0" key="menuID"/>
<integer value="0" key="excludesMarkColumn"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="usePencilGlyph"/>
<integer value="0" key="hidden"/>
<integer value="0" key="condenseSeparators"/>
</object>
<object class="IBHIMenu" id="231014827">
<string key="NSTitle">Batch Viewer</string>
<array class="NSMutableArray" key="NSMenuItems">
<object class="IBHIMenuItem" id="177821328">
<reference key="NSMenu" ref="231014827"/>
<string key="NSTitle">Show BatchViewer</string>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="678796781"/>
<reference key="NSMixedImage" ref="788635175"/>
<string key="title">Show BatchViewer</string>
<string key="keyEquivalent"/>
<integer value="0" key="disabled"/>
<integer value="0" key="checked"/>
<integer value="0" key="submenuParentChoosable"/>
<integer value="0" key="dynamic"/>
<integer value="1" key="notPreviousAlternate"/>
<integer value="0" key="hidden"/>
<integer value="0" key="ignoreMeta"/>
<integer value="0" key="sectionHeader"/>
<integer value="0" key="customDraw"/>
<integer value="0" key="autoRepeat"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="updateSingleItem"/>
<integer value="0" key="includeInCmdKeyMatching"/>
<integer value="1048576" key="keyEquivalentModifierMask"/>
<integer value="1112962930" key="command"/>
<nil key="helpTagText"/>
<nil key="helpTagExtendedText"/>
<integer value="0" key="helpTagDisplaySide"/>
</object>
<object class="IBHIMenuItem" id="443792299">
<reference key="NSMenu" ref="231014827"/>
<string key="NSTitle">Show GL Layer Setup</string>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="678796781"/>
<reference key="NSMixedImage" ref="788635175"/>
<string key="title">Show GL Layer Setup</string>
<string key="keyEquivalent"/>
<integer value="0" key="disabled"/>
<integer value="0" key="checked"/>
<integer value="0" key="submenuParentChoosable"/>
<integer value="0" key="dynamic"/>
<integer value="1" key="notPreviousAlternate"/>
<integer value="0" key="hidden"/>
<integer value="0" key="ignoreMeta"/>
<integer value="0" key="sectionHeader"/>
<integer value="0" key="customDraw"/>
<integer value="0" key="autoRepeat"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="updateSingleItem"/>
<integer value="0" key="includeInCmdKeyMatching"/>
<integer value="1048576" key="keyEquivalentModifierMask"/>
<integer value="1196182643" key="command"/>
<nil key="helpTagText"/>
<nil key="helpTagExtendedText"/>
<integer value="0" key="helpTagDisplaySide"/>
</object>
</array>
<string key="title">Batch Viewer</string>
<integer value="0" key="menuID"/>
<integer value="0" key="excludesMarkColumn"/>
<integer value="0" key="autoDisable"/>
<integer value="0" key="usePencilGlyph"/>
<integer value="0" key="hidden"/>
<integer value="0" key="condenseSeparators"/>
</object>
</array>
<object class="IBObjectContainer" key="IBDocument.Objects">
<array class="NSMutableArray" key="connectionRecords"/>
<object class="IBMutableOrderedSet" key="objectRecords">
<array key="orderedObjects">
<object class="IBObjectRecord">
<int key="objectID">0</int>
<reference key="object" ref="0"/>
<reference key="children" ref="234250886"/>
<nil key="parent"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">29</int>
<reference key="object" ref="783341525"/>
<array class="NSMutableArray" key="children">
<reference ref="832277564"/>
<reference ref="374205419"/>
</array>
<reference key="parent" ref="0"/>
<string key="objectName">MenuBar</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">197</int>
<reference key="object" ref="231014827"/>
<array class="NSMutableArray" key="children">
<reference ref="177821328"/>
<reference ref="443792299"/>
</array>
<reference key="parent" ref="0"/>
<string key="objectName">BatchViewerMenu</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">152</int>
<reference key="object" ref="832277564"/>
<array class="NSMutableArray" key="children">
<reference ref="775244329"/>
</array>
<reference key="parent" ref="783341525"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">182</int>
<reference key="object" ref="374205419"/>
<array class="NSMutableArray" key="children">
<reference ref="273282363"/>
</array>
<reference key="parent" ref="783341525"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">198</int>
<reference key="object" ref="177821328"/>
<reference key="parent" ref="231014827"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">199</int>
<reference key="object" ref="443792299"/>
<reference key="parent" ref="231014827"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">147</int>
<reference key="object" ref="775244329"/>
<array class="NSMutableArray" key="children">
<reference ref="780439468"/>
<reference ref="348288318"/>
<reference ref="1036249919"/>
<reference ref="525595591"/>
<reference ref="504943467"/>
<reference ref="270786867"/>
</array>
<reference key="parent" ref="832277564"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">181</int>
<reference key="object" ref="273282363"/>
<array class="NSMutableArray" key="children">
<reference ref="962291476"/>
<reference ref="716945557"/>
<reference ref="28259413"/>
</array>
<reference key="parent" ref="374205419"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">144</int>
<reference key="object" ref="780439468"/>
<reference key="parent" ref="775244329"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">142</int>
<reference key="object" ref="348288318"/>
<reference key="parent" ref="775244329"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">149</int>
<reference key="object" ref="1036249919"/>
<reference key="parent" ref="775244329"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">141</int>
<reference key="object" ref="525595591"/>
<reference key="parent" ref="775244329"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">143</int>
<reference key="object" ref="504943467"/>
<reference key="parent" ref="775244329"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">148</int>
<reference key="object" ref="270786867"/>
<reference key="parent" ref="775244329"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">183</int>
<reference key="object" ref="962291476"/>
<reference key="parent" ref="273282363"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">187</int>
<reference key="object" ref="716945557"/>
<reference key="parent" ref="273282363"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">186</int>
<reference key="object" ref="28259413"/>
<reference key="parent" ref="273282363"/>
</object>
</array>
</object>
<dictionary class="NSMutableDictionary" key="flattenedProperties"/>
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
<nil key="activeLocalization"/>
<dictionary class="NSMutableDictionary" key="localizations"/>
<nil key="sourceID"/>
<int key="maxID">200</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes"/>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.TargetRuntimeIdentifier">IBCarbonFramework</string>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
<string key="NS.key.0">com.apple.InterfaceBuilder.CarbonPlugin.macosx</string>
<integer value="1030" key="NS.object.0"/>
</object>
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
<string key="IBDocument.LastKnownRelativeProjectPath">../../../WoW.xcodeproj</string>
<int key="IBDocument.defaultPropertyAccessControl">3</int>
</data>
</archive>

19
src/app/mac/MainApp.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef APP_MAC_MAIN_APP_H
#define APP_MAC_MAIN_APP_H
#include "app/mac/MacClient.h"
#include <AppKit/AppKit.h>
#include <Foundation/Foundation.h>
@interface MainApp : NSObject
@property (retain) NSTimer* m_pollTimer;
@property bool isPolling;
@property (retain) IBOutlet NSMenuItem* captureFrameMenuItem;
@property (retain) IBOutlet NSMenuItem* showBatchViewerMenuItem;
@property (retain) IBOutlet NSMenuItem* showGLLayerSetupMenuItem;
@end
#endif

90
src/app/mac/MainApp.mm Normal file
View file

@ -0,0 +1,90 @@
#include "app/mac/MainApp.h"
#include "event/Event.hpp"
#include "event/Scheduler.hpp"
#include "os/Compat.hpp"
@implementation MainApp
+ (void)initialize {
[[NSUserDefaults standardUserDefaults]
registerDefaults: [NSDictionary
dictionaryWithObject: @"YES"
forKey: @"NSDisabledCharacterPaletteMenuItem"]];
[NSApp
setActivationPolicy: NSApplicationActivationPolicyRegular];
}
- (void)applicationDidFinishLaunching:(id)a1 {
self.m_pollTimer = [NSTimer
timerWithTimeInterval: 0.0001
target: self
selector: @selector(poll:)
userInfo: nil
repeats: true];
[[NSRunLoop currentRunLoop]
addTimer: self.m_pollTimer
forMode: NSDefaultRunLoopMode];
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
// TODO
// OsQueuePut(5, 0, 0, 0, 0);
return NSTerminateCancel;
}
- (void)captureFrame:(id)a1 {
}
- (void)copy:(id)a3 {
MacClient::PostClipboardKeyEvents(MacClient::ClipboardCopy);
}
- (void)cut:(id)a3 {
MacClient::PostClipboardKeyEvents(MacClient::ClipboardCut);
}
- (void)paste:(id)a3 {
MacClient::PostClipboardKeyEvents(MacClient::ClipboardPaste);
}
- (void)poll:(id)a1 {
if (!Event::s_shouldLoopTerminate) {
Event::s_shouldLoopTerminate = SchedulerMainProcess();
if (Event::s_shouldLoopTerminate) {
[self.m_pollTimer invalidate];
self.m_pollTimer = nil;
[NSApp stop:self];
[NSApp
postEvent:
[NSEvent
otherEventWithType: NSEventTypeApplicationDefined
location: NSMakePoint(0, 0)
modifierFlags: 0
timestamp: 0
windowNumber: 0
context: 0
subtype: 0
data1: 0
data2: 0]
atStart: 0];
}
}
}
- (void)showBatchViewer:(id)a1 {
}
- (void)showGLLayerSetup:(id)a1 {
}
- (void)toggleFullscreenMode:(id)a1 {
// TODO
}
@end

901
src/app/mac/MainMenu.nib/designable.nib generated Executable file
View file

@ -0,0 +1,901 @@
<?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.03">
<data>
<int key="IBDocument.SystemTarget">1030</int>
<string key="IBDocument.SystemVersion">9J61</string>
<string key="IBDocument.InterfaceBuilderVersion">677</string>
<string key="IBDocument.AppKitVersion">949.46</string>
<string key="IBDocument.HIToolboxVersion">353.00</string>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
<integer value="24"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
</object>
<object class="NSMutableDictionary" key="IBDocument.Metadata">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSCustomObject" id="1021">
<string key="NSClassName">NSApplication</string>
</object>
<object class="NSCustomObject" id="1014">
<string key="NSClassName">FirstResponder</string>
</object>
<object class="NSCustomObject" id="1050">
<string key="NSClassName">NSApplication</string>
</object>
<object class="NSMenu" id="649796088">
<string key="NSTitle">AMainMenu</string>
<object class="NSMutableArray" key="NSMenuItems">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMenuItem" id="694149608">
<reference key="NSMenu" ref="649796088"/>
<string key="NSTitle">World of Warcraft</string>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<object class="NSCustomResource" key="NSOnImage" id="229763992">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">NSMenuCheckmark</string>
</object>
<object class="NSCustomResource" key="NSMixedImage" id="909111550">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">NSMenuMixedState</string>
</object>
<string key="NSAction">submenuAction:</string>
<object class="NSMenu" key="NSSubmenu" id="110575045">
<string key="NSTitle">World of Warcraft</string>
<object class="NSMutableArray" key="NSMenuItems">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMenuItem" id="238522557">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">MENU_ABOUT</string>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="304266470">
<reference key="NSMenu" ref="110575045"/>
<bool key="NSIsDisabled">YES</bool>
<bool key="NSIsSeparator">YES</bool>
<string key="NSTitle"/>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="41361050">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">MENU_SWITCH_TO_FULLSCREEN</string>
<string key="NSKeyEquiv">m</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="294290359">
<reference key="NSMenu" ref="110575045"/>
<bool key="NSIsDisabled">YES</bool>
<bool key="NSIsSeparator">YES</bool>
<string key="NSTitle"/>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="755159360">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">MENU_HIDE</string>
<string key="NSKeyEquiv">h</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="342932134">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">MENU_HIDE_OTHERS</string>
<string key="NSKeyEquiv">h</string>
<int key="NSKeyEquivModMask">1572864</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="908899353">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">MENU_SHOW_ALL</string>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="1056857174">
<reference key="NSMenu" ref="110575045"/>
<bool key="NSIsDisabled">YES</bool>
<bool key="NSIsSeparator">YES</bool>
<string key="NSTitle"/>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="632727374">
<reference key="NSMenu" ref="110575045"/>
<string key="NSTitle">MENU_QUIT</string>
<string key="NSKeyEquiv">q</string>
<int key="NSKeyEquivModMask">1572864</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
</object>
<string key="NSName">_NSAppleMenu</string>
</object>
</object>
<object class="NSMenuItem" id="952259628">
<reference key="NSMenu" ref="649796088"/>
<string key="NSTitle">MENU_EDIT</string>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
<string key="NSAction">submenuAction:</string>
<object class="NSMenu" key="NSSubmenu" id="789758025">
<string key="NSTitle">MENU_EDIT</string>
<object class="NSMutableArray" key="NSMenuItems">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMenuItem" id="1058277027">
<reference key="NSMenu" ref="789758025"/>
<string key="NSTitle">MENU_UNDO</string>
<string key="NSKeyEquiv">z</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="1040322652">
<reference key="NSMenu" ref="789758025"/>
<bool key="NSIsDisabled">YES</bool>
<bool key="NSIsSeparator">YES</bool>
<string key="NSTitle"/>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="296257095">
<reference key="NSMenu" ref="789758025"/>
<string key="NSTitle">MENU_EDIT_CUT</string>
<string key="NSKeyEquiv">x</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="860595796">
<reference key="NSMenu" ref="789758025"/>
<string key="NSTitle">MENU_EDIT_COPY</string>
<string key="NSKeyEquiv">c</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="29853731">
<reference key="NSMenu" ref="789758025"/>
<string key="NSTitle">MENU_EDIT_PASTE</string>
<string key="NSKeyEquiv">v</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="583158037">
<reference key="NSMenu" ref="789758025"/>
<string key="NSTitle">MENU_EDIT_SELECT_ALL</string>
<string key="NSKeyEquiv">a</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
</object>
</object>
</object>
<object class="NSMenuItem" id="713487014">
<reference key="NSMenu" ref="649796088"/>
<string key="NSTitle">MENU_WINDOW</string>
<string key="NSKeyEquiv"/>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
<string key="NSAction">submenuAction:</string>
<object class="NSMenu" key="NSSubmenu" id="835318025">
<string key="NSTitle">MENU_WINDOW</string>
<object class="NSMutableArray" key="NSMenuItems">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMenuItem" id="839061908">
<reference key="NSMenu" ref="835318025"/>
<string key="NSTitle">Show Batch Viewer</string>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="825097611">
<reference key="NSMenu" ref="835318025"/>
<string key="NSTitle">Show GL Layer Setup</string>
<string key="NSKeyEquiv"/>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="891014876">
<reference key="NSMenu" ref="835318025"/>
<string key="NSTitle">Capture Frame</string>
<string key="NSKeyEquiv">r</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
</object>
<string key="NSName">_NSWindowsMenu</string>
</object>
</object>
</object>
<string key="NSName">_NSMainMenu</string>
</object>
<object class="NSCustomObject" id="106825686">
<string key="NSClassName">MainApp</string>
</object>
</object>
<object class="IBObjectContainer" key="IBDocument.Objects">
<object class="NSMutableArray" key="connectionRecords">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">orderFrontStandardAboutPanel:</string>
<reference key="source" ref="1021"/>
<reference key="destination" ref="238522557"/>
</object>
<int key="connectionID">142</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">undo:</string>
<reference key="source" ref="1014"/>
<reference key="destination" ref="1058277027"/>
</object>
<int key="connectionID">223</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">copy:</string>
<reference key="source" ref="1014"/>
<reference key="destination" ref="860595796"/>
</object>
<int key="connectionID">224</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">paste:</string>
<reference key="source" ref="1014"/>
<reference key="destination" ref="29853731"/>
</object>
<int key="connectionID">226</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">cut:</string>
<reference key="source" ref="1014"/>
<reference key="destination" ref="296257095"/>
</object>
<int key="connectionID">228</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">selectAll:</string>
<reference key="source" ref="1014"/>
<reference key="destination" ref="583158037"/>
</object>
<int key="connectionID">232</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">hide:</string>
<reference key="source" ref="1014"/>
<reference key="destination" ref="755159360"/>
</object>
<int key="connectionID">367</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">hideOtherApplications:</string>
<reference key="source" ref="1014"/>
<reference key="destination" ref="342932134"/>
</object>
<int key="connectionID">368</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">terminate:</string>
<reference key="source" ref="1014"/>
<reference key="destination" ref="632727374"/>
</object>
<int key="connectionID">369</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">unhideAllApplications:</string>
<reference key="source" ref="1014"/>
<reference key="destination" ref="908899353"/>
</object>
<int key="connectionID">370</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">delegate</string>
<reference key="source" ref="1021"/>
<reference key="destination" ref="106825686"/>
</object>
<int key="connectionID">452</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">showGLLayerSetup:</string>
<reference key="source" ref="106825686"/>
<reference key="destination" ref="825097611"/>
</object>
<int key="connectionID">454</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">showBatchViewer:</string>
<reference key="source" ref="106825686"/>
<reference key="destination" ref="839061908"/>
</object>
<int key="connectionID">455</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">showBatchViewerMenuItem</string>
<reference key="source" ref="106825686"/>
<reference key="destination" ref="839061908"/>
</object>
<int key="connectionID">456</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">showGLLayerSetupMenuItem</string>
<reference key="source" ref="106825686"/>
<reference key="destination" ref="825097611"/>
</object>
<int key="connectionID">457</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">toggleFullscreenMode:</string>
<reference key="source" ref="106825686"/>
<reference key="destination" ref="41361050"/>
</object>
<int key="connectionID">460</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">captureFrameMenuItem</string>
<reference key="source" ref="106825686"/>
<reference key="destination" ref="891014876"/>
</object>
<int key="connectionID">462</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">captureFrame:</string>
<reference key="source" ref="106825686"/>
<reference key="destination" ref="891014876"/>
</object>
<int key="connectionID">463</int>
</object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBObjectRecord">
<int key="objectID">0</int>
<object class="NSArray" key="object" id="1049">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<reference key="children" ref="1048"/>
<nil key="parent"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">-2</int>
<reference key="object" ref="1021"/>
<reference key="parent" ref="1049"/>
<string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-1</int>
<reference key="object" ref="1014"/>
<reference key="parent" ref="1049"/>
<string key="objectName">First Responder</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-3</int>
<reference key="object" ref="1050"/>
<reference key="parent" ref="1049"/>
<string key="objectName">Application</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">29</int>
<reference key="object" ref="649796088"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="713487014"/>
<reference ref="694149608"/>
<reference ref="952259628"/>
</object>
<reference key="parent" ref="1049"/>
<string key="objectName">Main Menu</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">19</int>
<reference key="object" ref="713487014"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="835318025"/>
</object>
<reference key="parent" ref="649796088"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">56</int>
<reference key="object" ref="694149608"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="110575045"/>
</object>
<reference key="parent" ref="649796088"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">217</int>
<reference key="object" ref="952259628"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="789758025"/>
</object>
<reference key="parent" ref="649796088"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">205</int>
<reference key="object" ref="789758025"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="583158037"/>
<reference ref="1058277027"/>
<reference ref="296257095"/>
<reference ref="29853731"/>
<reference ref="860595796"/>
<reference ref="1040322652"/>
</object>
<reference key="parent" ref="952259628"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">198</int>
<reference key="object" ref="583158037"/>
<reference key="parent" ref="789758025"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">207</int>
<reference key="object" ref="1058277027"/>
<reference key="parent" ref="789758025"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">199</int>
<reference key="object" ref="296257095"/>
<reference key="parent" ref="789758025"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">203</int>
<reference key="object" ref="29853731"/>
<reference key="parent" ref="789758025"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">197</int>
<reference key="object" ref="860595796"/>
<reference key="parent" ref="789758025"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">206</int>
<reference key="object" ref="1040322652"/>
<reference key="parent" ref="789758025"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">57</int>
<reference key="object" ref="110575045"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="238522557"/>
<reference ref="755159360"/>
<reference ref="908899353"/>
<reference ref="632727374"/>
<reference ref="304266470"/>
<reference ref="1056857174"/>
<reference ref="342932134"/>
<reference ref="41361050"/>
<reference ref="294290359"/>
</object>
<reference key="parent" ref="694149608"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">58</int>
<reference key="object" ref="238522557"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">134</int>
<reference key="object" ref="755159360"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">150</int>
<reference key="object" ref="908899353"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">136</int>
<reference key="object" ref="632727374"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">236</int>
<reference key="object" ref="304266470"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">149</int>
<reference key="object" ref="1056857174"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">145</int>
<reference key="object" ref="342932134"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">24</int>
<reference key="object" ref="835318025"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="839061908"/>
<reference ref="825097611"/>
<reference ref="891014876"/>
</object>
<reference key="parent" ref="713487014"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">449</int>
<reference key="object" ref="839061908"/>
<reference key="parent" ref="835318025"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">450</int>
<reference key="object" ref="825097611"/>
<reference key="parent" ref="835318025"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">451</int>
<reference key="object" ref="106825686"/>
<reference key="parent" ref="1049"/>
<string key="objectName">MainApp</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">458</int>
<reference key="object" ref="41361050"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">459</int>
<reference key="object" ref="294290359"/>
<reference key="parent" ref="110575045"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">461</int>
<reference key="object" ref="891014876"/>
<reference key="parent" ref="835318025"/>
</object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMutableArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>-1.IBPluginDependency</string>
<string>-2.IBPluginDependency</string>
<string>-3.IBPluginDependency</string>
<string>134.IBPluginDependency</string>
<string>134.ImportedFromIB2</string>
<string>136.IBPluginDependency</string>
<string>136.ImportedFromIB2</string>
<string>145.IBPluginDependency</string>
<string>145.ImportedFromIB2</string>
<string>149.IBPluginDependency</string>
<string>149.ImportedFromIB2</string>
<string>150.IBPluginDependency</string>
<string>150.ImportedFromIB2</string>
<string>19.IBPluginDependency</string>
<string>19.ImportedFromIB2</string>
<string>197.IBPluginDependency</string>
<string>197.ImportedFromIB2</string>
<string>198.IBPluginDependency</string>
<string>198.ImportedFromIB2</string>
<string>199.IBPluginDependency</string>
<string>199.ImportedFromIB2</string>
<string>203.IBPluginDependency</string>
<string>203.ImportedFromIB2</string>
<string>205.IBEditorWindowLastContentRect</string>
<string>205.IBPluginDependency</string>
<string>205.ImportedFromIB2</string>
<string>205.editorWindowContentRectSynchronizationRect</string>
<string>206.IBPluginDependency</string>
<string>206.ImportedFromIB2</string>
<string>207.IBPluginDependency</string>
<string>207.ImportedFromIB2</string>
<string>217.IBPluginDependency</string>
<string>217.ImportedFromIB2</string>
<string>236.IBPluginDependency</string>
<string>236.ImportedFromIB2</string>
<string>24.IBEditorWindowLastContentRect</string>
<string>24.IBPluginDependency</string>
<string>24.ImportedFromIB2</string>
<string>24.editorWindowContentRectSynchronizationRect</string>
<string>29.IBEditorWindowLastContentRect</string>
<string>29.IBPluginDependency</string>
<string>29.ImportedFromIB2</string>
<string>29.WindowOrigin</string>
<string>29.editorWindowContentRectSynchronizationRect</string>
<string>449.IBPluginDependency</string>
<string>449.ImportedFromIB2</string>
<string>450.IBPluginDependency</string>
<string>450.ImportedFromIB2</string>
<string>451.IBPluginDependency</string>
<string>458.IBPluginDependency</string>
<string>458.ImportedFromIB2</string>
<string>459.IBPluginDependency</string>
<string>459.ImportedFromIB2</string>
<string>461.IBPluginDependency</string>
<string>56.IBPluginDependency</string>
<string>56.ImportedFromIB2</string>
<string>57.IBEditorWindowLastContentRect</string>
<string>57.IBPluginDependency</string>
<string>57.ImportedFromIB2</string>
<string>57.editorWindowContentRectSynchronizationRect</string>
<string>58.IBPluginDependency</string>
<string>58.ImportedFromIB2</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<integer value="1" id="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>{{1422, 1180}, {243, 113}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>{{197, 734}, {243, 243}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>{{1548, 966}, {218, 63}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>{{525, 802}, {197, 73}}</string>
<string>{{1295, 1029}, {390, 20}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>{74, 862}</string>
<string>{{11, 977}, {478, 20}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES" id="5"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="5"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="5"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>{{49, 388}, {312, 153}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>{{23, 794}, {245, 183}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
</object>
</object>
<object class="NSMutableDictionary" key="unlocalizedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<nil key="activeLocalization"/>
<object class="NSMutableDictionary" key="localizations">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<nil key="sourceID"/>
<int key="maxID">463</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBPartialClassDescription">
<string key="className">MainApp</string>
<string key="superclassName">NSObject</string>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMutableArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>captureFrame:</string>
<string>cut:</string>
<string>paste:</string>
<string>selectAll:</string>
<string>showBatchViewer:</string>
<string>showGLLayerSetup:</string>
<string>toggleFullscreenMode:</string>
<string>undo:</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>id</string>
<string>id</string>
<string>id</string>
<string>id</string>
<string>id</string>
<string>id</string>
<string>id</string>
<string>id</string>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMutableArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>captureFrameMenuItem</string>
<string>showBatchViewerMenuItem</string>
<string>showGLLayerSetupMenuItem</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>NSMenuItem</string>
<string>NSMenuItem</string>
<string>NSMenuItem</string>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">Source/MainApp.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">MainApp</string>
<string key="superclassName">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">NSObject</string>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMutableArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>didAdjustSubviews:</string>
<string>willAdjustSubviews:</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>RBSplitView</string>
<string>RBSplitView</string>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="35014534">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">../../../Engine/Source/Gx/CGxDeviceGLL/GLLayer/RBSplitView.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">RBSplitSubview</string>
<string key="superclassName">NSView</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">../../../Engine/Source/Gx/CGxDeviceGLL/GLLayer/RBSplitSubview.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">RBSplitSubview</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="60681676">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">../../../Engine/Source/Gx/CGxDeviceGLL/GLLayer/RBSplitViewPrivateDefines.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">RBSplitView</string>
<string key="superclassName">RBSplitSubview</string>
<object class="NSMutableDictionary" key="outlets">
<string key="NS.key.0">delegate</string>
<string key="NS.object.0">id</string>
</object>
<reference key="sourceIdentifier" ref="35014534"/>
</object>
<object class="IBPartialClassDescription">
<string key="className">RBSplitView</string>
<reference key="sourceIdentifier" ref="60681676"/>
</object>
<object class="IBPartialClassDescription">
<string key="className">StackTableView</string>
<string key="superclassName">NSTableView</string>
<object class="NSMutableDictionary" key="actions">
<string key="NS.key.0">copy:</string>
<string key="NS.object.0">id</string>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">../../../Engine/Source/Gx/CGxDeviceGLL/GLLayer/StackCrawlViewer.h</string>
</object>
</object>
</object>
</object>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.LastKnownRelativeProjectPath">../../WoW.xcodeproj</string>
<int key="IBDocument.defaultPropertyAccessControl">3</int>
</data>
</archive>

BIN
src/app/mac/MainMenu.nib/keyedobjects.nib generated Executable file

Binary file not shown.

126
src/app/mac/MainMenu.xib Normal file
View file

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="15G19009" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment version="1030" identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="451" id="452"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application"/>
<menu title="AMainMenu" systemMenu="main" id="29" userLabel="Main Menu">
<items>
<menuItem title="World of Warcraft" id="56">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="World of Warcraft" systemMenu="apple" id="57">
<items>
<menuItem title="MENU_ABOUT" id="58">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="236"/>
<menuItem title="MENU_SWITCH_TO_FULLSCREEN" keyEquivalent="m" id="458">
<connections>
<action selector="toggleFullscreenMode:" target="451" id="460"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="459"/>
<menuItem title="MENU_HIDE" keyEquivalent="h" id="134">
<connections>
<action selector="hide:" target="-1" id="367"/>
</connections>
</menuItem>
<menuItem title="MENU_HIDE_OTHERS" keyEquivalent="h" id="145">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="368"/>
</connections>
</menuItem>
<menuItem title="MENU_SHOW_ALL" id="150">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="370"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="149"/>
<menuItem title="MENU_QUIT" keyEquivalent="q" id="136">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="terminate:" target="-1" id="369"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="MENU_EDIT" id="217">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="MENU_EDIT" id="205">
<items>
<menuItem title="MENU_UNDO" keyEquivalent="z" id="207">
<connections>
<action selector="undo:" target="-1" id="223"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="206"/>
<menuItem title="MENU_EDIT_CUT" keyEquivalent="x" id="199">
<connections>
<action selector="cut:" target="-1" id="228"/>
</connections>
</menuItem>
<menuItem title="MENU_EDIT_COPY" keyEquivalent="c" id="197">
<connections>
<action selector="copy:" target="-1" id="224"/>
</connections>
</menuItem>
<menuItem title="MENU_EDIT_PASTE" keyEquivalent="v" id="203">
<connections>
<action selector="paste:" target="-1" id="226"/>
</connections>
</menuItem>
<menuItem title="MENU_EDIT_SELECT_ALL" keyEquivalent="a" id="198">
<connections>
<action selector="selectAll:" target="-1" id="232"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="MENU_WINDOW" id="19">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="MENU_WINDOW" systemMenu="window" id="24">
<items>
<menuItem title="Show Batch Viewer" id="449">
<connections>
<action selector="showBatchViewer:" target="451" id="455"/>
</connections>
</menuItem>
<menuItem title="Show GL Layer Setup" id="450">
<connections>
<action selector="showGLLayerSetup:" target="451" id="454"/>
</connections>
</menuItem>
<menuItem title="Capture Frame" keyEquivalent="r" id="461">
<connections>
<action selector="captureFrame:" target="451" id="463"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
<customObject id="451" userLabel="MainApp" customClass="MainApp">
<connections>
<outlet property="captureFrameMenuItem" destination="461" id="462"/>
<outlet property="showBatchViewerMenuItem" destination="449" id="456"/>
<outlet property="showGLLayerSetupMenuItem" destination="450" id="457"/>
</connections>
</customObject>
</objects>
</document>

12
src/app/mac/View.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef APP_MAC_VIEW_H
#define APP_MAC_VIEW_H
#include <objc/objc-runtime.h>
struct GLWindowCallbacks;
void AssignEngineViewCallbacks(GLWindowCallbacks*);
Class GetEngineViewClass(void);
#endif

27
src/app/mac/View.mm Normal file
View file

@ -0,0 +1,27 @@
#include "app/mac/View.h"
#include "app/mac/EngineGLLayerView.h"
#include "app/mac/WindowCallbacks.h"
#include "gx/gll/GLWindow.h"
GLWindowCallbacks EngineViewCallbacks = {
&MacOnResized,
&MacOnMouseDown,
&MacOnMouseMoved,
&MacOnMouseUp,
&MacOnKeyDown,
&MacOnKeyUp
};
void AssignEngineViewCallbacks(GLWindowCallbacks* callbacks) {
*callbacks = EngineViewCallbacks;
// TODO
// (callbacks + 100) = 0;
// TODO
// dword_12B9F54 = sub_A15850;
}
Class GetEngineViewClass() {
return [EngineGLLayerView class];
}

41
src/app/mac/Whoa.mm Normal file
View file

@ -0,0 +1,41 @@
#include "app/mac/WoWApplication.h"
#include "app/mac/MacClient.h"
#include "client/Client.hpp"
#include <AppKit/AppKit.h>
#include <Foundation/Foundation.h>
int32_t main(int32_t argc, char* argv[]) {
// TODO
// MacClient::SetupCommandLine(argc, argv, v10);
if (MacClient::IsUsingGLLayer()) {
// TODO
// GxSetRequestedApi(3);
// TODO
// OsInputSetIsUsingCocoaEventLoop(1);
[WoWApplication sharedApplication];
#if WHOA_SYSTEM_VERSION < WHOA_MACOS_10_8
[NSBundle
loadNibNamed: @"MainMenu"
owner: NSApp];
#endif
#if WHOA_SYSTEM_VERSION >= WHOA_MACOS_10_8
[[NSBundle mainBundle]
loadNibNamed: @"MainMenu"
owner: NSApp
topLevelObjects: nil];
#endif
[NSRunLoop currentRunLoop];
[NSApp mainMenu];
CommonMain();
}
return 0;
}

View file

@ -0,0 +1,19 @@
#ifndef APP_MAC_WINDOW_CALLBACKS_H
#define APP_MAC_WINDOW_CALLBACKS_H
#include <cstdint>
#include <AppKit/AppKit.h>
void MacOnKeyDown(NSEvent*);
void MacOnKeyUp(NSEvent*);
void MacOnMouseDown(int16_t, int32_t, int32_t);
void MacOnMouseMoved(int32_t, int32_t);
void MacOnMouseUp(int16_t, int32_t, int32_t);
void MacOnResized(int32_t width, int32_t height, bool a3);
#endif

View file

@ -0,0 +1,188 @@
#include "app/mac/WindowCallbacks.h"
#include "app/mac/MacClient.h"
#include "event/Input.hpp"
#include "gx/gll/CGxDeviceGLL.hpp"
#include "gx/Device.hpp"
#include "gx/Window.hpp"
#include "util/BlizzardCore.hpp"
void MacOnKeyDown(NSEvent* event) {
BLIZZARD_ASSERT(false);
}
void MacOnKeyUp(NSEvent* event) {
uint32_t keyCode = event.keyCode;
MacClient::CheckKeyboardLayout();
if (keyCode <= 0x7F) {
uint32_t key = MacClient::s_keyConversion[keyCode];
if (key != KEY_NONE) {
OsQueuePut(OS_INPUT_KEY_UP, key, 0, 0, 0);
}
}
}
void MacOnMouseDown(int16_t button, int32_t x, int32_t y) {
NSEvent* event = [NSApp currentEvent];
uint32_t modifierFlags = event.modifierFlags;
uint32_t v8 = 0;
if (modifierFlags & NSShiftKeyMask) {
v8 |= 0x2;
}
if (modifierFlags & NSAlternateKeyMask) {
v8 |= 0x8;
}
if (modifierFlags & NSCommandKeyMask) {
v8 |= 0x1;
}
if (modifierFlags & NSControlKeyMask) {
v8 |= 0x10;
}
if (modifierFlags & NSAlphaShiftKeyMask) {
v8 |= 0x4;
}
int16_t buttonNumber = button + 1;
int16_t buttonIndex = button;
if (buttonNumber > 0xF) {
return;
}
if (Input::s_buttonDown[buttonIndex]) {
return;
}
int16_t effectiveButtonNumber = buttonNumber;
Input::s_buttonDown[buttonIndex] = 1;
if (buttonNumber == 1) {
effectiveButtonNumber = 1;
if (v8 & 0x1) {
Input::s_simulatedRightButtonClick = 1;
// TODO
// if (Input::byte_12B94E2) {
// return;
// }
effectiveButtonNumber = 2;
}
}
if (buttonNumber == 2) {
if (Input::s_simulatedRightButtonClick) {
return;
} else {
effectiveButtonNumber = 2;
}
}
MOUSEBUTTON mouseButton = ConvertButtonNumberToMOUSEBUTTON(effectiveButtonNumber);
if (mouseButton) {
if (Input::s_mouseMode == 0) {
Input::s_currentMouse = { x, y };
}
OsQueuePut(OS_INPUT_MOUSE_DOWN, mouseButton, x, y, 0);
}
}
void MacOnMouseMoved(int32_t x, int32_t y) {
if (Input::s_mouseMode == 1) {
NSEvent* event = [NSApp currentEvent];
int32_t deltaX = static_cast<int32_t>(floor(event.deltaX));
int32_t deltaY = static_cast<int32_t>(floor(event.deltaY));
OsQueuePut(OS_INPUT_MOUSE_MOVE_RELATIVE, 0, deltaX, deltaY, 0);
} else {
Input::s_currentMouse = { x, y };
OsQueuePut(OS_INPUT_MOUSE_MOVE, 0, x, y, 0);
}
}
void MacOnMouseUp(int16_t button, int32_t x, int32_t y) {
NSEvent* event = [NSApp currentEvent];
uint32_t modifierFlags = event.modifierFlags;
int16_t buttonNumber = button + 1;
int16_t buttonIndex = button;
if (buttonNumber > 0xF) {
return;
}
if (!Input::s_buttonDown[buttonIndex]) {
return;
}
int16_t effectiveButtonNumber = buttonNumber;
Input::s_buttonDown[buttonIndex] = 0;
if (buttonNumber == 1) {
effectiveButtonNumber = 1;
if (Input::s_simulatedRightButtonClick) {
effectiveButtonNumber = 2;
Input::s_simulatedRightButtonClick = 0;
// TODO
// if (Input::byte_12B94E2) {
// return;
// }
}
}
if (buttonNumber == 2) {
if (Input::s_simulatedRightButtonClick) {
return;
} else {
effectiveButtonNumber = 2;
}
}
MOUSEBUTTON mouseButton = ConvertButtonNumberToMOUSEBUTTON(effectiveButtonNumber);
if (mouseButton) {
if (Input::s_mouseMode != 0) {
Input::s_currentMouse = { x, y };
}
OsQueuePut(OS_INPUT_MOUSE_UP, mouseButton, x, y, 0);
}
}
void MacOnResized(int32_t width, int32_t height, bool a3) {
if (a3) {
return;
}
static_cast<CGxDeviceGLL*>(g_theGxDevicePtr)->Resize(width, height);
OsQueuePut(OS_INPUT_SIZE, width, height, 0, 0);
// TODO SubA61E60(width, height)
auto bounds = GetSavedWindowBounds();
Rect newBounds = {
bounds->top,
bounds->left,
static_cast<int16_t>(bounds->top + height),
static_cast<int16_t>(bounds->left + width)
};
SetSavedWindowBounds(newBounds);
}

View file

@ -0,0 +1,11 @@
#ifndef APP_MAC_WOW_APPLICATION_H
#define APP_MAC_WOW_APPLICATION_H
#include <AppKit/AppKit.h>
#include <Foundation/Foundation.h>
@interface WoWApplication : NSApplication
@end
#endif

View file

@ -0,0 +1,24 @@
#include "app/mac/WoWApplication.h"
#include "gx/gll/GLLayerView.h"
@implementation WoWApplication
- (void)sendEvent:(NSEvent*)event {
auto responder = [[NSApp keyWindow] firstResponder];
if (responder && [responder isKindOfClass: [GLLayerView class]]) {
NSEventType type = [event type];
if (type == NSKeyDown && (event.keyCode == 114 || (event.keyCode == 48 && event.modifierFlags & NSControlKeyMask))) {
[responder keyDown: event];
return;
} else if (type == NSKeyUp) {
[responder keyUp: event];
return;
}
}
[super sendEvent:event];
}
@end

143
src/async/AsyncFile.cpp Normal file
View file

@ -0,0 +1,143 @@
#include "async/AsyncFile.hpp"
#include "async/AsyncFileRead.hpp"
#include "async/CAsyncQueue.hpp"
#include "event/Event.hpp"
#include "util/SFile.hpp"
#include <common/Prop.hpp>
#include <common/Time.hpp>
CAsyncObject* AsyncFileReadAllocObject() {
AsyncFileRead::s_queueLock.Enter();
CAsyncObject* object = AsyncFileRead::s_asyncFileReadFreeList.Head();
if (!object) {
object = AsyncFileRead::s_asyncFileReadFreeList.NewNode(1, 0, 0x0);
}
object->link.Unlink();
AsyncFileRead::s_queueLock.Leave();
object->file = nullptr;
object->buffer = nullptr;
object->size = 0;
object->userArg = nullptr;
object->userPostloadCallback = nullptr;
object->userFailedCallback = nullptr;
object->queue = nullptr;
object->isProcessed = 0;
object->isRead = 0;
object->isCurrent = 0;
object->char24 = 0;
object->char25 = 0;
object->ptr1C = 0;
object->priority = 126;
return object;
}
void AsyncFileReadDestroyObject(CAsyncObject* object) {
AsyncFileRead::s_queueLock.Enter();
if (object->isCurrent) {
// TODO
// nullsub_3();
AsyncFileRead::s_queueLock.Leave();
while (object->isCurrent) {
OsSleep(1);
}
AsyncFileRead::s_queueLock.Enter();
}
object->link.Unlink();
if (object->file) {
SFile::Close(object->file);
}
AsyncFileRead::s_asyncFileReadFreeList.LinkToHead(object);
AsyncFileRead::s_queueLock.Leave();
}
void AsyncFileReadInitialize(uint32_t threadSleep, uint32_t handlerTimeout) {
AsyncFileRead::s_threadSleep = std::min(threadSleep, 100u);
AsyncFileRead::s_handlerTimeout = std::max(handlerTimeout, 20u);
EventRegisterEx(EVENT_ID_POLL, &AsyncFileReadPollHandler, nullptr, 0.0f);
if (SFile::IsStreamingMode()) {
// TODO
// EventRegisterEx(EVENT_ID_IDLE, &Sub4B9F40, nullptr, -1.0f);
}
AsyncFileRead::s_asyncWaitObject = nullptr;
AsyncFileRead::s_progressCallback = nullptr;
AsyncFileRead::s_progressParam = nullptr;
AsyncFileRead::s_ingameProgressCallback = nullptr;
AsyncFileRead::s_ingameStartCallback = nullptr;
AsyncFileRead::s_propContext = PropGetSelectedContext();
AsyncFileRead::s_shutdownEvent.Reset();
int32_t numQueues = SFile::IsStreamingMode() != 0 ? 3 : 1;
for (int32_t i = 0; i < numQueues; i++) {
CAsyncQueue* queue = AsyncFileReadCreateQueue();
const char* queueName = AsyncFileRead::s_asyncQueueNames[i];
AsyncFileRead::s_asyncQueues[i] = queue;
AsyncFileReadCreateThread(queue, queueName);
}
if (SFile::IsStreamingMode()) {
AsyncFileRead::s_asyncQueues[2]->int20 = 1;
}
// TODO
// - Something related to AsyncFileRead::s_userQueueLock
}
void AsyncFileReadObject(CAsyncObject* object, int32_t a2) {
CAsyncQueue* queue = AsyncFileRead::s_asyncQueues[0];
if (SFile::IsStreamingMode()) {
// TODO
// int32_t v3 = SFile::FileIsLocal(object->file, 6);
//
// if (!v3 || v3 == 2) {
// int32_t v4 = object->priority <= 127;
// object->char24 = 1;
// queue = AsyncFileRead::s_asyncQueues[1];
//
// if (!v4) {
// queue = AsyncFileRead::s_asyncQueues[2];
// }
// }
}
AsyncFileRead::s_queueLock.Enter();
object->queue = queue;
if (AsyncFileRead::s_asyncWaitObject == object) {
object->priority = object->priority > 127 ? 128 : 0;
// TODO
// object->ptr1C = g_theGxDevicePtr + 3944;
object->char25 = 0;
} else if (queue->int20) {
// TODO
// Sub4BA530(object, a2);
} else {
AsyncFileReadLinkObject(object, a2);
}
AsyncFileRead::s_queueLock.Leave();
if (SFile::IsStreamingMode()) {
// TODO
// SFile::LogFileAccess(object->file, 0, 0);
}
}

14
src/async/AsyncFile.hpp Normal file
View file

@ -0,0 +1,14 @@
#ifndef ASYNC_ASYNC_FILE_HPP
#define ASYNC_ASYNC_FILE_HPP
#include "async/CAsyncObject.hpp"
CAsyncObject* AsyncFileReadAllocObject(void);
void AsyncFileReadDestroyObject(CAsyncObject* object);
void AsyncFileReadInitialize(uint32_t threadSleep, uint32_t handlerTimeout);
void AsyncFileReadObject(CAsyncObject* object, int32_t a2);
#endif

196
src/async/AsyncFileRead.cpp Normal file
View file

@ -0,0 +1,196 @@
#include "async/AsyncFileRead.hpp"
#include "util/SFile.hpp"
#include <common/Prop.hpp>
#include <common/Time.hpp>
uint32_t AsyncFileRead::s_threadSleep;
uint32_t AsyncFileRead::s_handlerTimeout = 100;
CAsyncObject* AsyncFileRead::s_asyncWaitObject;
void* AsyncFileRead::s_progressCallback;
void* AsyncFileRead::s_progressParam;
int32_t AsyncFileRead::s_progressCount;
void* AsyncFileRead::s_ingameProgressCallback;
void* AsyncFileRead::s_ingameStartCallback;
void* AsyncFileRead::s_propContext;
SEvent AsyncFileRead::s_shutdownEvent = SEvent(1, 0);
const char* AsyncFileRead::s_asyncQueueNames[NUM_ASYNC_QUEUES] = {
"Disk Queue",
"Net Geometry Queue",
"Net Texture Queue"
};
CAsyncQueue* AsyncFileRead::s_asyncQueues[NUM_ASYNC_QUEUES];
SCritSect AsyncFileRead::s_queueLock;
SCritSect AsyncFileRead::s_userQueueLock;
TSList<CAsyncQueue, TSGetLink<CAsyncQueue>> AsyncFileRead::s_asyncQueueList;
TSList<CAsyncThread, TSGetLink<CAsyncThread>> AsyncFileRead::s_asyncThreadList;
STORM_EXPLICIT_LIST(CAsyncObject, link) AsyncFileRead::s_asyncFileReadPostList;
STORM_EXPLICIT_LIST(CAsyncObject, link) AsyncFileRead::s_asyncFileReadFreeList;
CAsyncQueue* AsyncFileReadCreateQueue() {
CAsyncQueue* queue = AsyncFileRead::s_asyncQueueList.NewNode(0, 2, 0x8);
return queue;
}
void AsyncFileReadCreateThread(CAsyncQueue* queue, const char* queueName) {
CAsyncThread* thread = AsyncFileRead::s_asyncThreadList.NewNode(0, 2, 0x8);
thread->queue = queue;
thread->currentObject = nullptr;
SThread::Create(AsyncFileReadThread, thread, thread->thread, const_cast<char*>(queueName), 0);
}
void AsyncFileReadLinkObject(CAsyncObject* object, int32_t a2) {
if (!object->queue) {
return;
}
object->link.Unlink();
auto& readList = object->queue->readList;
for (auto currentObject = readList.Head(); currentObject; currentObject = readList.Link(currentObject)->Next()) {
uint8_t priority = object->priority;
uint8_t currentPriority = currentObject->priority;
if (priority <= currentPriority && (a2 || priority != currentPriority)) {
readList.LinkNode(object, 2, currentObject);
object->char25 = 0;
return;
}
}
readList.LinkToTail(object);
object->char25 = 0;
}
int32_t AsyncFileReadPollHandler(const void*, void*) {
uint32_t start = OsGetAsyncTimeMsPrecise();
while (1) {
AsyncFileRead::s_queueLock.Enter();
CAsyncObject* object = AsyncFileRead::s_asyncFileReadPostList.Head();
if (!object) {
AsyncFileRead::s_queueLock.Leave();
break;
}
AsyncFileRead::s_asyncFileReadPostList.UnlinkNode(object);
if (AsyncFileRead::s_asyncWaitObject == object) {
AsyncFileRead::s_asyncWaitObject = nullptr;
}
object->isProcessed = 1;
AsyncFileRead::s_queueLock.Leave();
object->userPostloadCallback(object->userArg);
AsyncFileRead::s_progressCount--;
// Check if we're exceeded the allowed running time
if (OsGetAsyncTimeMsPrecise() - start > AsyncFileRead::s_handlerTimeout) {
break;
}
}
// TODO
// for (int32_t i = 0; i < DwordB4A224; i++) {
// DwordB4A228[i]();
// }
return 1;
}
uint32_t AsyncFileReadThread(void* param) {
CAsyncThread* thread = static_cast<CAsyncThread*>(param);
PropSelectContext(AsyncFileRead::s_propContext);
while (AsyncFileRead::s_shutdownEvent.Wait(0)) {
uint32_t sleep = 0;
CAsyncObject* object;
while (1) {
AsyncFileRead::s_queueLock.Enter();
object = thread->queue->readList.Head();
if (object && thread->queue->int20 && /* TODO */ true) {
// TODO
// Sub4BA530(object, 1);
AsyncFileRead::s_queueLock.Leave();
continue;
}
if (!object) {
object = thread->queue->list14.Head();
}
if (!object) {
AsyncFileRead::s_queueLock.Leave();
break;
}
object->link.Unlink();
object->queue = nullptr;
object->isCurrent = 1;
thread->currentObject = object;
AsyncFileRead::s_queueLock.Leave();
int32_t tries = 10;
while (1) {
if (SFile::IsStreamingMode() && object->file) {
// TODO
// Sub421820(object->file, (object->priority > 127) + 1, 1);
}
if (SFile::Read(object->file, object->buffer, object->size, nullptr, nullptr, nullptr)) {
break;
}
tries--;
// Handle failure
if (tries == 0) {
// TODO
// Sub421850((object->file, v17, 512);
// v10 = Sub7717E0();
// Sub771A80(v10, v18, 512);
// nullsub_3(v17);
break;
}
}
AsyncFileRead::s_queueLock.Enter();
AsyncFileRead::s_asyncFileReadPostList.LinkToTail(object);
thread->currentObject = nullptr;
object->isCurrent = 0;
object->isRead = 1;
AsyncFileRead::s_queueLock.Leave();
if (AsyncFileRead::s_threadSleep) {
sleep++;
if (sleep == AsyncFileRead::s_threadSleep) {
OsSleep(1);
sleep = 0;
}
}
}
OsSleep(1);
}
return 0;
}

View file

@ -0,0 +1,46 @@
#ifndef ASYNC_ASYNC_FILE_READ_HPP
#define ASYNC_ASYNC_FILE_READ_HPP
#include "async/CAsyncQueue.hpp"
#include "async/CAsyncThread.hpp"
#include <common/Prop.hpp>
#include <storm/Thread.hpp>
#define NUM_ASYNC_QUEUES 3
class CAsyncObject;
class AsyncFileRead {
public:
// Static variables
static uint32_t s_threadSleep;
static uint32_t s_handlerTimeout;
static CAsyncObject* s_asyncWaitObject;
static void* s_progressCallback;
static void* s_progressParam;
static int32_t s_progressCount;
static void* s_ingameProgressCallback;
static void* s_ingameStartCallback;
static HPROPCONTEXT s_propContext;
static SEvent s_shutdownEvent;
static const char* s_asyncQueueNames[];
static CAsyncQueue* s_asyncQueues[];
static SCritSect s_queueLock;
static SCritSect s_userQueueLock;
static TSList<CAsyncQueue, TSGetLink<CAsyncQueue>> s_asyncQueueList;
static TSList<CAsyncThread, TSGetLink<CAsyncThread>> s_asyncThreadList;
static STORM_EXPLICIT_LIST(CAsyncObject, link) s_asyncFileReadPostList;
static STORM_EXPLICIT_LIST(CAsyncObject, link) s_asyncFileReadFreeList;
};
CAsyncQueue* AsyncFileReadCreateQueue(void);
void AsyncFileReadCreateThread(CAsyncQueue* queue, const char* queueName);
void AsyncFileReadLinkObject(CAsyncObject* object, int32_t a2);
int32_t AsyncFileReadPollHandler(const void*, void*);
uint32_t AsyncFileReadThread(void* thread);
#endif

View file

@ -0,0 +1,30 @@
#ifndef ASYNC_C_ASYNC_OBJECT_HPP
#define ASYNC_C_ASYNC_OBJECT_HPP
#include <storm/List.hpp>
class SFile;
class CAsyncQueue;
class CAsyncObject {
public:
// Member variables
SFile* file;
void* buffer;
uint32_t size;
void* userArg;
void (*userPostloadCallback)(void*);
void (*userFailedCallback)(void*);
CAsyncQueue* queue;
void* ptr1C;
uint8_t priority;
uint8_t isProcessed;
uint8_t isRead;
uint8_t isCurrent;
uint8_t char24;
uint8_t char25;
uint8_t padding[2];
TSLink<CAsyncObject> link;
};
#endif

16
src/async/CAsyncQueue.hpp Normal file
View file

@ -0,0 +1,16 @@
#ifndef ASYNC_C_ASYNC_QUEUE_HPP
#define ASYNC_C_ASYNC_QUEUE_HPP
#include "async/CAsyncObject.hpp"
#include <cstdint>
#include <storm/List.hpp>
class CAsyncQueue : public TSLinkedNode<CAsyncQueue> {
public:
// Member variables
STORM_EXPLICIT_LIST(CAsyncObject, link) readList;
STORM_EXPLICIT_LIST(CAsyncObject, link) list14;
int32_t int20;
};
#endif

View file

@ -0,0 +1,19 @@
#ifndef ASYNC_C_ASYNC_THREAD_HPP
#define ASYNC_C_ASYNC_THREAD_HPP
#include <cstdint>
#include <storm/List.hpp>
#include <storm/Thread.hpp>
class CAsyncObject;
class CAsyncQueue;
class CAsyncThread : public TSLinkedNode<CAsyncThread> {
public:
// Member variables
SThread thread;
CAsyncQueue* queue;
CAsyncObject* currentObject;
};
#endif

19
src/async/CMakeLists.txt Normal file
View file

@ -0,0 +1,19 @@
file(GLOB PRIVATE_SOURCES "*.cpp")
add_library(async STATIC
${PRIVATE_SOURCES}
)
target_include_directories(async
PRIVATE
${CMAKE_SOURCE_DIR}/src
)
target_link_libraries(async
PRIVATE
event
util
PUBLIC
common
storm
)

25
src/client/CMakeLists.txt Normal file
View file

@ -0,0 +1,25 @@
file(GLOB PRIVATE_SOURCES "*.cpp")
add_library(client STATIC
${PRIVATE_SOURCES}
)
target_include_directories(client
PRIVATE
${CMAKE_SOURCE_DIR}/src
)
target_link_libraries(client
PRIVATE
async
event
gx
model
net
ui
util
world
PUBLIC
common
storm
)

437
src/client/Client.cpp Normal file
View file

@ -0,0 +1,437 @@
#include "client/Client.hpp"
#include "client/ClientServices.hpp"
#include "client/Console.hpp"
#include "async/AsyncFile.hpp"
#include "glue/CGlueMgr.hpp"
#include "gx/Device.hpp"
#include "gx/Screen.hpp"
#include "gx/Texture.hpp"
#include "model/Model2.hpp"
#include "ui/FrameScript.hpp"
#include "ui/FrameXML.hpp"
#include "util/BlizzardCore.hpp"
#include "util/CVar.hpp"
#include "world/World.hpp"
#include <cstring>
#include <common/Prop.hpp>
#include <storm/Error.hpp>
CVar* Client::g_accountListVar;
HEVENTCONTEXT Client::g_clientEventContext;
void AsyncFileInitialize() {
// TODO
AsyncFileReadInitialize(0, 100);
}
void BaseInitializeGlobal() {
PropInitialize();
}
void ClientMiscInitialize() {
// TODO
Client::g_accountListVar = CVar::Register(
"accountList",
"List of wow accounts for saved Blizzard account",
0,
"",
nullptr,
4,
false,
nullptr,
false
);
// TODO
}
void ClientPostClose(int32_t a1) {
// TODO s_finalDialog = a1;
EventPostCloseEx(nullptr);
}
int32_t DestroyEngineCallback(const void* a1, void* a2) {
// TODO
return 1;
}
int32_t InitializeEngineCallback(const void* a1, void* a2) {
// TODO
// sub_4D2A30();
AsyncFileInitialize();
TextureInitialize();
// ModelBlobLoad("world\\model.blob");
// if (SFile::IsStreamingMode()) {
// TextureLoadBlob("world\\liquid.tex");
// }
ScrnInitialize(0);
// ConsoleScreenInitialize(a2);
// s_cvarTextureFilteringMode = CVar::Register(
// "textureFilteringMode",
// "Texture filtering mode",
// 1,
// "1",
// &TextureFilteringCallback,
// 1,
// 0,
// 0,
// 0
// );
// s_cvarUIFaster = CVar::Register(
// "UIFaster",
// "UI acceleration option",
// 0,
// "3",
// &UIFasterCalllback,
// 1,
// 0,
// 0,
// 0
// );
// s_cvarTextureCacheSize = CVar::Register(
// "textureCacheSize",
// "Texture cache size in bytes",
// 1,
// "32",
// &TextureCacheSizeCallback,
// 1,
// 0,
// 0,
// 0
// );
// sub_4B6580(*(_DWORD *)(dword_B2F9FC + 48) << 20);
// AddConsoleDeviceDefaultCallback(SetDefaults);
// if (ConsoleDeviceHardwareChanged()) {
// v3 = 0;
// do {
// SetDefaults(v3++);
// } while (v3 < 3);
// }
auto m2Flags = M2RegisterCVars();
M2Initialize(m2Flags, 0);
// v4 = *(_DWORD *)(dword_B2FA00 + 48);
// sub_4B61C0(dword_AB6128[v4]);
// sub_4B6230(dword_AB6140[v4]);
WowClientInit();
return 1;
}
int32_t InitializeGlobal() {
// TODO
// SCmdRegisterArgList(&ProcessCommandLine(void)::s_wowArgList, 17u);
// CmdLineProcess();
// sub_403600("WoW.mfil");
// if (dword_B2FA10 != 2) {
// sub_403560();
// }
// LOBYTE(v24) = 0;
// if (sub_422140()) {
// LOBYTE(v24) = OsDirectoryExists((int)"WTF/Account") == 0;
// }
// ClientServices::LoadCDKey();
ConsoleInitializeClientCommand();
ConsoleInitializeClientCVar("Config.wtf");
// sub_7663F0();
// v18 = 0;
// v19 = 0;
// ptr = 0;
// v21 = 0;
// sub_406740(&v18, &CVar::Load);
// if (ptr) {
// SMemFree(ptr, a_pad, -2, 0);
// }
// CVar::Register("dbCompress", "Database compression", 0, "-1", 0, 5, 0, 0, 0);
// v2 = CVar::Register("locale", "Set the game locale", 0, "****", &LocaleChangedCallback, 5, 0, 0, 0);
// if (!SStrCmp(v2->m_stringValue.m_str, "****", 0x7FFFFFFFu)) {
// CVar::Set(v2, "enUS", 1, 0, 0, 1);
// }
// CVar::Register("useEnglishAudio", "override the locale and use English audio", 0, "0", 0, 5, 0, 0, 0);
// if (sub_422140()) {
// sub_4036B0(v24, 0, a2, (int)v2, (char)v24);
// }
// SStrCopy(&a1a, v2->m_stringValue.m_str, 5);
// sub_402D50(&a1a);
// CVar::Set(v2, &a1a, 1, 0, 0, 1);
// SStrPrintf(dest, 260, "%s%s", *(_DWORD *)off_AB6158, v2->m_stringValue.m_str);
// sub_421B50(dest);
// sub_423D70();
// sub_405DD0();
// CVar* v3 = CVar::Register(
// "processAffinityMask",
// "Sets which core(s) WoW may execute on - changes require restart to take effect",
// 2,
// "0",
// &sub_4022E0,
// 0,
// 0,
// 0,
// 0
// );
// CVar* v4 = CVar::Lookup("videoOptionsVersion");
// if (!v4 || v4->m_intValue < 3) {
// SStrPrintf(v23, 8, "%u", 0);
// CVar::Set(v3, v23, 1, 0, 0, 1);
// CVar::Update((int)v3);
// }
// v5 = v3->m_intValue;
// if (v5) {
// SSetCurrentProcessAffinityMask(v5);
// }
BaseInitializeGlobal();
EventInitialize(1, 0);
// CVar* v6 = CVar::Register(
// "timingTestError",
// "Error reported by the timing validation system",
// 6,
// "0",
// 0,
// 5,
// 0,
// 0,
// 0
// );
// v7 = v6;
// CVar* v8 = CVar::Register(
// "timingMethod",
// "Desired method for game timing",
// 2,
// "0",
// &sub_403200,
// 5,
// 0,
// v6,
// 0
// );
// sub_86D430(v8->m_intValue);
// ConsoleCommandRegister("timingInfo", (int)sub_4032A0, 0, 0);
// v9 = sub_86AD50();
// v10 = v9 == v7->m_intValue;
// dword_B2F9D8 = v9;
// if (!v10) {
// sprintf(&v17, "%d", v9);
// CVar::SetReadOnly((int)v7, 0);
// CVar::Set(v7, &v17, 1, 0, 0, 1);
// CVar::Update((int)v7);
// CVar::SetReadOnly((int)v7, 1);
// ConsolePrintf("Timing test error: %d", (int)v7);
// }
// WowClientDB<Startup_StringsRec>::Load(&g_Startup_StringsDB, 0, ".\\Client.cpp", 0x12E3u);
// Startup_StringsRec* v11 = g_Startup_StringsDB.GetRecordByIndex(1);
// const char* v12;
// if (v11) {
// v12 = v11->m_text;
// } else {
// v12 = "World of Warcraft";
// }
// TODO
// - replace with above logic for loading from Startup_Strings.dbc
const char* v12 = "World of Warcraft";
char v15[260];
SStrCopy(v15, v12, 0x7FFFFFFF);
ConsoleDeviceInitialize(v15);
// OsIMEInitialize();
// uint32_t v13 = OsGetAsyncTimeMs();
// g_rndSeed.SetSeed(v13);
Client::g_clientEventContext = EventCreateContextEx(
1,
&InitializeEngineCallback,
&DestroyEngineCallback,
0,
0
);
return 1;
}
void CommonMain() {
StormInitialize();
// TODO
// - error log setup
// - misc other setup
if (InitializeGlobal()) {
EventDoMessageLoop();
// TODO
// sub_406B70();
}
// TODO
// - misc cleanup
}
void BlizzardAssertCallback(const char* a1, const char* a2, const char* a3, uint32_t a4) {
if (*a2) {
SErrDisplayError(0, a3, a4, a2, 0, 1, 0x11111111);
} else {
SErrDisplayError(0, a3, a4, a1, 0, 1, 0x11111111);
}
}
void StormInitialize() {
// TODO
// SStrInitialize();
// SErrInitialize();
// SLogInitialize();
// SFile::Initialize();
Blizzard::Debug::SetAssertHandler(BlizzardAssertCallback);
}
void WowClientInit() {
// TODO
// EventRegister(EVENT_ID_5, (int)sub_4020E0);
// _cfltcvt_init_0();
ClientMiscInitialize();
// sub_401B60();
// ClientDBInitialize();
// LoadingScreenInitialize();
FrameScript_Initialize(0);
// TODO
// SI2::Init(0);
// sub_6F66B0();
FrameXML_RegisterDefault();
GlueScriptEventsInitialize();
ScriptEventsInitialize();
// TODO
// sub_6F75E0();
// sub_401FF0();
ClientServices::Initialize();
// TODO ClientServices::SetMessageHandler(SMSG_TUTORIAL_FLAGS, (int)sub_530920, 0);
// TODO
// v2 = CVar::Lookup("EnableVoiceChat");
// if (v2 && *(_DWORD *)(v2 + 48)) {
// ComSatClient_Init();
// }
// TODO
// DBCache_RegisterHandlers();
// DBCache_Initialize(a1);
// TODO
// sub_78E400();
CWorld::Initialize();
// TODO
// ShadowInit();
// GxuLightInitialize();
// GxuLightBucketSizeSet(16.665001);
// InputControlInitialize();
CGlueMgr::Initialize();
// TODO
// if (GetConsoleMessage()) {
// v3 = (const char *)GetConsoleMessage();
// CGlueMgr::AddChangedOptionWarning(v3);
// SetConsoleMessage(0);
// }
// TODO
// if (sub_422140()) {
// sub_421630();
// }
// TODO
// if (byte_B2F9E1 != 1) {
// if ((g_playIntroMovie + 48) == 1) {
// CVar::Set(g_playIntroMovie, "0", 1, 0, 0, 1);
// CGlueMgr::SetScreen("movie");
// } else {
// CGlueMgr::SetScreen("login");
// }
// } else {
// if ((dword_B2F980 + 48) == 1) {
// CVar::Set(dword_B2F980, "0", 1, 0, 0, 1);
// CVar::Set(g_playIntroMovie, "0", 1, 0, 0, 1);
// CGlueMgr::SetScreen("movie");
// } else {
// CGlueMgr::SetScreen("login");
// }
// }
// TODO
// - temporary until above logic is implemented
CGlueMgr::SetScreen("login");
// TODO
// CGlueMgr::m_pendingTimerAlert = dword_B2F9D8;
// sub_7FC5A0();
// EventRegister(EVENT_ID_POLL, &PollNet);
}

22
src/client/Client.hpp Normal file
View file

@ -0,0 +1,22 @@
#ifndef CLIENT_CLIENT_HPP
#define CLIENT_CLIENT_HPP
#include "event/Event.hpp"
#include <cstdint>
class CVar;
namespace Client {
extern CVar* g_accountListVar;
extern HEVENTCONTEXT g_clientEventContext;
}
void ClientPostClose(int32_t);
void CommonMain(void);
void StormInitialize(void);
void WowClientInit(void);
#endif

View file

@ -0,0 +1,10 @@
#ifndef CLIENT_CLIENT_REALM_RESPONSE_ADAPTER_HPP
#define CLIENT_CLIENT_REALM_RESPONSE_ADAPTER_HPP
#include "net/Connection.hpp"
class ClientRealmResponseAdapter : public RealmResponse {
public:
};
#endif

View file

@ -0,0 +1,92 @@
#include "client/ClientServices.hpp"
#include "client/ClientRealmResponseAdapter.hpp"
#include "net/Connection.hpp"
#include "net/Login.hpp"
#include <storm/Memory.hpp>
#include <storm/String.hpp>
#include <new>
ClientConnection* g_clientConnection;
RealmResponse* ClientServices::s_clientRealmResponse;
ClientConnection* ClientServices::s_currentConnection;
ClientServices* ClientServices::s_instance;
Login* ClientServices::s_loginObj;
bool ClientServices::s_newLogin;
ClientConnection* ClientServices::Connection() {
// TODO assertion?
return ClientServices::s_currentConnection;
}
ClientServices* ClientServices::GetInstance() {
if (ClientServices::s_instance) {
return ClientServices::s_instance;
}
auto instanceMem = SMemAlloc(sizeof(ClientServices), __FILE__, __LINE__, 0x0);
auto instance = new (instanceMem) ClientServices();
ClientServices::s_instance = instance;
return ClientServices::s_instance;
}
void ClientServices::Initialize() {
if (!g_clientConnection) {
auto adapterMem = SMemAlloc(sizeof(ClientRealmResponseAdapter), __FILE__, __LINE__, 0x0);
auto clientRealmResponse = new (adapterMem) ClientRealmResponseAdapter();
ClientServices::s_clientRealmResponse = clientRealmResponse;
auto connectionMem = SMemAlloc(sizeof(ClientConnection), __FILE__, __LINE__, 0x0);
auto clientConnection = new (connectionMem) ClientConnection(ClientServices::s_clientRealmResponse);
g_clientConnection = clientConnection;
}
ClientServices::s_currentConnection = g_clientConnection;
// TODO ConsoleCommandRegister("logout", &Sub6B2030, 5, nullptr);
}
Login* ClientServices::LoginConnection() {
return ClientServices::s_loginObj;
}
void ClientServices::Logon(const char* accountName, const char* password) {
if (ClientServices::s_newLogin) {
if (ClientServices::s_loginObj) {
// TODO
// ClientServices::s_loginObj->Vfunc48(1);
ClientServices::s_loginObj = nullptr;
}
ClientServices::s_newLogin = false;
}
auto useBattlenet = SStrChr(accountName, '@') != 0;
Login* loginObj;
if (useBattlenet) {
// TODO
} else {
auto loginMem = SMemAlloc(sizeof(GruntLogin), __FILE__, __LINE__, 0x0);
loginObj = new (loginMem) GruntLogin();
}
ClientServices::s_loginObj = loginObj;
ClientServices::s_loginObj->Init(ClientServices::GetInstance());
// TODO
ClientServices::s_loginObj->SetLogonCreds(accountName, password);
// TODO
ClientServices::s_loginObj->Logon(nullptr, nullptr);
}
void ClientServices::LoginServerStatus(LOGIN_STATE state, LOGIN_RESULT result, const char* addrStr, const char* stateStr, const char* resultStr, uint16_t a7) {
// TODO
}

View file

@ -0,0 +1,30 @@
#ifndef CLIENT_CLIENT_SERVICES_HPP
#define CLIENT_CLIENT_SERVICES_HPP
#include "net/login/LoginResponse.hpp"
class ClientConnection;
class Login;
class RealmResponse;
class ClientServices : public LoginResponse {
public:
// Static variables
static RealmResponse* s_clientRealmResponse;
static ClientConnection* s_currentConnection;
static ClientServices* s_instance;
static Login* s_loginObj;
static bool s_newLogin;
// Static functions
static ClientConnection* Connection();
static ClientServices* GetInstance();
static void Initialize();
static Login* LoginConnection();
static void Logon(const char* accountName, const char* password);
// Virtual member functions
virtual void LoginServerStatus(LOGIN_STATE state, LOGIN_RESULT result, const char* addrStr, const char* stateStr, const char* resultStr, uint16_t a7);
};
#endif

191
src/client/Console.cpp Normal file
View file

@ -0,0 +1,191 @@
#include "client/Console.hpp"
#include "gx/Device.hpp"
#include "util/CVar.hpp"
#include <cstring>
CVar* s_cvGxMaximize;
CVar* s_cvGxResolution;
CVar* s_cvGxWidescreen;
CVar* s_cvGxWindow;
DefaultSettings s_defaults;
bool s_hwDetect;
bool s_hwChanged;
CGxFormat s_requestedFormat;
bool CVGxMaximizeCallback(CVar*, const char*, const char*, void*) {
// TODO
return true;
}
bool CVGxResolutionCallback(CVar*, const char*, const char*, void*) {
// TODO
return true;
}
bool CVGxWindowCallback(CVar*, const char*, const char*, void*) {
// TODO
return true;
}
void RegisterGxCVars() {
auto& format = s_defaults.format;
// TODO CURRENT_LANGUAGE check?
auto v1 = true;
s_cvGxWidescreen = CVar::Register(
"widescreen",
"Allow widescreen support",
0x0,
"1",
nullptr,
1,
false,
nullptr,
false
);
s_cvGxWindow = CVar::Register(
"gxWindow",
"toggle fullscreen/window",
0x1 | 0x2,
v1 ? "1" : "0",
&CVGxWindowCallback,
1,
0,
0,
0
);
s_cvGxMaximize = CVar::Register(
"gxMaximize",
"maximize game window",
0x1 | 0x2,
v1 ? "1" : "0",
&CVGxMaximizeCallback,
1,
0,
0,
0
);
// TODO s_cvGxColorBits
// TODO s_cvGxDepthBits
char resolution[260];
SStrPrintf(resolution, 260, "%dx%d", format.size.x, format.size.y);
s_cvGxResolution = CVar::Register(
"gxResolution",
"resolution",
0x1 | 0x2,
resolution,
&CVGxResolutionCallback,
1,
false,
nullptr,
false
);
// TODO s_cvGxRefresh
// TODO s_cvGxTripleBuffer
// TODO s_cvGxApi
// TODO s_cvGxVSync
// TODO s_cvGxAspect
// TODO s_cvGxCursor
// TODO s_cvGxMultisample
// TODO s_cvGxFixLag
// TODO s_cvGxStereoEnabled
// TODO s_cvGxOverride
// TODO s_cvGxAspect
// TODO s_cvGxMaxFPS
// TODO s_cvGxMaxFPSBk
// TODO s_cvWindowResizeLock
// TODO s_cvFixedFunction
}
void UpdateGxCVars() {
// TODO others
s_cvGxWindow->Update();
s_cvGxResolution->Update();
// TODO others
s_cvGxMaximize->Update();
// TODO others
}
void SetGxCVars(const CGxFormat& format) {
char value[1024];
// TODO s_cvGxColorBits
// TODO s_cvGxDepthBits
SStrPrintf(value, sizeof(value), "%d", format.window);
s_cvGxWindow->Set(value, true, false, false, true);
SStrPrintf(value, sizeof(value), "%dx%d", format.size.x, format.size.y);
s_cvGxResolution->Set(value, true, false, false, true);
// TODO s_cvGxRefresh
// TODO others
SStrPrintf(value, sizeof(value), "%d", format.maximize);
s_cvGxMaximize->Set(value, true, false, false, true);
// TODO others
UpdateGxCVars();
}
void ConsoleInitializeClientCommand() {
// TODO
}
void ConsoleInitializeClientCVar(const char* a1) {
// TODO
}
void ConsoleDeviceInitialize(const char* title) {
// TODO
// TODO proper logic
s_hwDetect = true;
// TODO
RegisterGxCVars();
// TODO ConsoleCommandRegister("gxRestart", &CCGxRestart, 1, nullptr);
// TODO
// TODO
// - source the size values correctly
s_requestedFormat.size.x = 1024;
s_requestedFormat.size.y = 768;
s_requestedFormat.colorFormat = CGxFormat::Fmt_Argb8888;
s_requestedFormat.depthFormat = CGxFormat::Fmt_Ds248;
if (s_hwDetect || s_hwChanged) {
// TODO Sub76B3F0(&UnkCABAF0, &UnkCABB38);
// TODO s_cvFixedFunction->Set("0", 1, 0, 0, 1);
// TODO memcpy(&s_requestedFormat, &s_defaults.format, sizeof(s_requestedFormat));
s_requestedFormat.window = s_cvGxWindow->GetInt() != 0;
s_requestedFormat.maximize = s_cvGxMaximize->GetInt() != 0;
// TODO temporary override
s_requestedFormat.maximize = 0;
SetGxCVars(s_requestedFormat);
}
CGxFormat format;
memcpy(&format, &s_requestedFormat, sizeof(s_requestedFormat));
CGxDevice* device = GxDevCreate(GxApi_GLL, nullptr, format);
// TODO
}

16
src/client/Console.hpp Normal file
View file

@ -0,0 +1,16 @@
#ifndef CLIENT_CONSOLE_HPP
#define CLIENT_CONSOLE_HPP
#include "gx/CGxFormat.hpp"
struct DefaultSettings {
CGxFormat format;
};
void ConsoleInitializeClientCommand();
void ConsoleInitializeClientCVar(const char* a1);
void ConsoleDeviceInitialize(const char* title);
#endif

40
src/event/CEvent.cpp Normal file
View file

@ -0,0 +1,40 @@
#include "event/CEvent.hpp"
#include "gx/Coordinate.hpp"
CCharEvent& CCharEvent::operator=(const EVENT_DATA_CHAR& data) {
this->ch = data.ch;
this->metaKeyState = data.metaKeyState;
this->repeat = data.repeat;
return *this;
}
CKeyEvent& CKeyEvent::operator=(const EVENT_DATA_KEY& data) {
this->key = data.key;
this->metaKeyState = data.metaKeyState;
this->repeat = data.repeat;
this->time = data.time;
return *this;
}
CMouseEvent& CMouseEvent::operator=(const EVENT_DATA_MOUSE& data) {
this->mode = data.mode;
this->button = data.button;
this->buttonState = data.buttonState;
this->metaKeyState = data.metaKeyState;
this->flags = data.flags;
this->time = data.time;
this->wheelDistance = data.wheelDistance;
NDCToDDC(data.x, data.y, &this->x, &this->y);
return *this;
}
CSizeEvent& CSizeEvent::operator=(const EVENT_DATA_SIZE& data) {
this->w = data.w;
this->h = data.h;
return *this;
}

39
src/event/CEvent.hpp Normal file
View file

@ -0,0 +1,39 @@
#ifndef EVENT_C_EVENT_HPP
#define EVENT_C_EVENT_HPP
#include "event/Types.hpp"
#include <cstdint>
#include <common/Ref.hpp>
class CEvent : public TRefCnt {
public:
// Member variables
uint32_t id;
void* param;
};
class CCharEvent : public CEvent, public EVENT_DATA_CHAR {
public:
// Member functions
CCharEvent& operator=(const EVENT_DATA_CHAR&);
};
class CKeyEvent : public CEvent, public EVENT_DATA_KEY {
public:
// Member functions
CKeyEvent& operator=(const EVENT_DATA_KEY&);
};
class CMouseEvent : public CEvent, public EVENT_DATA_MOUSE {
public:
// Member functions
CMouseEvent& operator=(const EVENT_DATA_MOUSE&);
};
class CSizeEvent : public CEvent, public EVENT_DATA_SIZE {
public:
// Member functions
CSizeEvent& operator=(const EVENT_DATA_SIZE&);
};
#endif

27
src/event/CMakeLists.txt Normal file
View file

@ -0,0 +1,27 @@
file(GLOB PRIVATE_SOURCES "*.cpp")
if(WHOA_SYSTEM_MAC)
file(GLOB MAC_SOURCES
"mac/*.cpp"
"mac/*.mm"
)
list(APPEND PRIVATE_SOURCES ${MAC_SOURCES})
endif()
add_library(event STATIC
${PRIVATE_SOURCES}
)
target_include_directories(event
PRIVATE
${CMAKE_SOURCE_DIR}/src
)
target_link_libraries(event
PRIVATE
gx
PUBLIC
common
storm
tempest
)

112
src/event/Context.cpp Normal file
View file

@ -0,0 +1,112 @@
#include "event/Context.hpp"
#include "event/Event.hpp"
#include "event/EvtThread.hpp"
#include <common/Time.hpp>
#include <storm/Atomic.hpp>
HEVENTCONTEXT AttachContextToThread(EvtContext* context) {
SInterlockedIncrement(&Event::s_threadListContention);
Event::s_threadListCritsect.Enter();
// Select the thread with the highest weight total
EvtThread* thread = nullptr;
EvtThread* t = Event::s_threadList.Head();
while (t) {
if (!thread || t->m_weightTotal < thread->m_weightTotal) {
thread = t;
}
t = t->Next();
}
if (thread) {
TSingletonInstanceId<EvtContext, offsetof(EvtContext, m_id)>::s_idTable.Insert(context);
uint32_t v13 = OsGetAsyncTimeMs();
if (v13 != context->m_schedNextWakeTime.m_val) {
context->m_schedNextWakeTime.m_val = v13;
context->m_schedNextWakeTime.Relink();
}
Event::s_threadSlotCritsects[thread->m_threadSlot].Enter();
thread->m_contextQueue.Enqueue(context);
Event::s_threadSlotCritsects[thread->m_threadSlot].Leave();
thread->m_wakeEvent.Set();
uint32_t v14 = context->m_schedWeight + thread->m_weightTotal;
uint32_t v15 = thread->m_contextCount + 1;
thread->m_contextCount = v15;
thread->m_weightTotal = v14;
thread->m_weightAvg = v14 / v15;
} else {
// TODO
}
Event::s_threadListCritsect.Leave();
SInterlockedDecrement(&Event::s_threadListContention);
return context;
}
void DetachContextFromThread(uint32_t a1, EvtContext* a2) {
// TODO
}
EvtContext* GetNextContext(uint32_t hThread) {
EvtContext* context;
Event::s_threadSlotCritsects[hThread].Enter();
context = Event::s_threadSlots[hThread]->m_contextQueue.Dequeue();
Event::s_threadSlotCritsects[hThread].Leave();
if (hThread == Event::s_mainThread) {
Event::s_currentEvtContext = context;
}
return context;
}
void PutContext(uint32_t nextWakeTime, uint32_t newSmoothWeight, EvtContext* context, uint32_t hThread) {
if (nextWakeTime != context->m_schedNextWakeTime.m_val) {
context->m_schedNextWakeTime.m_val = nextWakeTime;
context->m_schedNextWakeTime.Relink();
}
if (context->m_schedSmoothWeight != newSmoothWeight) {
uint32_t v8 = context->m_schedWeight;
context->m_schedSmoothWeight = newSmoothWeight;
int32_t v9;
if (newSmoothWeight <= v8) {
v9 = v8 - newSmoothWeight;
} else {
v9 = newSmoothWeight - v8;
}
context->m_schedRebalance = v9 >= v8 >> 3;
}
if (!SInterlockedIncrement(&Event::s_threadListContention)) {
Event::s_threadListCritsect.Enter();
// TODO
Event::s_threadListCritsect.Leave();
}
SInterlockedDecrement(&Event::s_threadListContention);
if (hThread < Event::s_threadSlotCount) {
Event::s_threadSlotCritsects[hThread].Enter();
Event::s_threadSlots[hThread]->m_contextQueue.Enqueue(context);
Event::s_threadSlotCritsects[hThread].Leave();
}
}

17
src/event/Context.hpp Normal file
View file

@ -0,0 +1,17 @@
#ifndef EVENT_CONTEXT_HPP
#define EVENT_CONTEXT_HPP
#include "event/Types.hpp"
#include <cstdint>
class EvtContext;
HEVENTCONTEXT AttachContextToThread(EvtContext* context);
void DetachContextFromThread(uint32_t a1, EvtContext* a2);
EvtContext* GetNextContext(uint32_t hThread);
void PutContext(uint32_t nextWakeTime, uint32_t newSmoothWeight, EvtContext* context, uint32_t hThread);
#endif

136
src/event/Event.cpp Normal file
View file

@ -0,0 +1,136 @@
#include "event/Event.hpp"
#include "event/EvtContext.hpp"
#include "event/EvtThread.hpp"
#include "event/Input.hpp"
#include "event/Queue.hpp"
#include "event/Scheduler.hpp"
#include <cstring>
#include <common/Prop.hpp>
#include <common/Time.hpp>
#include <storm/String.hpp>
SEvent Event::s_startEvent = SEvent(1, 0);
SEvent Event::s_shutdownEvent = SEvent(1, 0);
int32_t Event::s_netServer;
int32_t Event::s_threadSlotCount;
SCritSect* Event::s_threadSlotCritsects;
EvtThread** Event::s_threadSlots;
uint32_t Event::s_mainThread;
TSGrowableArray<SThread*> Event::s_schedulerThreads;
ATOMIC32 Event::s_threadListContention { -1 };
SCritSect Event::s_threadListCritsect;
TSList<EvtThread, TSGetLink<EvtThread>> Event::s_threadList;
EvtContext* Event::s_currentEvtContext;
ATOMIC32 Event::s_interactiveCount;
#if defined(WHOA_SYSTEM_MAC)
bool Event::s_shouldLoopTerminate;
#endif
void OsNetPump(uint32_t timeout) {
// TODO
}
void EventInitialize(int32_t threadCount, int32_t netServer) {
IEvtInputInitialize();
int32_t v2 = threadCount;
if (threadCount < 1) {
v2 = 1;
}
IEvtSchedulerInitialize(v2, netServer);
// TODO
// OsInputSetEventPollProc(&sub_47DCA0);
}
int32_t EventIsControlKeyDown() {
return EventIsKeyDown(KEY_LCONTROL) || EventIsKeyDown(KEY_RCONTROL);
}
int32_t EventIsKeyDown(KEY key) {
// TODO
return 0;
}
int32_t EventIsShiftKeyDown() {
return EventIsKeyDown(KEY_LSHIFT) || EventIsKeyDown(KEY_RSHIFT);
}
HEVENTCONTEXT EventCreateContextEx(int32_t interactive, int32_t (*initializeHandler)(const void*, void*), int32_t (*destroyHandler)(const void*, void*), uint32_t idleTime, uint32_t debugFlags) {
return IEvtSchedulerCreateContext(interactive, initializeHandler, destroyHandler, idleTime, debugFlags);
}
void EventDoMessageLoop() {
IEvtSchedulerProcess();
}
void EventPostCloseEx(HEVENTCONTEXT contextHandle) {
if (!contextHandle) {
contextHandle = PropGet(PROP_EVENTCONTEXT);
}
if (contextHandle) {
uint32_t contextId = *reinterpret_cast<uint32_t*>(contextHandle);
int32_t findMask;
EvtContext* context = TSingletonInstanceId<EvtContext, offsetof(EvtContext, m_id)>::s_idTable.Ptr(
contextId,
0,
&findMask
);
if (context) {
context->m_critsect.Enter();
if (context->m_schedState == EvtContext::SCHEDSTATE_ACTIVE) {
context->m_schedState = EvtContext::SCHEDSTATE_CLOSED;
}
context->m_critsect.Leave();
if (findMask != -1) {
TSingletonInstanceId<EvtContext, offsetof(EvtContext, m_id)>::s_idTable.Unlock(
findMask & (INSTANCE_TABLE_SLOT_COUNT - 1),
findMask >= INSTANCE_TABLE_SLOT_COUNT
);
}
}
}
}
void EventRegister(EVENTID id, EVENTHANDLERFUNC handler) {
EventRegisterEx(id, handler, nullptr, 0.0f);
}
void EventRegisterEx(EVENTID id, EVENTHANDLERFUNC handler, void* param, float priority) {
if (id < 0 || id > EVENTIDS || handler == nullptr) {
// TODO
// SErrSetLastError(0x57u);
return;
}
HEVENTCONTEXT hContext = PropGet(PROP_EVENTCONTEXT);
uint32_t contextId = *reinterpret_cast<uint32_t*>(hContext);
int32_t findMask;
EvtContext* context = TSingletonInstanceId<EvtContext, offsetof(EvtContext, m_id)>::s_idTable.Ptr(
contextId,
0,
&findMask
);
if (context) {
IEvtQueueRegister(context, id, handler, param, priority);
if (findMask != -1) {
TSingletonInstanceId<EvtContext, offsetof(EvtContext, m_id)>::s_idTable.Unlock(
findMask & (INSTANCE_TABLE_SLOT_COUNT - 1),
findMask >= INSTANCE_TABLE_SLOT_COUNT
);
}
}
}

56
src/event/Event.hpp Normal file
View file

@ -0,0 +1,56 @@
#ifndef EVENT_EVENT_HPP
#define EVENT_EVENT_HPP
#include "event/CEvent.hpp"
#include "event/Types.hpp"
#include <cstdint>
#include <storm/Array.hpp>
#include <storm/Atomic.hpp>
#include <storm/List.hpp>
#include <storm/Thread.hpp>
class EvtContext;
class EvtThread;
namespace Event {
extern SEvent s_startEvent;
extern SEvent s_shutdownEvent;
extern int32_t s_netServer;
extern int32_t s_originalThreadPriority;
extern int32_t s_threadSlotCount;
extern SCritSect* s_threadSlotCritsects;
extern EvtThread** s_threadSlots;
extern uint32_t s_mainThread;
extern TSGrowableArray<SThread*> s_schedulerThreads;
extern ATOMIC32 s_threadListContention;
extern SCritSect s_threadListCritsect;
extern TSList<EvtThread, TSGetLink<EvtThread>> s_threadList;
extern EvtContext* s_currentEvtContext;
extern ATOMIC32 s_interactiveCount;
#if defined(WHOA_SYSTEM_MAC)
extern bool s_shouldLoopTerminate;
#endif
}
HEVENTCONTEXT EventCreateContextEx(int32_t interactive, int32_t (*initializeHandler)(const void*, void*), int32_t (*destroyHandler)(const void*, void*), uint32_t idleTime, uint32_t debugFlags);
void EventDoMessageLoop();
void EventInitialize(int32_t threadCount, int32_t netServer);
int32_t EventIsControlKeyDown();
int32_t EventIsKeyDown(KEY key);
int32_t EventIsShiftKeyDown();
void EventPostCloseEx(HEVENTCONTEXT contextHandle);
void EventRegister(EVENTID id, int32_t (*handler)(const void*, void*));
void EventRegisterEx(EVENTID id, int32_t (*handler)(const void*, void*), void* param, float priority);
void OsNetPump(uint32_t timeout);
#endif

30
src/event/EvtContext.cpp Normal file
View file

@ -0,0 +1,30 @@
#include "event/EvtContext.hpp"
#include <common/Time.hpp>
EvtContext::EvtContext(uint32_t flags, uint32_t idleTime, uint32_t schedWeight, void* callContext, int32_t startWatchdog) :
TSingletonInstanceId<EvtContext, offsetof(TInstanceId<EvtContext>, m_id)>(),
m_critsect(),
m_schedNextWakeTime(),
m_queueHandlerList(),
m_queueMessageList(),
m_queueSyncKeyDownList()
// TODO
// m_timerIdTable()
{
this->m_currTime = 0;
this->m_schedState = SCHEDSTATE_ACTIVE;
this->m_schedLastIdle = OsGetAsyncTimeMs();
this->m_schedFlags = flags;
this->m_schedIdleTime = idleTime;
this->m_schedInitialIdleTime = idleTime;
this->m_schedWeight = schedWeight;
this->m_schedSmoothWeight = schedWeight;
this->m_schedRebalance = 0;
this->m_queueSyncButtonState = 0;
this->m_propContext = PropCreateContext();
this->m_callContext = callContext;
this->m_startWatchdog = startWatchdog;
}
EvtContextQueue::EvtContextQueue() : TSPriorityQueue<EvtContext>(offsetof(EvtContext, m_schedNextWakeTime)) {
}

57
src/event/EvtContext.hpp Normal file
View file

@ -0,0 +1,57 @@
#ifndef EVENT_EVT_CONTEXT_HPP
#define EVENT_EVT_CONTEXT_HPP
#include "event/EvtHandler.hpp"
#include "event/EvtKeyDown.hpp"
#include "event/EvtMessage.hpp"
#include "event/EvtTimer.hpp"
#include "event/Types.hpp"
#include <cstdint>
#include <common/Instance.hpp>
#include <common/Prop.hpp>
#include <storm/Queue.hpp>
#include <storm/Thread.hpp>
class EvtContext : public TSingletonInstanceId<EvtContext, offsetof(TInstanceId<EvtContext>, m_id)> {
public:
// Types
enum SCHEDSTATE {
SCHEDSTATE_ACTIVE = 0x0,
SCHEDSTATE_CLOSED = 0x1,
SCHEDSTATE_DESTROYED = 0x2,
_UNIQUE_SYMBOL_SCHEDSTATE_96 = 0xFFFFFFFF,
};
// Member variables
SCritSect m_critsect;
uint32_t m_currTime;
SCHEDSTATE m_schedState;
TSTimerPriority<uint32_t> m_schedNextWakeTime;
uint32_t m_schedLastIdle;
uint32_t m_schedFlags;
uint32_t m_schedIdleTime;
uint32_t m_schedInitialIdleTime;
uint32_t m_schedWeight;
uint32_t m_schedSmoothWeight;
int32_t m_schedRebalance;
TSExplicitList<EvtHandler, offsetof(EvtHandler, link)> m_queueHandlerList[EVENTIDS];
TSExplicitList<EvtMessage, offsetof(EvtMessage, link)> m_queueMessageList;
uint32_t m_queueSyncButtonState;
TSExplicitList<EvtKeyDown, offsetof(EvtKeyDown, link)> m_queueSyncKeyDownList;
// TODO
// EvtIdTable<EvtTimer*> m_timerIdTable;
EvtTimerQueue m_timerQueue;
HPROPCONTEXT m_propContext;
void* m_callContext;
uint32_t m_startWatchdog;
// Member functions
EvtContext(uint32_t, uint32_t, uint32_t, void*, int32_t);
};
class EvtContextQueue : public TSPriorityQueue<EvtContext> {
public:
EvtContextQueue();
};
#endif

17
src/event/EvtHandler.hpp Normal file
View file

@ -0,0 +1,17 @@
#ifndef EVENT_EVT_HANDLER_HPP
#define EVENT_EVT_HANDLER_HPP
#include <cstdint>
#include <storm/List.hpp>
class EvtHandler {
public:
// Member variables
TSLink<EvtHandler> link;
int32_t (*func)(const void*, void*);
void* param;
float priority;
int32_t marker;
};
#endif

14
src/event/EvtKeyDown.hpp Normal file
View file

@ -0,0 +1,14 @@
#ifndef EVENT_EVT_KEY_DOWN_HPP
#define EVENT_EVT_KEY_DOWN_HPP
#include "event/Types.hpp"
#include <storm/List.hpp>
class EvtKeyDown {
public:
// Member variables
TSLink<EvtKeyDown> link;
KEY key;
};
#endif

16
src/event/EvtMessage.hpp Normal file
View file

@ -0,0 +1,16 @@
#ifndef EVENT_EVT_MESSAGE_HPP
#define EVENT_EVT_MESSAGE_HPP
#include "event/Types.hpp"
#include <common/Instance.hpp>
#include <storm/List.hpp>
class EvtMessage : public TExtraInstanceRecyclable<EvtMessage> {
public:
// Member variables
TSLink<EvtMessage> link;
EVENTID id;
char data[4];
};
#endif

4
src/event/EvtThread.cpp Normal file
View file

@ -0,0 +1,4 @@
#include "event/EvtThread.hpp"
EvtThread::EvtThread() : TSLinkedNode<EvtThread>() {
}

25
src/event/EvtThread.hpp Normal file
View file

@ -0,0 +1,25 @@
#ifndef EVENT_EVT_THREAD_HPP
#define EVENT_EVT_THREAD_HPP
#include "event/EvtContext.hpp"
#include <cstdint>
#include <storm/List.hpp>
#include <storm/Thread.hpp>
class EvtThread : public TSLinkedNode<EvtThread> {
public:
// Member variables
uint32_t m_threadSlot;
uint32_t m_threadCount;
uint32_t m_weightTotal;
uint32_t m_weightAvg;
uint32_t m_contextCount;
uint32_t m_rebalance;
SEvent m_wakeEvent = SEvent(0, 0);
EvtContextQueue m_contextQueue;
// Member functions
EvtThread();
};
#endif

27
src/event/EvtTimer.hpp Normal file
View file

@ -0,0 +1,27 @@
#ifndef EVENT_EVT_TIMER_HPP
#define EVENT_EVT_TIMER_HPP
#include <cstdint>
#include <storm/Queue.hpp>
class EvtTimer {
public:
// Member variables
uint32_t id;
TSTimerPriority<uint32_t> targetTime;
float timeout;
int32_t (*handler)(const void*, void*);
void* param;
int32_t (*guidHandler)(const void*, uint64_t, void*);
uint64_t guidParam;
void* guidParam2;
};
class EvtTimerQueue : public TSPriorityQueue<EvtTimer> {
public:
EvtTimerQueue()
: TSPriorityQueue<EvtTimer>(offsetof(EvtTimer, targetTime))
{};
};
#endif

686
src/event/Input.cpp Normal file
View file

@ -0,0 +1,686 @@
#include "event/Input.hpp"
#include "event/EvtContext.hpp"
#include "event/Queue.hpp"
#include "gx/Window.hpp"
#include <common/Time.hpp>
#include <storm/String.hpp>
#include <storm/Unicode.hpp>
#include <tempest/Rect.hpp>
#include <tempest/Vector.hpp>
#if defined(WHOA_SYSTEM_MAC)
#include "app/mac/MacClient.h"
#endif
namespace Input {
CRect s_boundingRect;
int32_t s_queueHead;
int32_t s_queueTail;
OSEVENT s_queue[32];
MOUSEBUTTON s_buttonConversion[16] = {
MOUSE_BUTTON_NONE,
MOUSE_BUTTON_LEFT,
MOUSE_BUTTON_RIGHT,
MOUSE_BUTTON_MIDDLE,
MOUSE_BUTTON_XBUTTON1,
MOUSE_BUTTON_XBUTTON2,
MOUSE_BUTTON_XBUTTON3,
MOUSE_BUTTON_XBUTTON4,
MOUSE_BUTTON_XBUTTON5,
MOUSE_BUTTON_XBUTTON6,
MOUSE_BUTTON_XBUTTON7,
MOUSE_BUTTON_XBUTTON8,
MOUSE_BUTTON_XBUTTON9,
MOUSE_BUTTON_XBUTTON10,
MOUSE_BUTTON_XBUTTON11,
MOUSE_BUTTON_XBUTTON12,
};
}
int32_t Input::s_buttonDown[16];
uint32_t Input::s_buttonState;
C2iVector Input::s_currentMouse;
uint32_t Input::s_mouseHoldButton;
MOUSEMODE Input::s_mouseMode;
int32_t Input::s_numlockState;
int32_t Input::s_simulatedRightButtonClick;
uint32_t Input::s_metaKeyState;
#if defined(WHOA_SYSTEM_WIN)
int32_t Input::s_savedMouseSpeed;
#endif
#if defined(WHOA_SYSTEM_MAC)
double Input::s_savedMouseSpeed;
#endif
void PostChar(EvtContext* context, int32_t ch, int32_t repeat) {
EVENT_DATA_CHAR data;
data.ch = ch;
data.metaKeyState = Input::s_metaKeyState;
data.repeat = repeat;
IEvtQueueDispatch(context, EVENT_ID_CHAR, &data);
}
void PostKeyDown(EvtContext* context, int32_t key, int32_t repeat, int32_t time) {
if (key <= KEY_LASTMETAKEY) {
if ((1 << key) & Input::s_metaKeyState) {
return;
}
Input::s_metaKeyState |= 1 << key;
}
EVENT_DATA_KEY data;
data.key = static_cast<KEY>(key);
data.metaKeyState = Input::s_metaKeyState;
data.repeat = repeat;
data.time = time;
IEvtQueueDispatch(context, EVENT_ID_KEYDOWN, &data);
}
void PostKeyUp(EvtContext* context, int32_t key, int32_t repeat, int32_t time) {
if (key <= KEY_LASTMETAKEY) {
if ( !((1 << key) & Input::s_metaKeyState) ) {
return;
}
Input::s_metaKeyState &= ~(1 << key);
}
EVENT_DATA_KEY data;
data.key = static_cast<KEY>(key);
data.metaKeyState = Input::s_metaKeyState;
data.repeat = repeat;
data.time = time;
IEvtQueueDispatch(context, EVENT_ID_KEYUP, &data);
}
void PostMouseDown(EvtContext* context, MOUSEBUTTON button, int32_t x, int32_t y, int32_t time) {
Input::s_buttonState |= button;
EVENT_DATA_MOUSE data;
data.mode = Input::s_mouseMode;
data.button = button;
data.buttonState = Input::s_buttonState;
data.metaKeyState = Input::s_metaKeyState;
data.flags = GenerateMouseFlags();
data.time = time;
ConvertPosition(x, y, &data.x, &data.y);
IEvtQueueDispatch(context, EVENT_ID_MOUSEDOWN, &data);
}
void PostMouseMove(EvtContext* context, int32_t x, int32_t y, int32_t time) {
EVENT_DATA_MOUSE data;
data.mode = Input::s_mouseMode;
data.button = MOUSE_BUTTON_NONE;
data.buttonState = Input::s_buttonState;
data.metaKeyState = Input::s_metaKeyState;
data.flags = GenerateMouseFlags();
data.time = time;
ConvertPosition(x, y, &data.x, &data.y);
IEvtQueueDispatch(context, EVENT_ID_MOUSEMOVE, &data);
}
void PostMouseUp(EvtContext* context, MOUSEBUTTON button, int32_t x, int32_t y, uint32_t flags, int32_t time) {
Input::s_buttonState &= ~button;
EVENT_DATA_MOUSE data;
data.mode = Input::s_mouseMode;
data.button = button;
data.buttonState = Input::s_buttonState;
data.metaKeyState = Input::s_metaKeyState;
data.flags = flags | GenerateMouseFlags();
data.time = time;
ConvertPosition(x, y, &data.x, &data.y);
IEvtQueueDispatch(context, EVENT_ID_MOUSEUP, &data);
CheckMouseModeState();
}
void PostSize(EvtContext* context, int32_t w, int32_t h) {
EVENT_DATA_SIZE data;
data.w = w;
data.h = h;
IEvtQueueDispatch(context, EVENT_ID_SIZE, &data);
}
void ProcessInput(const int32_t param[], OSINPUT id, int32_t* shutdown, EvtContext* context) {
if (!context) {
// TODO
// nullsub_3();
// SErrSetLastError(0x57u);
}
switch (id) {
case OS_INPUT_CAPTURE_CHANGED:
// TODO
break;
case OS_INPUT_CHAR:
PostChar(
context,
param[0],
param[1]
);
break;
case OS_INPUT_STRING:
// TODO
break;
case OS_INPUT_IME:
// TODO
break;
case OS_INPUT_SIZE:
PostSize(
context,
param[0],
param[1]
);
break;
case OS_INPUT_CLOSE:
// TODO
break;
case OS_INPUT_FOCUS:
// TODO
break;
case OS_INPUT_KEY_DOWN:
PostKeyDown(
context,
param[0],
param[1],
param[3]
);
break;
case OS_INPUT_KEY_UP:
PostKeyUp(
context,
param[0],
param[1],
param[3]
);
break;
case OS_INPUT_MOUSE_DOWN:
PostMouseDown(
context,
static_cast<MOUSEBUTTON>(param[0]),
param[1],
param[2],
param[3]
);
break;
case OS_INPUT_MOUSE_MOVE:
PostMouseMove(
context,
param[1],
param[2],
param[3]
);
break;
case OS_INPUT_MOUSE_WHEEL:
// TODO
break;
case OS_INPUT_MOUSE_MOVE_RELATIVE:
// TODO
break;
case OS_INPUT_MOUSE_UP:
PostMouseUp(
context,
static_cast<MOUSEBUTTON>(param[0]),
param[1],
param[2],
0,
param[3]
);
break;
case OS_INPUT_14:
// TODO
break;
case OS_INPUT_15:
// TODO
break;
case OS_INPUT_16:
// TODO
break;
case OS_INPUT_17:
// TODO
break;
case OS_INPUT_18:
// TODO
break;
case OS_INPUT_SHUTDOWN:
// TODO
break;
}
}
void CheckMouseModeState() {
if (Input::s_mouseHoldButton) {
if (Input::s_mouseHoldButton != (Input::s_mouseHoldButton & Input::s_buttonState)) {
// TODO
// EventSetMouseMode(0, 0);
}
}
}
MOUSEBUTTON ConvertButtonNumberToMOUSEBUTTON(int32_t buttonNumber) {
return Input::s_buttonConversion[buttonNumber];
}
void ConvertPosition(int32_t clientx, int32_t clienty, float* x, float* y) {
if (Input::s_boundingRect.maxX - Input::s_boundingRect.minX != 0.0 && Input::s_boundingRect.maxY - Input::s_boundingRect.minY != 0.0) {
C2Vector pt = {
static_cast<float>(clientx),
static_cast<float>(clienty)
};
if (!Input::s_boundingRect.IsPointInside(pt)) {
// TODO
// - handle out of bounds positions
}
}
tagRECT windowDim;
OsGetDefaultWindowRect(&windowDim);
*x = static_cast<float>(clientx) / static_cast<float>(windowDim.right - windowDim.left);
*y = 1.0 - (static_cast<float>(clienty) / static_cast<float>(windowDim.bottom - windowDim.top));
}
uint32_t GenerateMouseFlags() {
uint32_t flags = 0;
if (Input::s_mouseMode == MOUSE_MODE_RELATIVE) {
flags |= 0x2;
}
return flags;
}
const char* GetButtonName(int32_t button) {
switch (button) {
case 0x1:
return "LeftButton";
case 0x2:
return "MiddleButton";
case 0x4:
return "RightButton";
case 0x8:
return "Button4";
case 0x10:
return "Button5";
case 0x20:
return "Button6";
case 0x40:
return "Button7";
case 0x80:
return "Button8";
case 0x100:
return "Button9";
case 0x200:
return "Button10";
case 0x400:
return "Button11";
case 0x800:
return "Button12";
case 0x1000:
return "Button13";
case 0x2000:
return "Button14";
case 0x4000:
return "Button15";
case 0x8000:
return "Button16";
case 0x10000:
return "Button17";
case 0x20000:
return "Button18";
case 0x40000:
return "Button19";
case 0x80000:
return "Button20";
case 0x100000:
return "Button21";
case 0x200000:
return "Button22";
case 0x400000:
return "Button23";
case 0x800000:
return "Button24";
case 0x1000000:
return "Button25";
case 0x2000000:
return "Button26";
case 0x4000000:
return "Button27";
case 0x8000000:
return "Button28";
case 0x10000000:
return "Button29";
case 0x20000000:
return "Button30";
case 0x40000000:
return "Button31";
default:
return "UNKNOWN";
}
}
void IEvtInputInitialize() {
OsInputInitialize();
}
int32_t IEvtInputProcess(EvtContext* context, int32_t* shutdown) {
if (context) {
// TODO
// nullsub_3();
int32_t v4 = 0;
OSINPUT id;
int32_t param[4];
while (OsInputGet(&id, &param[0], &param[1], &param[2], &param[3])) {
v4 = 1;
ProcessInput(param, id, shutdown, context);
}
return v4;
} else {
// TODO
// nullsub_3();
// SErrSetLastError(0x57u);
return 0;
}
}
const char* KeyCodeToString(KEY key) {
static char charBuf[8];
if (key - 33 <= 222) {
SUniSPutUTF8(key, charBuf);
return charBuf;
}
if (key <= KEY_SPACE) {
switch (key) {
case KEY_NONE:
return "NONE";
case KEY_LSHIFT:
return "LSHIFT";
case KEY_RSHIFT:
return "RSHIFT";
case KEY_LCONTROL:
return "LCTRL";
case KEY_RCONTROL:
return "RCTRL";
case KEY_LALT:
return "LALT";
case KEY_RALT:
return "RALT";
case KEY_SPACE:
return "SPACE";
default:
return "UNKNOWN";
}
}
if (key <= KEY_ESCAPE) {
switch (key) {
case KEY_NUMPAD0:
case KEY_NUMPAD1:
case KEY_NUMPAD2:
case KEY_NUMPAD3:
case KEY_NUMPAD4:
case KEY_NUMPAD5:
case KEY_NUMPAD6:
case KEY_NUMPAD7:
case KEY_NUMPAD8:
case KEY_NUMPAD9:
SStrPrintf(charBuf, sizeof(charBuf), "NUMPAD%d", key);
return charBuf;
case KEY_NUMPAD_PLUS:
return "NUMPADPLUS";
case KEY_NUMPAD_MINUS:
return "NUMPADMINUS";
case KEY_NUMPAD_MULTIPLY:
return "NUMPADMULTIPLY";
case KEY_NUMPAD_DIVIDE:
return "NUMPADDIVIDE";
case KEY_NUMPAD_DECIMAL:
return "NUMPADDECIMAL";
case KEY_ESCAPE:
return "ESCAPE";
default:
return "UNKNOWN";
}
}
if (key <= KEY_PRINTSCREEN) {
switch (key) {
case KEY_ENTER:
return "ENTER";
case KEY_BACKSPACE:
return "BACKSPACE";
case KEY_TAB:
return "TAB";
case KEY_LEFT:
return "LEFT";
case KEY_UP:
return "UP";
case KEY_RIGHT:
return "RIGHT";
case KEY_DOWN:
return "DOWN";
case KEY_INSERT:
return "INSERT";
case KEY_DELETE:
return "DELETE";
case KEY_HOME:
return "HOME";
case KEY_END:
return "END";
case KEY_PAGEUP:
return "PAGEUP";
case KEY_PAGEDOWN:
return "PAGEDOWN";
case KEY_CAPSLOCK:
return "CAPSLOCK";
case KEY_NUMLOCK:
return "NUMLOCK";
case KEY_PRINTSCREEN:
return "PRINTSCREEN";
default:
return "UNKNOWN";
}
}
if (key <= KEY_F12) {
switch (key) {
case KEY_F1:
case KEY_F2:
case KEY_F3:
case KEY_F4:
case KEY_F5:
case KEY_F6:
case KEY_F7:
case KEY_F8:
case KEY_F9:
case KEY_F10:
case KEY_F11:
case KEY_F12:
SStrPrintf(charBuf, sizeof(charBuf), "F%d", key - KEY_F1 + 1);
return charBuf;
default:
return "UNKNOWN";
}
}
if (key == KEY_NUMPAD_EQUALS) {
return "NUMPADEQUALS";
}
return "UNKNOWN";
}
int32_t OsInputGet(OSINPUT* id, int32_t* param0, int32_t* param1, int32_t* param2, int32_t* param3) {
#if defined(WHOA_SYSTEM_WIN)
// TODO
#endif
#if defined(WHOA_SYSTEM_MAC)
// TODO
// Unknown logic
if (!OsInputIsUsingCocoaEventLoop()) {
// Legacy Carbon input handling
return 0;
}
// TODO
// Steelseries WoW Mouse logic
if (Input::s_queueTail == Input::s_queueHead) {
return 0;
}
OsQueueSetParam(3, OsGetAsyncTimeMs());
return OsQueueGet(id, param0, param1, param2, param3);
#endif
}
void OsInputInitialize() {
#if defined(WHOA_SYSTEM_WIN)
Input::s_numlockState = GetAsyncKeyState(144);
PVOID pvParam = 10;
SystemParametersInfoA(SPI_GETMOUSESPEED, 0, &pvParam, 0);
Input::s_savedMouseSpeed = pvParam;
#endif
#if defined(WHOA_SYSTEM_MAC)
// Legacy Carbon input handling
// if (!byte_143EFE0) {
// Carbon_OsInputRegisterHICommandHandler(0x71756974, sub_A4F230);
// }
MacClient::SetMouseCoalescingEnabled(true);
Input::s_savedMouseSpeed = MacClient::GetMouseSpeed();
#endif
}
bool OsInputIsUsingCocoaEventLoop() {
// TODO
return true;
}
void OsInputPostEvent(OSINPUT id, int32_t param0, int32_t param1, int32_t param2, int32_t param3) {
// TODO
}
int32_t OsQueueGet(OSINPUT* id, int32_t* param0, int32_t* param1, int32_t* param2, int32_t* param3) {
if (Input::s_queueTail == Input::s_queueHead) {
return 0;
}
OSEVENT event = Input::s_queue[Input::s_queueTail];
*id = event.id;
*param0 = event.param[0];
*param1 = event.param[1];
*param2 = event.param[2];
*param3 = event.param[3];
if (Input::s_queueTail == OS_QUEUE_SIZE - 1) {
Input:: s_queueTail = 0;
} else {
++Input::s_queueTail;
}
return 1;
}
void OsQueuePut(OSINPUT id, int32_t param0, int32_t param1, int32_t param2, int32_t param3) {
int32_t nextTail = 0;
int32_t nextHead = 0;
if (Input::s_queueHead != OS_QUEUE_SIZE - 1) {
nextHead = Input::s_queueHead + 1;
}
if (nextHead == Input::s_queueTail) {
if (nextHead != OS_QUEUE_SIZE - 1) {
nextTail = nextHead + 1;
}
Input::s_queueTail = nextTail;
}
OSEVENT* event = &Input::s_queue[Input::s_queueHead];
event->id = id;
event->param[0] = param0;
event->param[1] = param1;
event->param[2] = param2;
event->param[3] = param3;
Input::s_queueHead = nextHead;
}
void OsQueueSetParam(int32_t index, int32_t param) {
int32_t pos = Input::s_queueTail;
while (pos != Input::s_queueHead) {
OSEVENT* event = &Input::s_queue[pos];
event->param[index] = param;
if (pos == OS_QUEUE_SIZE - 1) {
pos = 0;
} else {
++pos;
}
}
}

62
src/event/Input.hpp Normal file
View file

@ -0,0 +1,62 @@
#ifndef EVENT_INPUT_HPP
#define EVENT_INPUT_HPP
#include "event/Types.hpp"
#include <cstdint>
#define OS_QUEUE_SIZE 32
class C2iVector;
class CRect;
class EvtContext;
namespace Input {
extern int32_t s_buttonDown[16];
extern uint32_t s_buttonState;
extern C2iVector s_currentMouse;
extern uint32_t s_mouseHoldButton;
extern MOUSEMODE s_mouseMode;
extern int32_t s_numlockState;
extern int32_t s_simulatedRightButtonClick;
extern uint32_t s_metaKeyState;
#if defined(WHOA_SYSTEM_WIN)
extern int32_t s_savedMouseSpeed;
#endif
#if defined(WHOA_SYSTEM_MAC)
extern double s_savedMouseSpeed;
#endif
}
void CheckMouseModeState(void);
MOUSEBUTTON ConvertButtonNumberToMOUSEBUTTON(int32_t);
void ConvertPosition(int32_t, int32_t, float*, float*);
uint32_t GenerateMouseFlags(void);
const char* GetButtonName(int32_t);
void IEvtInputInitialize();
int32_t IEvtInputProcess(EvtContext* context, int32_t* shutdown);
const char* KeyCodeToString(KEY);
int32_t OsInputGet(OSINPUT*, int32_t*, int32_t*, int32_t*, int32_t*);
void OsInputInitialize(void);
bool OsInputIsUsingCocoaEventLoop(void);
void OsInputPostEvent(OSINPUT, int32_t, int32_t, int32_t, int32_t);
int32_t OsQueueGet(OSINPUT*, int32_t*, int32_t*, int32_t*, int32_t*);
void OsQueuePut(OSINPUT, int32_t, int32_t, int32_t, int32_t);
void OsQueueSetParam(int32_t, int32_t);
#endif

74
src/event/Queue.cpp Normal file
View file

@ -0,0 +1,74 @@
#include "event/Queue.hpp"
#include "event/EvtContext.hpp"
#include "event/EvtHandler.hpp"
#include <storm/Error.hpp>
void IEvtQueueDispatch(EvtContext* context, EVENTID id, const void* data) {
STORM_ASSERT(context);
// TODO
// UpdateSyncState(data, &id, context, v3);
// TODO
// if (SErrIsDisplayingError()) {
// return;
// }
auto handlerList = &context->m_queueHandlerList[id];
EvtHandler marker;
marker.marker = 1;
handlerList->LinkNode(&marker, 1, nullptr);
EvtHandler* handler;
while (1) {
handler = marker.link.Next();
if (!handler) {
break;
}
handlerList->LinkNode(&marker, 1, marker.link.Next());
if (!handler->marker && !handler->func(data, handler->param)) {
break;
}
}
handlerList->UnlinkNode(&marker);
}
void IEvtQueueDispatchAll(EvtContext* context) {
// TODO
}
void IEvtQueueRegister(EvtContext* context, EVENTID id, int32_t (*handler)(const void*, void*), void* param, float priority) {
STORM_ASSERT(context);
auto handlerList = &context->m_queueHandlerList[id];
EvtHandler* evtHandler;
void* m = SMemAlloc(sizeof(EvtHandler), __FILE__, __LINE__, 0x8);
if (m) {
evtHandler = new (m) EvtHandler();
} else {
evtHandler = nullptr;
}
evtHandler->priority = priority;
evtHandler->param = param;
evtHandler->func = handler;
evtHandler->marker = 0;
EvtHandler* h = handlerList->Head();
while (h && (priority < h->priority || h->marker)) {
h = handlerList->Link(h)->Next();
}
handlerList->LinkNode(evtHandler, 1, h);
}

14
src/event/Queue.hpp Normal file
View file

@ -0,0 +1,14 @@
#ifndef EVENT_QUEUE_HPP
#define EVENT_QUEUE_HPP
#include "event/Types.hpp"
class EvtContext;
void IEvtQueueDispatch(EvtContext* context, EVENTID id, const void* data);
void IEvtQueueDispatchAll(EvtContext* context);
void IEvtQueueRegister(EvtContext* context, EVENTID id, int32_t (*handler)(const void*, void*), void* param, float priority);
#endif

382
src/event/Scheduler.cpp Normal file
View file

@ -0,0 +1,382 @@
#include "event/Scheduler.hpp"
#include "event/Context.hpp"
#include "event/Event.hpp"
#include "event/EvtContext.hpp"
#include "event/EvtThread.hpp"
#include "event/Input.hpp"
#include "event/Queue.hpp"
#include "event/Synthesize.hpp"
#include "event/Timer.hpp"
#include <algorithm>
#include <cstring>
#include <common/Call.hpp>
#include <common/Prop.hpp>
#include <common/Time.hpp>
#include <storm/Memory.hpp>
#include <storm/String.hpp>
#include <storm/Thread.hpp>
#if defined(WHOA_SYSTEM_MAC)
#include "event/mac/Event.h"
#endif
void DestroySchedulerThread(uint32_t a1) {
// TODO
}
HEVENTCONTEXT IEvtSchedulerCreateContext(int32_t interactive, int32_t (*initializeHandler)(const void*, void*), int32_t (*destroyHandler)(const void*, void*), uint32_t idleTime, uint32_t debugFlags) {
if (idleTime < 1) {
idleTime = 1;
}
char contextName[256];
void* callContext = nullptr;
if (debugFlags & 0x1) {
SStrPrintf(contextName, 256, "Context: interactive = %u, idleTime = %u", interactive, idleTime);
callContext = OsCallInitializeContext(contextName);
}
void* m = SMemAlloc(sizeof(EvtContext), __FILE__, __LINE__, 0);
EvtContext* context;
if (m) {
context = new (m) EvtContext(
interactive != 0 ? 2 : 0,
idleTime,
interactive != 0 ? 1000 : 1,
callContext,
(debugFlags >> 1) & 1
);
} else {
context = nullptr;
}
if (interactive) {
SInterlockedIncrement(&Event::s_interactiveCount);
}
if (initializeHandler) {
IEvtQueueRegister(context, EVENT_ID_INITIALIZE, initializeHandler, 0, 1000.0);
}
if (destroyHandler) {
IEvtQueueRegister(context, EVENT_ID_DESTROY, destroyHandler, 0, 1000.0);
}
return AttachContextToThread(context);
}
void IEvtSchedulerInitialize(int32_t threadCount, int32_t netServer) {
if (Event::s_threadSlotCount) {
// SErrDisplayAppFatal("IEvtScheduler already initialized");
}
Event::s_netServer = netServer;
// TODO
// Thread::s_originalThreadPriority = SGetCurrentThreadPriority();
int32_t threadSlotCount = 1;
while (threadSlotCount < threadCount) {
threadSlotCount *= 2;
}
Event::s_threadSlotCount = threadSlotCount;
// Allocate SCritSects for each thread slot
int32_t v4 = sizeof(SCritSect) * threadSlotCount;
void* v5 = SMemAlloc((v4 + 4), ".\\EvtSched.cpp", 791, 0);
if (v5) {
Event::s_threadSlotCritsects = new (v5) SCritSect[threadSlotCount];
} else {
Event::s_threadSlotCritsects = nullptr;
}
// Allocate EvtThread pointers for each thread slot
Event::s_threadSlots = static_cast<EvtThread**>(SMemAlloc(sizeof(EvtThread*) * threadSlotCount, __FILE__, __LINE__, 0));
memset(Event::s_threadSlots, 0, sizeof(EvtThread*) * threadSlotCount);
Event::s_startEvent.Reset();
Event::s_shutdownEvent.Reset();
Event::s_mainThread = InitializeSchedulerThread();
for (int32_t i = 0; i < threadCount - 1; ++i) {
void* m = SMemAlloc(sizeof(SThread), __FILE__, __LINE__, 0);
SThread* thread;
if (m) {
thread = new (m) SThread();
} else {
thread = nullptr;
}
Event::s_schedulerThreads.SetCount(Event::s_schedulerThreads.Count() + 1);
Event::s_schedulerThreads[Event::s_schedulerThreads.Count() - 1] = thread;
char threadName[16];
SStrPrintf(threadName, 16, "EvtSched#%d", i);
if (!SThread::Create(&SchedulerThreadProc, 0, *thread, threadName, 0)) {
// TODO
}
}
}
void IEvtSchedulerProcess() {
#if defined(WHOA_SYSTEM_WIN)
Event::s_startEvent.Set();
SchedulerThreadProc(1);
Event::s_mainThread = 0;
#endif
#if defined(WHOA_SYSTEM_MAC)
Event::s_startEvent.Set();
if (OsInputIsUsingCocoaEventLoop()) {
PropSelectContext(0);
Event::s_startEvent.Wait(0xFFFFFFFF);
uintptr_t v0 = SGetCurrentThreadId();
char v2[64];
SStrPrintf(v2, 64, "Engine %x", v0);
OsCallInitialize(v2);
RunCocoaEventLoop();
DestroySchedulerThread(Event::s_mainThread);
OsCallDestroy();
Event::s_mainThread = 0;
} else {
// Legacy
// sub_890180(1);
// dword_141B3C8 = 0;
}
#endif
}
void IEvtSchedulerShutdown() {
// TODO
}
uint32_t InitializeSchedulerThread() {
SInterlockedIncrement(&Event::s_threadListContention);
Event::s_threadListCritsect.Enter();
uint32_t slot = Event::s_threadSlotCount;
for (int32_t i = 0; i < Event::s_threadSlotCount; ++i) {
if (slot == Event::s_threadSlotCount
|| Event::s_threadSlots[i] == nullptr
|| Event::s_threadSlots[i]->m_threadCount < Event::s_threadSlots[slot]->m_threadCount)
{
slot = i;
if (!Event::s_threadSlots[i]) {
break;
}
}
}
EvtThread* v4 = Event::s_threadSlots[slot];
if (!v4) {
v4 = Event::s_threadList.NewNode(1, 0, 0x8);
v4->m_threadCount = 0;
v4->m_weightTotal = 0;
v4->m_weightAvg = 0;
v4->m_contextCount = 0;
v4->m_rebalance = 0;
v4->m_threadSlot = slot;
Event::s_threadSlotCritsects[slot].Enter();
Event::s_threadSlots[slot] = v4;
Event::s_threadSlotCritsects[slot].Leave();
}
++v4->m_threadCount;
Event::s_threadListCritsect.Leave();
SInterlockedDecrement(&Event::s_threadListContention);
return slot;
}
bool SchedulerMainProcess() {
return SchedulerThreadProcProcess(Event::s_mainThread) != 0;
}
uint32_t SchedulerThreadProc(void* mainThread) {
uint32_t v1;
if (mainThread) {
v1 = Event::s_mainThread;
} else {
v1 = InitializeSchedulerThread();
}
PropSelectContext(0);
Event::s_startEvent.Wait(0xFFFFFFFF);
uintptr_t v2 = SGetCurrentThreadId();
char v4[64];
SStrPrintf(v4, 64, "Engine %x", v2);
OsCallInitialize(v4);
while (!SchedulerThreadProcProcess(v1));
DestroySchedulerThread(v1);
OsCallDestroy();
return 0;
}
int32_t SchedulerThreadProcProcess(uint32_t a1) {
// TODO
// if (SGetCurrentThreadPriority() != Event::s_originalThreadPriority) {
// SSetCurrentThreadPriority(Event::s_originalThreadPriority);
// }
if (!Event::s_shutdownEvent.Wait(0)) {
return 1;
}
EvtContext* context = GetNextContext(a1);
int32_t v11;
if (context) {
v11 = context->m_schedNextWakeTime.m_val - OsGetAsyncTimeMs();
if (v11 < 0) {
v11 = 0;
}
}
uint32_t v14;
if (Event::s_netServer) {
if (v11 == -1) {
v11 = 100;
}
OsNetPump(v11);
v14 = 258;
} else {
v14 = Event::s_threadSlots[a1]->m_wakeEvent.Wait(v11);
}
if (!context) {
return 0;
}
PropSelectContext(context->m_propContext);
PropSet(PROP_EVENTCONTEXT, &context->m_id);
OsCallSetContext(context->m_callContext);
uint32_t currTime = OsGetAsyncTimeMs();
uint32_t v19 = context->m_id;
if (v14 == 258) {
if (SynthesizeInitialize(context)) {
if (context->m_startWatchdog) {
// nullsub_5(20, 1);
// *a2 = 1;
}
}
uint32_t v9 = (currTime - context->m_schedLastIdle);
context->m_schedLastIdle = currTime;
double elapsedSec = v9 * 0.001;
// TODO
// FrameTime::Update(currTime, elapsedSec);
IEvtTimerDispatch(context);
if (context->m_schedFlags & 0x2) {
int32_t shutdown = 0;
IEvtInputProcess(context, &shutdown);
if (shutdown) {
context->m_critsect.Enter();
if (context->m_schedState == EvtContext::SCHEDSTATE_ACTIVE) {
context->m_schedState = EvtContext::SCHEDSTATE_CLOSED;
}
context->m_critsect.Leave();
IEvtSchedulerShutdown();
}
}
SynthesizePoll(context);
IEvtQueueDispatchAll(context);
SynthesizeIdle(context, currTime, elapsedSec);
SynthesizePaint(context);
}
if (a1 == Event::s_mainThread) {
// TODO
// dword_B417C4 = 0;
}
context->m_critsect.Enter();
uint32_t closed = context->m_schedState == EvtContext::SCHEDSTATE_CLOSED;
context->m_critsect.Leave();
if (closed) {
DetachContextFromThread(a1, context);
SynthesizeDestroy(context);
return 0;
}
uint32_t nextDelay;
if (context->m_schedFlags & 0x4) {
nextDelay = 0;
} else {
int32_t v15 = IEvtTimerGetNextTime(context, currTime);
int32_t v16 = context->m_schedIdleTime;
nextDelay = v15;
if (v16 != context->m_schedInitialIdleTime) {
nextDelay = context->m_schedIdleTime;
}
nextDelay = std::min(
nextDelay,
std::max((uint32_t)0, v16 + context->m_schedLastIdle - currTime)
);
}
OsCallResetContext(context->m_callContext);
PropSelectContext(nullptr);
PutContext(nextDelay + currTime, context->m_schedSmoothWeight, context, a1);
return 0;
}

25
src/event/Scheduler.hpp Normal file
View file

@ -0,0 +1,25 @@
#ifndef EVENT_SCHEDULER_HPP
#define EVENT_SCHEDULER_HPP
#include "event/Types.hpp"
#include <cstdint>
void DestroySchedulerThread(uint32_t a1);
HEVENTCONTEXT IEvtSchedulerCreateContext(int32_t interactive, int32_t (*initializeHandler)(const void*, void*), int32_t (*destroyHandler)(const void*, void*), uint32_t idleTime, uint32_t debugFlags);
void IEvtSchedulerInitialize(int32_t threadCount, int32_t netServer);
void IEvtSchedulerProcess();
void IEvtSchedulerShutdown();
uint32_t InitializeSchedulerThread();
bool SchedulerMainProcess();
uint32_t SchedulerThreadProc(void* mainThread);
int32_t SchedulerThreadProcProcess(uint32_t a1);
#endif

81
src/event/Synthesize.cpp Normal file
View file

@ -0,0 +1,81 @@
#include "event/Synthesize.hpp"
#include "event/EvtContext.hpp"
#include "event/Queue.hpp"
#include <common/Time.hpp>
void SynthesizeDestroy(EvtContext* context) {
// TODO
exit(0);
}
void SynthesizeIdle(EvtContext* context, uint32_t currTime, float elapsedSec) {
bool closed;
context->m_critsect.Enter();
closed = context->m_schedState == EvtContext::SCHEDSTATE_CLOSED;
context->m_critsect.Leave();
if (closed) {
return;
}
uint32_t schedFlags = context->m_schedFlags;
if (schedFlags & 0x2) {
context->m_schedFlags = schedFlags | 0x4;
}
EVENT_DATA_IDLE data;
data.elapsedSec = elapsedSec;
data.time = currTime;
IEvtQueueDispatch(context, EVENT_ID_IDLE, &data);
}
int32_t SynthesizeInitialize(EvtContext* context) {
uint32_t schedFlags = context->m_schedFlags;
if (schedFlags & 0x1) {
return 0;
}
context->m_schedFlags = schedFlags | 0x1;
context->m_schedLastIdle = OsGetAsyncTimeMs();
IEvtQueueDispatch(context, EVENT_ID_INITIALIZE, nullptr);
return 1;
}
void SynthesizePaint(EvtContext* context) {
bool closed;
context->m_critsect.Enter();
closed = context->m_schedState == EvtContext::SCHEDSTATE_CLOSED;
context->m_critsect.Leave();
if (closed) {
return;
}
uint32_t schedFlags = context->m_schedFlags;
if (schedFlags & 0x4) {
context->m_schedFlags = schedFlags & ~0x4;
IEvtQueueDispatch(context, EVENT_ID_PAINT, nullptr);
}
}
void SynthesizePoll(EvtContext* context) {
bool closed;
context->m_critsect.Enter();
closed = context->m_schedState == EvtContext::SCHEDSTATE_CLOSED;
context->m_critsect.Leave();
if (closed) {
return;
}
IEvtQueueDispatch(context, EVENT_ID_POLL, nullptr);
}

18
src/event/Synthesize.hpp Normal file
View file

@ -0,0 +1,18 @@
#ifndef EVENT_SYNTHESIZE_HPP
#define EVENT_SYNTHESIZE_HPP
#include <cstdint>
class EvtContext;
void SynthesizeDestroy(EvtContext* context);
void SynthesizeIdle(EvtContext* context, uint32_t currTime, float elapsedSec);
int32_t SynthesizeInitialize(EvtContext* context);
void SynthesizePaint(EvtContext* context);
void SynthesizePoll(EvtContext* context);
#endif

29
src/event/Timer.cpp Normal file
View file

@ -0,0 +1,29 @@
#include "event/Timer.hpp"
#include "event/EvtContext.hpp"
#include "event/EvtTimer.hpp"
#include <storm/Error.hpp>
int32_t IEvtTimerDispatch(EvtContext* context) {
// TODO
return 0;
}
uint32_t IEvtTimerGetNextTime(EvtContext* context, uint32_t currTime) {
STORM_ASSERT(context);
context->m_critsect.Enter();
uint32_t nextTime = -1;
if (context->m_timerQueue.Count()) {
auto queue = static_cast<EvtTimer*>(context->m_timerQueue[0]);
auto targetTime = queue->targetTime.m_val;
nextTime = targetTime - currTime;
nextTime = nextTime < 0 ? 0 : nextTime;
}
context->m_critsect.Leave();
return nextTime;
}

12
src/event/Timer.hpp Normal file
View file

@ -0,0 +1,12 @@
#ifndef EVENT_TIMER_HPP
#define EVENT_TIMER_HPP
#include <cstdint>
class EvtContext;
int32_t IEvtTimerDispatch(EvtContext* context);
uint32_t IEvtTimerGetNextTime(EvtContext* context, uint32_t currTime);
#endif

252
src/event/Types.hpp Normal file
View file

@ -0,0 +1,252 @@
#ifndef EVENT_TYPES_HPP
#define EVENT_TYPES_HPP
#include <cstdint>
typedef void* HEVENTCONTEXT;
typedef int32_t (*EVENTHANDLERFUNC)(const void*, void*);
enum EVENTID {
EVENT_ID_0 = 0,
EVENT_ID_CHAR = 1,
EVENT_ID_FOCUS = 2,
EVENT_ID_3 = 3,
EVENT_ID_DESTROY = 4,
EVENT_ID_5 = 5,
EVENT_ID_IDLE = 6,
EVENT_ID_POLL = 7,
EVENT_ID_INITIALIZE = 8,
EVENT_ID_KEYDOWN = 9,
EVENT_ID_KEYUP = 10,
EVENT_ID_KEYDOWN_REPEATING = 11,
EVENT_ID_MOUSEDOWN = 12,
EVENT_ID_MOUSEMOVE = 13,
EVENT_ID_MOUSEMOVE_RELATIVE = 14,
EVENT_ID_MOUSEUP = 15,
EVENT_ID_MOUSEMODE_CHANGED = 16,
EVENT_ID_MOUSEWHEEL = 17,
EVENT_ID_18 = 18,
EVENT_ID_19 = 19,
EVENT_ID_20 = 20,
EVENT_ID_21 = 21,
EVENT_ID_22 = 22,
EVENT_ID_PAINT = 23,
EVENT_ID_24 = 24,
EVENT_ID_25 = 25,
EVENT_ID_26 = 26,
EVENT_ID_27 = 27,
EVENT_ID_28 = 28,
EVENT_ID_29 = 29,
EVENT_ID_30 = 30,
EVENT_ID_31 = 31,
EVENT_ID_32 = 32,
EVENT_ID_33 = 33,
EVENT_ID_IME = 34,
EVENT_ID_SIZE = 35,
EVENTIDS = 36
};
enum KEY {
KEY_NONE = 0xFFFFFFFF,
KEY_LSHIFT = 0x0,
KEY_RSHIFT = 0x1,
KEY_LCONTROL = 0x2,
KEY_RCONTROL = 0x3,
KEY_LALT = 0x4,
KEY_RALT = 0x5,
KEY_LASTMETAKEY = 0x5,
KEY_SPACE = 0x20,
KEY_0 = 0x30,
KEY_1 = 0x31,
KEY_2 = 0x32,
KEY_3 = 0x33,
KEY_4 = 0x34,
KEY_5 = 0x35,
KEY_6 = 0x36,
KEY_7 = 0x37,
KEY_8 = 0x38,
KEY_9 = 0x39,
KEY_A = 0x41,
KEY_B = 0x42,
KEY_C = 0x43,
KEY_D = 0x44,
KEY_E = 0x45,
KEY_F = 0x46,
KEY_G = 0x47,
KEY_H = 0x48,
KEY_I = 0x49,
KEY_J = 0x4A,
KEY_K = 0x4B,
KEY_L = 0x4C,
KEY_M = 0x4D,
KEY_N = 0x4E,
KEY_O = 0x4F,
KEY_P = 0x50,
KEY_Q = 0x51,
KEY_R = 0x52,
KEY_S = 0x53,
KEY_T = 0x54,
KEY_U = 0x55,
KEY_V = 0x56,
KEY_W = 0x57,
KEY_X = 0x58,
KEY_Y = 0x59,
KEY_Z = 0x5A,
KEY_TILDE = 0x60,
KEY_NUMPAD0 = 0x100,
KEY_NUMPAD1 = 0x101,
KEY_NUMPAD2 = 0x102,
KEY_NUMPAD3 = 0x103,
KEY_NUMPAD4 = 0x104,
KEY_NUMPAD5 = 0x105,
KEY_NUMPAD6 = 0x106,
KEY_NUMPAD7 = 0x107,
KEY_NUMPAD8 = 0x108,
KEY_NUMPAD9 = 0x109,
KEY_NUMPAD_PLUS = 0x10A,
KEY_NUMPAD_MINUS = 0x10B,
KEY_NUMPAD_MULTIPLY = 0x10C,
KEY_NUMPAD_DIVIDE = 0x10D,
KEY_NUMPAD_DECIMAL = 0x10E,
KEY_NUMPAD_EQUALS = 0x30C,
KEY_PLUS = 0x3D,
KEY_MINUS = 0x2D,
KEY_BRACKET_OPEN = 0x5B,
KEY_BRACKET_CLOSE = 0x5D,
KEY_SLASH = 0x2F,
KEY_BACKSLASH = 0x5C,
KEY_SEMICOLON = 0x3B,
KEY_APOSTROPHE = 0x27,
KEY_COMMA = 0x2C,
KEY_PERIOD = 0x2E,
KEY_ESCAPE = 0x200,
KEY_ENTER = 0x201,
KEY_BACKSPACE = 0x202,
KEY_TAB = 0x203,
KEY_LEFT = 0x204,
KEY_UP = 0x205,
KEY_RIGHT = 0x206,
KEY_DOWN = 0x207,
KEY_INSERT = 0x208,
KEY_DELETE = 0x209,
KEY_HOME = 0x20A,
KEY_END = 0x20B,
KEY_PAGEUP = 0x20C,
KEY_PAGEDOWN = 0x20D,
KEY_CAPSLOCK = 0x20E,
KEY_NUMLOCK = 0x20F,
KEY_SCROLLLOCK = 0x210,
KEY_PAUSE = 0x211,
KEY_PRINTSCREEN = 0x212,
KEY_F1 = 0x300,
KEY_F2 = 0x301,
KEY_F3 = 0x302,
KEY_F4 = 0x303,
KEY_F5 = 0x304,
KEY_F6 = 0x305,
KEY_F7 = 0x306,
KEY_F8 = 0x307,
KEY_F9 = 0x308,
KEY_F10 = 0x309,
KEY_F11 = 0x30A,
KEY_F12 = 0x30B,
KEY_F13 = 0x212,
KEY_F14 = 0x30D,
KEY_F15 = 0x30E,
KEY_F16 = 0x30F,
KEY_F17 = 0x310,
KEY_F18 = 0x311,
KEY_F19 = 0x312,
KEY_LAST = 0x313
};
enum MOUSEBUTTON {
MOUSE_BUTTON_NONE = 0x0,
MOUSE_BUTTON_LEFT = 0x1,
MOUSE_BUTTON_MIDDLE = 0x2,
MOUSE_BUTTON_RIGHT = 0x4,
MOUSE_BUTTON_XBUTTON1 = 0x8,
MOUSE_BUTTON_XBUTTON2 = 0x10,
MOUSE_BUTTON_XBUTTON3 = 0x20,
MOUSE_BUTTON_XBUTTON4 = 0x40,
MOUSE_BUTTON_XBUTTON5 = 0x80,
MOUSE_BUTTON_XBUTTON6 = 0x100,
MOUSE_BUTTON_XBUTTON7 = 0x200,
MOUSE_BUTTON_XBUTTON8 = 0x400,
MOUSE_BUTTON_XBUTTON9 = 0x800,
MOUSE_BUTTON_XBUTTON10 = 0x1000,
MOUSE_BUTTON_XBUTTON11 = 0x2000,
MOUSE_BUTTON_XBUTTON12 = 0x4000,
MOUSE_BUTTON_ALL = 0xFFFFFFFF
};
enum MOUSEMODE {
MOUSE_MODE_NORMAL = 0x0,
MOUSE_MODE_RELATIVE = 0x1,
MOUSE_MODES = 0x2
};
enum OSINPUT {
OS_INPUT_CAPTURE_CHANGED = 0,
OS_INPUT_CHAR = 1,
OS_INPUT_STRING = 2,
OS_INPUT_IME = 3,
OS_INPUT_SIZE = 4,
OS_INPUT_CLOSE = 5,
OS_INPUT_FOCUS = 6,
OS_INPUT_KEY_DOWN = 7,
OS_INPUT_KEY_UP = 8,
OS_INPUT_MOUSE_DOWN = 9,
OS_INPUT_MOUSE_MOVE = 10,
OS_INPUT_MOUSE_WHEEL = 11,
OS_INPUT_MOUSE_MOVE_RELATIVE = 12,
OS_INPUT_MOUSE_UP = 13,
OS_INPUT_14 = 14,
OS_INPUT_15 = 15,
OS_INPUT_16 = 16,
OS_INPUT_17 = 17,
OS_INPUT_18 = 18,
OS_INPUT_SHUTDOWN = 19
};
struct OSEVENT {
OSINPUT id;
int32_t param[4];
};
struct EVENT_DATA_CHAR {
int32_t ch;
uint32_t metaKeyState;
uint32_t repeat;
};
struct EVENT_DATA_IDLE {
float elapsedSec;
uint32_t time;
};
struct EVENT_DATA_KEY {
KEY key;
uint32_t metaKeyState;
uint32_t repeat;
uint32_t time;
};
struct EVENT_DATA_MOUSE {
MOUSEMODE mode;
MOUSEBUTTON button;
uint32_t buttonState;
uint32_t metaKeyState;
uint32_t flags;
float x;
float y;
int32_t wheelDistance;
uint32_t time;
};
struct EVENT_DATA_SIZE {
int32_t w;
int32_t h;
};
#endif

6
src/event/mac/Event.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef EVENT_MAC_EVENT_H
#define EVENT_MAC_EVENT_H
void RunCocoaEventLoop();
#endif

9
src/event/mac/Event.mm Normal file
View file

@ -0,0 +1,9 @@
#include "event/mac/Event.h"
#include "event/Event.hpp"
#include <AppKit/AppKit.h>
void RunCocoaEventLoop() {
if (!Event::s_shouldLoopTerminate) {
[NSApp run];
}
}

View file

@ -0,0 +1,3 @@
#include "glue/CCharacterSelection.hpp"
TSGrowableArray<CharacterSelectionDisplay> CCharacterSelection::s_characterList;

View file

@ -0,0 +1,16 @@
#ifndef GLUE_C_CHARACTER_SELECTION_HPP
#define GLUE_C_CHARACTER_SELECTION_HPP
#include <storm/Array.hpp>
struct CharacterSelectionDisplay {
// TODO
};
class CCharacterSelection {
public:
// Static variables
static TSGrowableArray<CharacterSelectionDisplay> s_characterList;
};
#endif

452
src/glue/CGlueMgr.cpp Normal file
View file

@ -0,0 +1,452 @@
#include "glue/CGlueMgr.hpp"
#include "client/Client.hpp"
#include "client/ClientServices.hpp"
#include "gx/Coordinate.hpp"
#include "gx/Device.hpp"
#include "math/Utils.hpp"
#include "net/Connection.hpp"
#include "net/Login.hpp"
#include "sound/SI2.hpp"
#include "ui/CSimpleModelFFX.hpp"
#include "ui/CSimpleTop.hpp"
#include "ui/FrameScript.hpp"
#include "ui/FrameXML.hpp"
#include "ui/Interface.hpp"
#include "ui/ScriptFunctions.hpp"
#include "util/CVar.hpp"
#include "util/Filesystem.hpp"
#include "util/Log.hpp"
#include <cstdio>
#include <common/MD5.hpp>
unsigned char InterfaceKey[256] = {
0xC3, 0x5B, 0x50, 0x84, 0xB9, 0x3E, 0x32, 0x42, 0x8C, 0xD0, 0xC7, 0x48, 0xFA, 0x0E, 0x5D, 0x54,
0x5A, 0xA3, 0x0E, 0x14, 0xBA, 0x9E, 0x0D, 0xB9, 0x5D, 0x8B, 0xEE, 0xB6, 0x84, 0x93, 0x45, 0x75,
0xFF, 0x31, 0xFE, 0x2F, 0x64, 0x3F, 0x3D, 0x6D, 0x07, 0xD9, 0x44, 0x9B, 0x40, 0x85, 0x59, 0x34,
0x4E, 0x10, 0xE1, 0xE7, 0x43, 0x69, 0xEF, 0x7C, 0x16, 0xFC, 0xB4, 0xED, 0x1B, 0x95, 0x28, 0xA8,
0x23, 0x76, 0x51, 0x31, 0x57, 0x30, 0x2B, 0x79, 0x08, 0x50, 0x10, 0x1C, 0x4A, 0x1A, 0x2C, 0xC8,
0x8B, 0x8F, 0x05, 0x2D, 0x22, 0x3D, 0xDB, 0x5A, 0x24, 0x7A, 0x0F, 0x13, 0x50, 0x37, 0x8F, 0x5A,
0xCC, 0x9E, 0x04, 0x44, 0x0E, 0x87, 0x01, 0xD4, 0xA3, 0x15, 0x94, 0x16, 0x34, 0xC6, 0xC2, 0xC3,
0xFB, 0x49, 0xFE, 0xE1, 0xF9, 0xDA, 0x8C, 0x50, 0x3C, 0xBE, 0x2C, 0xBB, 0x57, 0xED, 0x46, 0xB9,
0xAD, 0x8B, 0xC6, 0xDF, 0x0E, 0xD6, 0x0F, 0xBE, 0x80, 0xB3, 0x8B, 0x1E, 0x77, 0xCF, 0xAD, 0x22,
0xCF, 0xB7, 0x4B, 0xCF, 0xFB, 0xF0, 0x6B, 0x11, 0x45, 0x2D, 0x7A, 0x81, 0x18, 0xF2, 0x92, 0x7E,
0x98, 0x56, 0x5D, 0x5E, 0x69, 0x72, 0x0A, 0x0D, 0x03, 0x0A, 0x85, 0xA2, 0x85, 0x9C, 0xCB, 0xFB,
0x56, 0x6E, 0x8F, 0x44, 0xBB, 0x8F, 0x02, 0x22, 0x68, 0x63, 0x97, 0xBC, 0x85, 0xBA, 0xA8, 0xF7,
0xB5, 0x40, 0x68, 0x3C, 0x77, 0x86, 0x6F, 0x4B, 0xD7, 0x88, 0xCA, 0x8A, 0xD7, 0xCE, 0x36, 0xF0,
0x45, 0x6E, 0xD5, 0x64, 0x79, 0x0F, 0x17, 0xFC, 0x64, 0xDD, 0x10, 0x6F, 0xF3, 0xF5, 0xE0, 0xA6,
0xC3, 0xFB, 0x1B, 0x8C, 0x29, 0xEF, 0x8E, 0xE5, 0x34, 0xCB, 0xD1, 0x2A, 0xCE, 0x79, 0xC3, 0x9A,
0x0D, 0x36, 0xEA, 0x01, 0xE0, 0xAA, 0x91, 0x20, 0x54, 0xF0, 0x72, 0xD8, 0x1E, 0xC7, 0x89, 0xD2
};
int32_t CGlueMgr::m_acceptedEULA = 1; // TODO
int32_t CGlueMgr::m_acceptedTerminationWithoutNotice;
int32_t CGlueMgr::m_acceptedTOS = 1; // TODO
char CGlueMgr::m_accountName[1280];
float CGlueMgr::m_aspect;
bool CGlueMgr::m_authenticated;
char CGlueMgr::m_currentScreen[64];
CGlueMgr::GLUE_IDLE_STATE CGlueMgr::m_idleState;
int32_t CGlueMgr::m_initialized;
int32_t CGlueMgr::m_lastLoginResult;
int32_t CGlueMgr::m_lastLoginState;
int32_t CGlueMgr::m_loginResult;
int32_t CGlueMgr::m_loginState;
int32_t CGlueMgr::m_matrixRemaining;
int32_t CGlueMgr::m_reload;
int32_t CGlueMgr::m_scandllOkayToLogIn = 1; // TODO
float CGlueMgr::m_screenHeight;
float CGlueMgr::m_screenWidth;
int32_t CGlueMgr::m_showedDisconnect;
CSimpleTop* CGlueMgr::m_simpleTop;
int32_t CGlueMgr::m_suspended;
float CalculateAspectRatio() {
auto widescreenVar = CVar::Lookup("widescreen");
auto resolutionVar = CVar::Lookup("gxResolution");
int32_t width = 4;
int32_t height = 3;
if (widescreenVar && widescreenVar->GetInt() && resolutionVar) {
char separator;
sscanf(resolutionVar->GetString(), "%d%c%d", &width, &separator, &height);
}
return static_cast<float>(width) / static_cast<float>(height);
}
int32_t CGlueMgr::HandleDisplaySizeChanged(const CSizeEvent& event) {
if (
CGlueMgr::m_screenWidth > 0
&& CGlueMgr::m_screenWidth == event.w
&& CGlueMgr::m_screenHeight > 0
&& CGlueMgr::m_screenHeight == event.h
) {
return 1;
}
CGlueMgr::m_screenWidth = event.w;
CGlueMgr::m_screenHeight = event.h;
float aspect = CalculateAspectRatio();
auto glueParent = static_cast<CSimpleFrame*>(CScriptObject::GetScriptObjectByName("GlueParent", CSimpleFrame::GetObjectType()));
if (glueParent) {
glueParent->SetFrameScale(1.0f, true);
CLayoutFrame::ResizePending();
}
if (AreEqual(CGlueMgr::m_aspect, aspect, 0.0099999998)) {
return 1;
}
CGlueMgr::m_aspect = aspect;
CGlueMgr::m_reload = 1;
return 1;
}
// TODO a1: const EVENT_DATA_IDLE*
int32_t CGlueMgr::Idle(const void* a1, void* a2) {
// TODO
if (CGlueMgr::m_idleState == IDLE_NONE) {
if (CGlueMgr::m_reload) {
if (!CGlueMgr::m_suspended) {
// TODO CGlueMgr::Suspend();
// TODO CGlueMgr::Resume();
// TODO Sub4DA360();
// TODO CGlueMgr::SetScreen(ByteB6A9E0);
}
CGlueMgr::m_reload = 0;
}
// TODO
// if (CGlueMgr::m_accountMsgAvailable) {
// FrameScript_SignalEvent(0x22u, 0);
// CGlueMgr::m_accountMsgAvailable = 0;
// }
// TODO sub_4D84A0();
return 1;
}
// TODO
return 1;
}
void CGlueMgr::Initialize() {
CGlueMgr::m_initialized = 1;
// TODO
// - cvar stuff (tou, etc)
CRect windowSize;
g_theGxDevicePtr->CapsWindowSize(windowSize);
CSizeEvent sizeEvent;
sizeEvent.id = -1;
sizeEvent.w = windowSize.maxX - windowSize.minX;
sizeEvent.h = windowSize.maxY - windowSize.minY;
CGlueMgr::HandleDisplaySizeChanged(sizeEvent);
FrameXML_RegisterFactory("ModelFFX", &CSimpleModelFFX::Create, 0);
CGlueMgr::Resume();
// TODO
// CRealmList::Initialize();
EventRegisterEx(EVENT_ID_IDLE, &CGlueMgr::Idle, 0, 0.0);
// TODO
// CGLCD::Initialize();
// sub_552380();
// TODO
// - options changed warning stuff
// TODO
// AccountDataInitializeBasicSystem();
}
void CGlueMgr::LoginServerLogin(const char* accountName, const char* password) {
if (!CGlueMgr::m_scandllOkayToLogIn || !CGlueMgr::m_acceptedTOS || !CGlueMgr::m_acceptedEULA || CGlueMgr::m_idleState != IDLE_NONE) {
return;
}
if (!accountName || !*accountName) {
auto prompt = FrameScript_GetText("LOGIN_ENTER_NAME", -1, GENDER_NOT_APPLICABLE);
FrameScript_SignalEvent(3, "%s%s", "OKAY", prompt);
return;
}
if (!password || !*password) {
auto prompt = FrameScript_GetText("LOGIN_ENTER_PASSWORD", -1, GENDER_NOT_APPLICABLE);
FrameScript_SignalEvent(3, "%s%s", "OKAY", prompt);
return;
}
CGlueMgr::m_loginResult = -1;
CGlueMgr::m_loginState = -1;
CGlueMgr::m_lastLoginResult = -1;
CGlueMgr::m_lastLoginState = -1;
CGlueMgr::m_authenticated = false;
CGlueMgr::m_matrixRemaining = 0;
CGlueMgr::m_idleState = IDLE_ACCOUNT_LOGIN;
CGlueMgr::m_showedDisconnect = 0;
char* dest = CGlueMgr::m_accountName;
for (const char* src = accountName; *src && dest < CGlueMgr::m_accountName + sizeof(CGlueMgr::m_accountName); src++, dest++) {
if (src[0] == '|' && src[1] == '|') {
src++;
}
*dest = *src;
}
*dest = '\0';
SStrUpper(CGlueMgr::m_accountName);
// Show prompt
FrameScript_SignalEvent(3, "%s", "CANCEL");
ClientServices::Logon(CGlueMgr::m_accountName, password);
// Zero out password
memset(const_cast<char*>(password), 0, SStrLen(password));
}
void CGlueMgr::QuitGame() {
ClientPostClose(0);
}
void CGlueMgr::Resume() {
// TODO
// CGlueMgr::m_disconnectPending = 0;
// CGlueMgr::m_reconnect = 0;
CGlueMgr::m_idleState = IDLE_NONE;
// TODO
// CGlueMgr::m_showedDisconnect = 0;
// CGlueMgr::m_characterInfo = 0;
CGlueMgr::m_suspended = 0;
CGlueMgr::m_reload = 0;
CRect screenRect;
g_theGxDevicePtr->CapsWindowSizeInScreenCoords(screenRect);
CGlueMgr::m_screenWidth = screenRect.maxX - screenRect.minX;
CGlueMgr::m_screenHeight = screenRect.maxY - screenRect.minY;
CGlueMgr::m_aspect = CalculateAspectRatio();
CoordinateSetAspectRatio(CGlueMgr::m_aspect);
// Create CSimpleTop
CSimpleTop* top;
void* m = SMemAlloc(sizeof(CSimpleTop), __FILE__, __LINE__, 0);
if (m) {
top = new (m) CSimpleTop();
} else {
top = nullptr;
}
CGlueMgr::m_simpleTop = top;
CGlueMgr::m_simpleTop->m_displaySizeCallback = &CGlueMgr::HandleDisplaySizeChanged;
// TODO
// - setting cursor texture
// - setting mouse mode
FrameScript_Flush();
SystemRegisterFunctions();
RegisterSimpleFrameScriptMethods();
GlueScriptEventsRegisterFunctions();
CharSelectRegisterScriptFunctions();
CharacterCreateRegisterScriptFunctions();
// TODO
// RealmListRegisterScriptFunctions();
SI2::RegisterScriptFunctions();
// TODO
// AccountMsg_RegisterScriptFunctions();
// CGVideoOptions::RegisterScriptFunctions();
// TODO
// FrameScript::s_scriptFunctionsLoaded = 1;
FrameScript_CreateEvents(g_glueScriptEvents, NUM_GLUE_SCRIPT_EVENTS);
OsCreateDirectory("Logs", 0);
CWOWClientStatus status;
if (!SLogCreate("Logs\\GlueXML.log", 0, status.m_logFile)) {
SysMsgPrintf(SYSMSG_WARNING, "Cannot create WOWClient log file \"%s\"!", "Logs\\GlueXML.log");
}
DeleteInterfaceFiles();
MD5_CTX md5;
unsigned char digest1[16];
unsigned char digest2[16];
int32_t v8;
unsigned char* v9;
unsigned char* v10;
MD5Init(&md5);
switch (FrameXML_CheckSignature("Interface\\GlueXML\\GlueXML.toc", 0, InterfaceKey, digest1)) {
case 0:
status.Add(STATUS_WARNING, "GlueXML missing signature");
ClientPostClose(9);
return;
case 1:
status.Add(STATUS_WARNING, "GlueXML has corrupt signature");
ClientPostClose(9);
return;
case 2:
status.Add(STATUS_WARNING, "GlueXML is modified or corrupt");
ClientPostClose(9);
return;
case 3:
FrameXML_FreeHashNodes();
FrameXML_CreateFrames("Interface\\GlueXML\\GlueXML.toc", 0, &md5, &status);
MD5Final(digest2, &md5);
v8 = 16;
v9 = digest2;
v10 = digest1;
break;
default:
ClientPostClose(9);
return;
}
// TODO
// - some kind of digest validation?
FrameScript_SignalEvent(22, nullptr);
// TODO
// CGlueMgr::InitializeFFX();
// TODO
// ClientServices::SetMessageHandler(SMSG_CHARACTER_RENAME_RESULT, CGlueMgr::OnCharRenameResult, 0);
// ClientServices::SetMessageHandler(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, CGlueMgr::OnCharDeclineResult, 0);
// ClientServices::SetMessageHandler(SMSG_CHAR_CUSTOMIZE, CGlueMgr::OnCharCustomizeResult, 0);
// ClientServices::SetMessageHandler(SMSG_REALM_SPLIT, CGlueMgr::OnRealmSplitMsg, 0);
// ClientServices::SetMessageHandler(SMSG_KICK_REASON, CGlueMgr::OnKickReasonMsg, 0);
// ClientServices::SetMessageHandler(SMSG_CHAR_FACTION_CHANGE, CGlueMgr::OnCharFactionChangeResult, 0);
// TODO
// CGlueMgr::m_pendingServerAlert = 1;
// CGlueMgr::m_processServerAlert = 0;
// CGlueMgr::m_serverAlert[0] = 0;
// v21 = (const char *)ClientServices::GetServerAlertURL();
// v22 = (const CHAR *)FrameScript_GetText(v21, -1, 0);
// if (!OsURLDownload(v22, CGlueMgr::ServerAlertURLCallback, 0)) {
// CGlueMgr::m_pendingServerAlert = 0;
// }
}
void CGlueMgr::SetScreen(const char* screen) {
FrameScript_SignalEvent(0, "%s", screen);
}
void CGlueMgr::StatusDialogClick() {
if (!SStrCmpI(CGlueMgr::m_currentScreen, "patchdownload", STORM_MAX_STR)) {
CGlueMgr::SetScreen("login");
}
switch (CGlueMgr::m_idleState) {
case IDLE_NONE: {
ClientServices::Connection()->Cleanup();
break;
}
case IDLE_ACCOUNT_LOGIN: {
ClientServices::LoginConnection()->Logoff();
CGlueMgr::m_showedDisconnect = 0;
CGlueMgr::m_idleState = IDLE_NONE;
break;
}
case IDLE_2:
case IDLE_3: {
ClientServices::Connection()->Cancel(2);
break;
}
case IDLE_4:
case IDLE_5:
case IDLE_6:
case IDLE_10: {
ClientServices::Connection()->Cancel(2);
CGlueMgr::m_showedDisconnect = 0;
CGlueMgr::m_idleState = IDLE_NONE;
break;
}
case IDLE_7:
case IDLE_8:
case IDLE_9: {
CGlueMgr::m_showedDisconnect = 0;
CGlueMgr::m_idleState = IDLE_NONE;
break;
}
case IDLE_11: {
CGlueMgr::m_showedDisconnect = 0;
CGlueMgr::m_idleState = IDLE_NONE;
// TODO
// CGlueMgr::GetCharacterList();
break;
}
case IDLE_12:
case IDLE_13: {
// TODO
break;
}
}
}
void CGlueMgr::Suspend() {
// TODO
}
void CGlueMgr::UpdateCurrentScreen(const char* screen) {
// TODO
SStrCopy(CGlueMgr::m_currentScreen, screen, sizeof(CGlueMgr::m_currentScreen));
// TODO
}

66
src/glue/CGlueMgr.hpp Normal file
View file

@ -0,0 +1,66 @@
#ifndef GLUE_C_GLUE_MGR_HPP
#define GLUE_C_GLUE_MGR_HPP
#include "event/Event.hpp"
#include <cstdint>
class CSimpleTop;
class CGlueMgr {
public:
// Types
enum GLUE_IDLE_STATE {
IDLE_NONE = 0,
IDLE_ACCOUNT_LOGIN = 1,
IDLE_2 = 2,
IDLE_3 = 3,
IDLE_4 = 4,
IDLE_5 = 5,
IDLE_6 = 6,
IDLE_7 = 7,
IDLE_8 = 8,
IDLE_9 = 9,
IDLE_10 = 10,
IDLE_11 = 11,
IDLE_12 = 12,
IDLE_13 = 13
};
// Static variables
static int32_t m_acceptedEULA;
static int32_t m_acceptedTerminationWithoutNotice;
static int32_t m_acceptedTOS;
static char m_accountName[];
static float m_aspect;
static bool m_authenticated;
static char m_currentScreen[];
static GLUE_IDLE_STATE m_idleState;
static int32_t m_initialized;
static int32_t m_lastLoginResult;
static int32_t m_lastLoginState;
static int32_t m_loginResult;
static int32_t m_loginState;
static int32_t m_matrixRemaining;
static int32_t m_reload;
static int32_t m_scandllOkayToLogIn;
static float m_screenHeight;
static float m_screenWidth;
static int32_t m_showedDisconnect;
static CSimpleTop* m_simpleTop;
static int32_t m_suspended;
// Static functions
// TODO a1: const EVENT_DATA_IDLE*
static int32_t HandleDisplaySizeChanged(const CSizeEvent& event);
static int32_t Idle(const void*, void*);
static void Initialize();
static void LoginServerLogin(const char* accountName, const char* password);
static void QuitGame();
static void Resume();
static void SetScreen(const char*);
static void StatusDialogClick();
static void Suspend();
static void UpdateCurrentScreen(const char* screen);
};
#endif

23
src/glue/CMakeLists.txt Normal file
View file

@ -0,0 +1,23 @@
file(GLOB PRIVATE_SOURCES "*.cpp")
add_library(glue STATIC
${PRIVATE_SOURCES}
)
target_include_directories(glue
PRIVATE
${CMAKE_SOURCE_DIR}/src
)
target_link_libraries(glue
PRIVATE
client
event
gx
net
sound
ui
util
PUBLIC
storm
)

236
src/gx/Blit.cpp Normal file
View file

@ -0,0 +1,236 @@
#include "gx/Blit.hpp"
#include <algorithm>
#include <cstring>
#include <tempest/Vector.hpp>
int32_t initBlit = 0;
BLIT_FUNCTION s_blits[BlitFormats_Last][BlitFormats_Last][BlitAlphas_Last];
BlitFormat GxGetBlitFormat(EGxTexFormat format) {
static BlitFormat blitTable[] = {
BlitFormat_Unknown, // GxTex_Unknown
BlitFormat_Abgr8888, // GxTex_Abgr8888
BlitFormat_Argb8888, // GxTex_Argb8888
BlitFormat_Argb4444, // GxTex_Argb4444
BlitFormat_Argb1555, // GxTex_Argb1555
BlitFormat_Rgb565, // GxTex_Rgb565
BlitFormat_Dxt1, // GxTex_Dxt1
BlitFormat_Dxt3, // GxTex_Dxt3
BlitFormat_Dxt5, // GxTex_Dxt5
BlitFormat_Uv88, // GxTex_Uv88
BlitFormat_Gr1616F, // GxTex_Gr1616F
BlitFormat_R32F, // GxTex_R32F
BlitFormat_D24X8 // GxTex_D24X8
};
return blitTable[format];
}
void Blit_uint16_uint16(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
if (inStride == 2 * size.x && outStride == 2 * size.x) {
memcpy(out, in, 2 * size.x * size.y);
return;
}
const char* in_ = reinterpret_cast<const char*>(in);
char* out_ = reinterpret_cast<char*>(out);
for (int32_t i = 0; i < size.y; i++) {
memcpy(out, in, 2 * size.x);
in_ += inStride;
out_ += outStride;
}
}
void Blit_uint32_uint32(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
if (inStride == 4 * size.x && outStride == 4 * size.x) {
memcpy(out, in, 4 * size.x * size.y);
return;
}
const char* in_ = reinterpret_cast<const char*>(in);
char* out_ = reinterpret_cast<char*>(out);
for (int32_t i = 0; i < size.y; i++) {
memcpy(out, in, 4 * size.x);
in_ += inStride;
out_ += outStride;
}
}
void Blit_Argb8888_Abgr8888(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Argb8888_Argb8888(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
Blit_uint32_uint32(size, in, inStride, out, outStride);
}
void Blit_Argb8888_Argb8888_A1(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Argb8888_Argb8888_A8(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Argb8888_Argb4444(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Argb8888_Argb1555(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Argb8888_Rgb565(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Argb4444_Abgr8888(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Argb4444_Argb4444(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
Blit_uint16_uint16(size, in, inStride, out, outStride);
}
void Blit_Argb1555_Argb1555(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Rgb565_Rgb565(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Dxt1_Argb8888(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Dxt1_Argb1555(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Dxt1_Rgb565(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Dxt1_Dxt1(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
const char* in_ = static_cast<const char*>(in);
char* out_ = static_cast<char*>(out);
int32_t v6 = std::max(size.x, 4);
int32_t v7 = std::max(size.y, 4);
memcpy(out_, in_, (4 * v6 * v7) >> 3);
}
void Blit_Dxt3_Argb8888(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Dxt3_Argb4444(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Dxt35_Dxt35(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
int32_t v5 = std::max(size.x, 4);
int32_t v6 = std::max(size.y / 4, 1);
const char* in_ = static_cast<const char*>(in);
char* out_ = static_cast<char*>(out);
if (inStride == v5 * 4 && outStride == v5 * 4) {
memcpy(out_, in_, v5 * v6 * 4);
return;
}
for (int32_t i = v6; i > 0; i--) {
memcpy(out_, in_, v5 * 4);
in_ += inStride;
out_ += outStride;
}
}
void Blit_Dxt5_Argb8888(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Dxt5_Argb4444(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Uv88_Uv88(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_Gr1616F_Gr1616F(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_R32F_R32F(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void Blit_D24X8_D24X8(const C2iVector& size, const void* in, uint32_t inStride, void* out, uint32_t outStride) {
// TODO
}
void InitBlit() {
// Source: Argb8888
s_blits [BlitFormat_Argb8888] [BlitFormat_Abgr8888] [BlitAlpha_0] = &Blit_Argb8888_Abgr8888;
s_blits [BlitFormat_Argb8888] [BlitFormat_Argb8888] [BlitAlpha_0] = &Blit_Argb8888_Argb8888;
s_blits [BlitFormat_Argb8888] [BlitFormat_Argb8888] [BlitAlpha_1] = &Blit_Argb8888_Argb8888_A1;
s_blits [BlitFormat_Argb8888] [BlitFormat_Argb8888] [BlitAlpha_8] = &Blit_Argb8888_Argb8888_A8;
s_blits [BlitFormat_Argb8888] [BlitFormat_Argb4444] [BlitAlpha_0] = &Blit_Argb8888_Argb4444;
s_blits [BlitFormat_Argb8888] [BlitFormat_Argb1555] [BlitAlpha_0] = &Blit_Argb8888_Argb1555;
s_blits [BlitFormat_Argb8888] [BlitFormat_Rgb565] [BlitAlpha_0] = &Blit_Argb8888_Rgb565;
// Source: Argb4444
s_blits [BlitFormat_Argb4444] [BlitFormat_Abgr8888] [BlitAlpha_0] = &Blit_Argb4444_Abgr8888;
s_blits [BlitFormat_Argb4444] [BlitFormat_Argb4444] [BlitAlpha_0] = &Blit_Argb4444_Argb4444;
// Source: Argb1555
s_blits [BlitFormat_Argb1555] [BlitFormat_Argb1555] [BlitAlpha_0] = &Blit_Argb1555_Argb1555;
// Source: Rgb565
s_blits [BlitFormat_Rgb565] [BlitFormat_Rgb565] [BlitAlpha_0] = &Blit_Rgb565_Rgb565;
// Source: Dxt1
s_blits [BlitFormat_Dxt1] [BlitFormat_Argb8888] [BlitAlpha_0] = &Blit_Dxt1_Argb8888;
s_blits [BlitFormat_Dxt1] [BlitFormat_Argb1555] [BlitAlpha_0] = &Blit_Dxt1_Argb1555;
s_blits [BlitFormat_Dxt1] [BlitFormat_Rgb565] [BlitAlpha_0] = &Blit_Dxt1_Rgb565;
s_blits [BlitFormat_Dxt1] [BlitFormat_Dxt1] [BlitAlpha_0] = &Blit_Dxt1_Dxt1;
// Source: Dxt3
s_blits [BlitFormat_Dxt3] [BlitFormat_Argb8888] [BlitAlpha_0] = &Blit_Dxt3_Argb8888;
s_blits [BlitFormat_Dxt3] [BlitFormat_Argb4444] [BlitAlpha_0] = &Blit_Dxt3_Argb4444;
s_blits [BlitFormat_Dxt3] [BlitFormat_Dxt3] [BlitAlpha_0] = &Blit_Dxt35_Dxt35;
// Source: Dxt5
s_blits [BlitFormat_Dxt5] [BlitFormat_Argb8888] [BlitAlpha_0] = &Blit_Dxt5_Argb8888;
s_blits [BlitFormat_Dxt5] [BlitFormat_Argb4444] [BlitAlpha_0] = &Blit_Dxt5_Argb4444;
s_blits [BlitFormat_Dxt5] [BlitFormat_Dxt5] [BlitAlpha_0] = &Blit_Dxt35_Dxt35;
// Source: Uv88
s_blits [BlitFormat_Uv88] [BlitFormat_Uv88] [BlitAlpha_0] = &Blit_Uv88_Uv88;
// Source: Gr1616F
s_blits [BlitFormat_Gr1616F] [BlitFormat_Gr1616F] [BlitAlpha_0] = &Blit_Gr1616F_Gr1616F;
// Source: R32F
s_blits [BlitFormat_R32F] [BlitFormat_R32F] [BlitAlpha_0] = &Blit_R32F_R32F;
// Source: D24X8
s_blits [BlitFormat_D24X8] [BlitFormat_D24X8] [BlitAlpha_0] = &Blit_D24X8_D24X8;
}
void Blit(const C2iVector& size, BlitAlpha alpha, const void* src, uint32_t srcStride, BlitFormat srcFmt, void* dst, uint32_t dstStride, BlitFormat dstFmt) {
if (!initBlit) {
InitBlit();
initBlit = 1;
}
BLIT_FUNCTION blit = s_blits[srcFmt][dstFmt][alpha];
blit(size, src, srcStride, dst, dstStride);
}

15
src/gx/Blit.hpp Normal file
View file

@ -0,0 +1,15 @@
#ifndef GX_BLIT_HPP
#define GX_BLIT_HPP
#include "gx/Types.hpp"
#include <cstdint>
class C2iVector;
typedef void (*BLIT_FUNCTION)(const C2iVector&, const void*, uint32_t, void*, uint32_t);
void Blit(const C2iVector&, BlitAlpha, const void*, uint32_t, BlitFormat, void*, uint32_t, BlitFormat);
BlitFormat GxGetBlitFormat(EGxTexFormat);
#endif

213
src/gx/Buffer.cpp Normal file
View file

@ -0,0 +1,213 @@
#include "gx/Buffer.hpp"
#include "gx/Device.hpp"
CGxVertexAttrib vertexAttribsP[] = {
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_P, GxVA_Position), 12 }
};
CGxVertexAttrib vertexAttribsPN[] = {
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PN, GxVA_Position), 24 },
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PN, GxVA_Normal), 24 }
};
CGxVertexAttrib vertexAttribsPNC[] = {
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PNC, GxVA_Position), 28 },
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PNC, GxVA_Normal), 28 },
{ GxVA_Color0, 0, GxVertexAttribOffset(GxVBF_PNC, GxVA_Color0), 28 }
};
CGxVertexAttrib vertexAttribsPNT[] = {
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PNT, GxVA_Position), 32 },
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PNT, GxVA_Normal), 32 },
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PNT, GxVA_TexCoord0), 32 }
};
CGxVertexAttrib vertexAttribsPNCT[] = {
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PNCT, GxVA_Position), 36 },
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PNCT, GxVA_Normal), 36 },
{ GxVA_Color0, 0, GxVertexAttribOffset(GxVBF_PNCT, GxVA_Color0), 36 },
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PNCT, GxVA_TexCoord0), 36 }
};
CGxVertexAttrib vertexAttribsPNT2[] = {
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PNT2, GxVA_Position), 40 },
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PNT2, GxVA_Normal), 40 },
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PNT2, GxVA_TexCoord0), 40 },
{ GxVA_TexCoord1, 3, GxVertexAttribOffset(GxVBF_PNT2, GxVA_TexCoord1), 40 }
};
CGxVertexAttrib vertexAttribsPNCT2[] = {
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PNCT2, GxVA_Position), 44 },
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PNCT2, GxVA_Normal), 44 },
{ GxVA_Color0, 0, GxVertexAttribOffset(GxVBF_PNCT2, GxVA_Color0), 44 },
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PNCT2, GxVA_TexCoord0), 44 },
{ GxVA_TexCoord1, 3, GxVertexAttribOffset(GxVBF_PNCT2, GxVA_TexCoord1), 44 }
};
CGxVertexAttrib vertexAttribsPC[] = {
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PC, GxVA_Position), 16 },
{ GxVA_Color0, 0, GxVertexAttribOffset(GxVBF_PC, GxVA_Color0), 16 }
};
CGxVertexAttrib vertexAttribsPCT[] = {
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PCT, GxVA_Position), 24 },
{ GxVA_Color0, 0, GxVertexAttribOffset(GxVBF_PCT, GxVA_Color0), 24 },
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PCT, GxVA_TexCoord0), 24 }
};
CGxVertexAttrib vertexAttribsPCT2[] = {
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PCT2, GxVA_Position), 32 },
{ GxVA_Color0, 0, GxVertexAttribOffset(GxVBF_PCT2, GxVA_Color0), 32 },
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PCT2, GxVA_TexCoord0), 32 },
{ GxVA_TexCoord1, 3, GxVertexAttribOffset(GxVBF_PCT2, GxVA_TexCoord1), 32 }
};
CGxVertexAttrib vertexAttribsPT[] = {
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PT, GxVA_Position), 20 },
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PT, GxVA_TexCoord0), 20 }
};
CGxVertexAttrib vertexAttribsPT2[] = {
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PT2, GxVA_Position), 28 },
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PT2, GxVA_TexCoord0), 28 },
{ GxVA_TexCoord1, 3, GxVertexAttribOffset(GxVBF_PT2, GxVA_TexCoord1), 28 }
};
CGxVertexAttrib vertexAttribsPBNT2[] = {
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PBNT2, GxVA_Position), 48 },
{ GxVA_BlendWeight, 2, GxVertexAttribOffset(GxVBF_PBNT2, GxVA_BlendWeight), 48 },
{ GxVA_BlendIndices, 1, GxVertexAttribOffset(GxVBF_PBNT2, GxVA_BlendIndices), 48 },
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PBNT2, GxVA_Normal), 48 },
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PBNT2, GxVA_TexCoord0), 48 },
{ GxVA_TexCoord1, 3, GxVertexAttribOffset(GxVBF_PBNT2, GxVA_TexCoord1), 48 }
};
CGxVertexAttrib vertexAttribsPNC2T2[] = {
{ GxVA_Position, 4, GxVertexAttribOffset(GxVBF_PNC2T2, GxVA_Position), 48 },
{ GxVA_Normal, 4, GxVertexAttribOffset(GxVBF_PNC2T2, GxVA_Normal), 48 },
{ GxVA_Color0, 0, GxVertexAttribOffset(GxVBF_PNC2T2, GxVA_Color0), 48 },
{ GxVA_Color1, 0, GxVertexAttribOffset(GxVBF_PNC2T2, GxVA_Color0), 48 },
{ GxVA_TexCoord0, 3, GxVertexAttribOffset(GxVBF_PNC2T2, GxVA_TexCoord0), 48 },
{ GxVA_TexCoord1, 3, GxVertexAttribOffset(GxVBF_PNC2T2, GxVA_TexCoord1), 48 }
};
VertexBufDesc Buffer::s_vertexBufDesc[] = {
// GxVBF_P
{ vertexAttribsP, 1, 12, GxPrim_Position },
// GxVBF_PN
{ vertexAttribsPN, 2, 24, GxPrim_Position | GxPrim_Normal },
// GxVBF_PNC
{ vertexAttribsPNC, 3, 28, GxPrim_Position | GxPrim_Normal | GxPrim_Color0 },
// GxVBF_PNT
{ vertexAttribsPNT, 3, 32, GxPrim_Position | GxPrim_Normal | GxPrim_TexCoord0 },
// GxVBF_PNCT
{ vertexAttribsPNCT, 4, 36, GxPrim_Position | GxPrim_Normal | GxPrim_Color0 | GxPrim_TexCoord0 },
// GxVBF_PNT2
{ vertexAttribsPNT2, 4, 40, GxPrim_Position | GxPrim_Normal | GxPrim_TexCoord0 | GxPrim_TexCoord1 },
// GxVBF_PNCT2
{ vertexAttribsPNCT2, 5, 44, GxPrim_Position | GxPrim_Normal | GxPrim_Color0 | GxPrim_TexCoord0 | GxPrim_TexCoord1 },
// GxVBF_PC
{ vertexAttribsPC, 2, 16, GxPrim_Position | GxPrim_Color0 },
// GxVBF_PCT
{ vertexAttribsPCT, 3, 24, GxPrim_Position | GxPrim_Color0 | GxPrim_TexCoord0 },
// GxVBF_PCT2
{ vertexAttribsPCT2, 4, 32, GxPrim_Position | GxPrim_Color0 | GxPrim_TexCoord0 | GxPrim_TexCoord1 },
// GxVBF_PT
{ vertexAttribsPT, 2, 20, GxPrim_Position | GxPrim_TexCoord0 },
// GxVBF_PT2
{ vertexAttribsPT2, 3, 28, GxPrim_Position | GxPrim_TexCoord0 | GxPrim_TexCoord1 },
// GxVBF_PBNT2
{ vertexAttribsPBNT2, 6, 48, GxPrim_Position | GxPrim_BlendWeight | GxPrim_BlendIndices | GxPrim_Normal | GxPrim_TexCoord0 | GxPrim_TexCoord1 },
// GxVBF_PNC2T2
{ vertexAttribsPNC2T2, 6, 48, GxPrim_Position | GxPrim_Normal | GxPrim_Color0 | GxPrim_Color1 | GxPrim_TexCoord0 | GxPrim_TexCoord1 }
};
int32_t Buffer::s_vertexBufOffset[GxVertexBufferFormats_Last][GxVAs_Last] = {
// GxVBF_P
{ 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
// GxVBF_PN
{ 0, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
// GxVBF_PNC
{ 0, -1, -1, 12, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
// GxVBF_PNT
{ 0, -1, -1, 12, -1, -1, 24, -1, -1, -1, -1, -1, -1, -1 },
// GxVBF_PNCT
{ 0, -1, -1, 12, 24, -1, 28, -1, -1, -1, -1, -1, -1, -1 },
// GxVBF_PNT2
{ 0, -1, -1, 12, -1, -1, 24, 32, -1, -1, -1, -1, -1, -1 },
// GxVBF_PNCT2
{ 0, -1, -1, 12, 24, -1, 28, 36, -1, -1, -1, -1, -1, -1 },
// GxVBF_PC
{ 0, -1, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
// GxVBF_PCT
{ 0, -1, -1, -1, 12, -1, 16, -1, -1, -1, -1, -1, -1, -1 },
// GxVBF_PCT2
{ 0, -1, -1, -1, 12, -1, 16, 24, -1, -1, -1, -1, -1, -1 },
// GxVBF_PT
{ 0, -1, -1, -1, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1 },
// GxVBF_PT2
{ 0, -1, -1, -1, -1, -1, 12, 20, -1, -1, -1, -1, -1, -1 },
// GxVBF_PBNT2
{ 0, 12, 16, 20, -1, -1, 32, 40, -1, -1, -1, -1, -1, -1 },
// GxVBF_PNC2T2
{ 0, -1, -1, 12, 24, 28, 32, 40, -1, -1, -1, -1, -1, -1 }
};
uint32_t GxVertexAttribOffset(EGxVertexBufferFormat format, EGxVertexAttrib attrib) {
return Buffer::s_vertexBufOffset[format][attrib];
}
CGxBuf* GxBufCreate(CGxPool* pool, uint32_t itemSize, uint32_t itemCount, uint32_t index) {
return g_theGxDevicePtr->BufCreate(pool, itemSize, itemCount, index);
}
char* GxBufLock(CGxBuf* buf) {
return g_theGxDevicePtr->BufLock(buf);
}
void GxBufUnlock(CGxBuf* buf, uint32_t size) {
g_theGxDevicePtr->BufUnlock(buf, size);
buf->unk1C = 1;
}
CGxPool* GxPoolCreate(EGxPoolTarget target, EGxPoolUsage usage, uint32_t size, EGxPoolHintBits hint, char* name) {
return g_theGxDevicePtr->PoolCreate(target, usage, size, hint, name);
}
void GxPrimIndexPtr(CGxBuf* buf) {
g_theGxDevicePtr->PrimIndexPtr(buf);
}
void GxPrimVertexPtr(CGxBuf* buf, EGxVertexBufferFormat format) {
auto desc = &Buffer::s_vertexBufDesc[format];
g_theGxDevicePtr->PrimVertexFormat(buf, desc->attribs, desc->attribCount);
g_theGxDevicePtr->PrimVertexMask(desc->mask);
g_theGxDevicePtr->PrimVertexPtr(buf, format);
}

38
src/gx/Buffer.hpp Normal file
View file

@ -0,0 +1,38 @@
#ifndef GX_BUFFER_HPP
#define GX_BUFFER_HPP
#include "gx/buffer/CGxBuf.hpp"
#include "gx/buffer/CGxPool.hpp"
#include "gx/buffer/Types.hpp"
#include <cstdint>
class CGxBuf;
class CGxPool;
struct VertexBufDesc {
CGxVertexAttrib* attribs;
uint32_t attribCount;
uint32_t size;
uint32_t mask;
};
namespace Buffer {
extern VertexBufDesc s_vertexBufDesc[GxVertexBufferFormats_Last];
extern int32_t s_vertexBufOffset[GxVertexBufferFormats_Last][GxVAs_Last];
}
uint32_t GxVertexAttribOffset(EGxVertexBufferFormat, EGxVertexAttrib);
CGxBuf* GxBufCreate(CGxPool*, uint32_t, uint32_t, uint32_t);
char* GxBufLock(CGxBuf* buf);
void GxBufUnlock(CGxBuf*, uint32_t);
CGxPool* GxPoolCreate(EGxPoolTarget, EGxPoolUsage, uint32_t, EGxPoolHintBits, char*);
void GxPrimIndexPtr(CGxBuf*);
void GxPrimVertexPtr(CGxBuf*, EGxVertexBufferFormat);
#endif

58
src/gx/CCamera.cpp Normal file
View file

@ -0,0 +1,58 @@
#include "gx/CCamera.hpp"
#include "gx/Shader.hpp"
#include "gx/Transform.hpp"
#include <cmath>
#include <tempest/Math.hpp>
#include <tempest/Matrix.hpp>
#include <tempest/Rect.hpp>
const C3Vector CCamera::DEFAULT_POSITION = { 100.0f, 0.0f, 0.0f };
const float CCamera::DEFAULT_DIST = 100.0f;
const float CCamera::DEFAULT_FARZ = 5000.0f;
const float CCamera::DEFAULT_NEARZ = 8.0f;
float CAngle::ClampTo2Pi(float angle) {
double v1 = floor(static_cast<double>(CMath::OO_TWO_PI) * angle) * CMath::TWO_PI;
if (angle < 0.0f) {
v1 -= CMath::TWO_PI;
}
return angle - v1;
}
void CAngle::Set(const float& angle) {
float clampedAngle = CAngle::ClampTo2Pi(angle);
if (this->m_data != clampedAngle) {
this->m_flags |= CBaseManaged::UPDATED;
this->m_data = clampedAngle;
}
this->m_cos = cos(this->m_data);
this->m_sin = sin(this->m_data);
}
void CCamera::SetupWorldProjection(const CRect& projectionRect, uint32_t flags) {
C44Matrix projMat;
float aspect = (projectionRect.maxX - projectionRect.minX) / (projectionRect.maxY - projectionRect.minY);
GxuXformCreateProjection_SG(this->m_fov.m_data, aspect, this->m_zNear.m_data, this->m_zFar.m_data, projMat);
GxXformSetProjection(projMat);
C44Matrix viewMat;
C3Vector cameraPos = { 0.0f, 0.0f, 0.0f };
C3Vector cameraVec = {
this->m_target.m_data.x - this->m_position.m_data.x,
this->m_target.m_data.y - this->m_position.m_data.y,
this->m_target.m_data.z - this->m_position.m_data.z
};
C3Vector upVec = {
this->m_rotation.m_sin * this->m_roll.m_sin,
-(this->m_rotation.m_cos * this->m_roll.m_sin),
this->m_roll.m_cos
};
GxuXformCreateLookAtSgCompat(cameraPos, cameraVec, upVec, viewMat);
GxXformSetView(viewMat);
CShaderEffect::UpdateProjMatrix();
}

70
src/gx/CCamera.hpp Normal file
View file

@ -0,0 +1,70 @@
#ifndef GX_C_CAMERA_HPP
#define GX_C_CAMERA_HPP
#include <common/DataMgr.hpp>
class CRect;
class CAngle : public TManaged<float> {
public:
// Static functions
static float ClampTo2Pi(float angle);
// Member variables
float m_cos;
float m_sin;
// Virtual member functions
virtual void Set(const float& angle);
// Member functions
CAngle(float angle) {
this->Set(angle);
};
};
class CCamera : public CDataMgr {
public:
static const C3Vector DEFAULT_POSITION;
static const float DEFAULT_DIST;
static const float DEFAULT_FARZ;
static const float DEFAULT_NEARZ;
// Member variables
TManaged<C3Vector> m_position;
TManaged<C3Vector> m_target;
TManaged<float> m_distance;
TManaged<float> m_zFar;
TManaged<float> m_zNear;
CAngle m_aoa;
CAngle m_fov;
CAngle m_roll;
CAngle m_rotation;
// Member functions
CCamera()
: m_position(DEFAULT_POSITION)
, m_distance(DEFAULT_DIST)
, m_zFar(DEFAULT_FARZ)
, m_zNear(DEFAULT_NEARZ)
, m_aoa(0.0f)
, m_fov(0.0f)
, m_roll(0.0f)
, m_rotation(0.0f)
{
this->m_managedArray.SetCount(9);
this->AddManaged(&this->m_position, 7, 0x0);
this->AddManaged(&this->m_target, 8, 0x0);
this->AddManaged(&this->m_distance, 1, 0x0);
this->AddManaged(&this->m_zFar, 2, 0x0);
this->AddManaged(&this->m_zNear, 3, 0x0);
this->AddManaged(&this->m_aoa, 0, 0x0);
this->AddManaged(&this->m_fov, 4, 0x0);
this->AddManaged(&this->m_roll, 5, 0x0);
this->AddManaged(&this->m_rotation, 6, 0x0);
}
void SetupWorldProjection(const CRect& projectionRect, uint32_t flags);
};
#endif

17
src/gx/CGxBatch.hpp Normal file
View file

@ -0,0 +1,17 @@
#ifndef GX_C_GX_BATCH_HPP
#define GX_C_GX_BATCH_HPP
#include "gx/Types.hpp"
#include <cstdint>
class CGxBatch {
public:
// Member variables
EGxPrim m_primType;
uint32_t m_start;
uint32_t m_count;
uint16_t m_minIndex;
uint16_t m_maxIndex;
};
#endif

28
src/gx/CGxCaps.hpp Normal file
View file

@ -0,0 +1,28 @@
#ifndef GX_C_GX_CAPS_HPP
#define GX_C_GX_CAPS_HPP
#include "gx/Types.hpp"
#include <cstdint>
class CGxCaps {
public:
int32_t m_pixelCenterOnEdge = 0;
int32_t m_texelCenterOnEdge = 0;
EGxColorFormat m_colorFormat = GxCF_argb;
int32_t m_generateMipMaps = 0;
uint32_t m_maxTextureSize = 0;
int32_t m_texFmtDxt1 = 0;
int32_t m_texFmtDxt3 = 0;
int32_t m_texFmtDxt5 = 0;
EGxShVS m_vertexShaderTarget = GxShVS_none;
EGxShPS m_pixelShaderTarget = GxShPS_none;
int32_t m_texFilterAnisotropic = 0;
uint32_t m_maxTexAnisotropy = 0;
int32_t m_texTarget[GxTexTargets_Last];
uint32_t m_texMaxSize[GxTexTargets_Last];
int32_t int130 = 1;
int32_t int134 = 0;
int32_t int138 = 0;
};
#endif

1020
src/gx/CGxDevice.cpp Normal file

File diff suppressed because it is too large Load diff

160
src/gx/CGxDevice.hpp Normal file
View file

@ -0,0 +1,160 @@
#ifndef GX_C_GX_DEVICE_HPP
#define GX_C_GX_DEVICE_HPP
#include "gx/Buffer.hpp"
#include "gx/CGxCaps.hpp"
#include "gx/CGxFormat.hpp"
#include "gx/CGxMatrixStack.hpp"
#include "gx/CGxStateBom.hpp"
#include "gx/Types.hpp"
#include "gx/Shader.hpp"
#include <cstdint>
#include <storm/Hash.hpp>
#include <tempest/Box.hpp>
#include <tempest/Rect.hpp>
class CGxBatch;
class CGxTex;
class CGxTexFlags;
struct CGxAppRenderState {
CGxStateBom m_value;
uint32_t m_stackDepth;
int32_t m_dirty;
};
struct CGxPushedRenderState {
EGxRenderState m_which;
CGxStateBom m_value;
uint32_t m_stackDepth;
};
struct ShaderConstants {
C4Vector constants[256];
uint32_t unk1;
uint32_t unk2;
};
class CGxDevice {
public:
// Static variables
static uint32_t s_alphaRef[];
static C3Vector s_pointScaleIdentity;
static ShaderConstants s_shadowConstants[2];
static uint32_t s_streamPoolSize[];
static uint32_t s_texFormatBitDepth[];
static uint32_t s_texFormatBytesPerBlock[];
// Static functions
static CGxDevice* NewGLL(void);
static CGxDevice* NewOpenGl(void);
// Member variables
TSGrowableArray<CGxPushedRenderState> m_pushedStates;
TSGrowableArray<size_t> m_stackOffsets;
TSGrowableArray<EGxRenderState> m_dirtyStates;
CRect m_defWindowRect;
CRect m_curWindowRect;
EGxApi m_api = GxApis_Last;
CGxFormat m_format;
CGxCaps m_caps;
int32_t m_shaderProfiles[GxShTargets_Last] = { 6, 0, 0, 0, 12, 0 }; // TODO placeholder
TSHashTable<CGxShader, HASHKEY_STRI> m_shaderList[GxShTargets_Last];
int32_t m_context = 0;
CBoundingBox m_viewport;
C44Matrix m_projection;
C44Matrix m_projNative;
CGxMatrixStack m_xforms[GxXforms_Last];
uint32_t m_appMasterEnables = 0;
uint32_t m_hwMasterEnables = 0;
TSList<CGxPool, TSGetLink<CGxPool>> m_poolList;
CGxBuf* m_bufLocked[GxPoolTargets_Last];
CGxPool* m_vertexPool = nullptr;
CGxPool* m_indexPool = nullptr;
CGxBuf* m_streamBufs[GxPoolTargets_Last];
CGxVertexAttrib m_primVertexFormatAttrib[GxVertexBufferFormats_Last];
CGxBuf* m_primVertexFormatBuf[GxVertexBufferFormats_Last];
uint32_t m_primVertexMask = 0;
uint32_t m_primVertexDirty = 0;
EGxVertexBufferFormat m_primVertexFormat = GxVertexBufferFormats_Last;
CGxBuf* m_primVertexBuf = nullptr;
uint32_t m_primVertexSize;
CGxBuf* m_primIndexBuf = nullptr;
int32_t m_primIndexDirty = 0;
TSFixedArray<CGxAppRenderState> m_appRenderStates;
TSFixedArray<CGxStateBom> m_hwRenderStates;
uint32_t m_baseMipLevel = 0; // TODO placeholder
// Virtual member functions
virtual void ITexMarkAsUpdated(CGxTex*) = 0;
virtual void IRsSendToHw(EGxRenderState) = 0;
virtual void ICursorCreate(const CGxFormat& format);
virtual int32_t DeviceCreate(long (*)(void*, uint32_t, uint32_t, long), const CGxFormat&);
virtual int32_t DeviceSetFormat(const CGxFormat&);
virtual void CapsWindowSize(CRect&) = 0;
virtual void CapsWindowSizeInScreenCoords(CRect& dst) = 0;
virtual void ScenePresent(void);
virtual void SceneClear(uint32_t, CImVector) {};
virtual void XformSetProjection(const C44Matrix&);
virtual void XformSetView(const C44Matrix&);
virtual void Draw(CGxBatch*, int32_t) {};
virtual void ValidateDraw(CGxBatch*, int32_t);
virtual void MasterEnableSet(EGxMasterEnables, int32_t);
virtual void PoolSizeSet(CGxPool*, uint32_t) = 0;
virtual char* BufLock(CGxBuf*);
virtual int32_t BufUnlock(CGxBuf*, uint32_t);
virtual int32_t TexCreate(EGxTexTarget, uint32_t, uint32_t, uint32_t, EGxTexFormat, EGxTexFormat, CGxTexFlags, void*, void (*)(EGxTexCommand, uint32_t, uint32_t, uint32_t, uint32_t, void*, uint32_t&, const void*&), const char*, CGxTex*&);
virtual void TexDestroy(CGxTex* texId);
virtual void ShaderCreate(CGxShader*[], EGxShTarget, const char*, const char*, int32_t);
virtual void ShaderConstantsSet(EGxShTarget, uint32_t, const float*, uint32_t);
virtual void IShaderCreate(CGxShader*) = 0;
virtual int32_t StereoEnabled(void) = 0;
// Member functions
CGxDevice();
CGxBuf* BufCreate(CGxPool*, uint32_t, uint32_t, uint32_t);
CGxBuf* BufStream(EGxPoolTarget, uint32_t, uint32_t);
void DeviceCreatePools(void);
void DeviceCreateStreamBufs(void);
const CRect& DeviceCurWindow(void);
void DeviceSetCurWindow(const CRect&);
void DeviceSetDefWindow(CRect const&);
const CRect& DeviceDefWindow(void);
int32_t IDevIsWindowed();
void IRsDirty(EGxRenderState);
void IRsForceUpdate(void);
void IRsForceUpdate(EGxRenderState);
void IRsInit(void);
void IRsSync(int32_t);
void IShaderBind(void) {};
void IShaderLoad(CGxShader*[], EGxShTarget, const char*, const char*, int32_t);
void ITexBind(void) {};
void ITexWHDStartEnd(CGxTex*, uint32_t&, uint32_t&, uint32_t&, uint32_t&);
int32_t MasterEnable(EGxMasterEnables);
CGxPool* PoolCreate(EGxPoolTarget, EGxPoolUsage, uint32_t, EGxPoolHintBits, const char*);
void PrimIndexPtr(CGxBuf*);
void PrimVertexFormat(CGxBuf*, CGxVertexAttrib*, uint32_t);
void PrimVertexMask(uint32_t);
void PrimVertexPtr(CGxBuf*, EGxVertexBufferFormat);
void RsGet(EGxRenderState, int32_t&);
void RsSet(EGxRenderState, int32_t);
void RsSet(EGxRenderState, void*);
void RsSetAlphaRef(void);
void RsPop(void);
void RsPush(void);
void ShaderConstantsClear(void);
char* ShaderConstantsLock(EGxShTarget target);
void ShaderConstantsUnlock(EGxShTarget target, uint32_t index, uint32_t count);
void TexMarkForUpdate(CGxTex*, const CiRect&, int32_t);
void TexSetWrap(CGxTex* texId, EGxTexWrapMode wrapU, EGxTexWrapMode wrapV);
void XformPop(EGxXform xf);
void XformProjection(C44Matrix&);
void XformProjNative(C44Matrix&);
void XformPush(EGxXform xf);
void XformSet(EGxXform xf, const C44Matrix& matrix);
void XformSetViewport(float, float, float, float, float, float);
void XformView(C44Matrix&);
void XformViewport(float&, float&, float&, float&, float&, float&);
};
#endif

32
src/gx/CGxFormat.hpp Normal file
View file

@ -0,0 +1,32 @@
#ifndef GX_C_GX_FORMAT_HPP
#define GX_C_GX_FORMAT_HPP
#include <cstdint>
#include <tempest/Vector.hpp>
class CGxFormat {
public:
// Types
enum Format {
Fmt_Rgb565 = 0,
Fmt_ArgbX888 = 1,
Fmt_Argb8888 = 2,
Fmt_Argb2101010 = 3,
Fmt_Ds160 = 4,
Fmt_Ds24X = 5,
Fmt_Ds248 = 6,
Fmt_Ds320 = 7,
Formats_Last = 8
};
// Member variables
int8_t window;
int32_t maximize;
Format depthFormat;
C2iVector size;
uint32_t sampleCount;
Format colorFormat;
uint32_t refreshRate;
};
#endif

30
src/gx/CGxMatrixStack.cpp Normal file
View file

@ -0,0 +1,30 @@
#include "gx/CGxMatrixStack.hpp"
CGxMatrixStack::CGxMatrixStack() {
this->m_flags[0] = 0x1;
}
void CGxMatrixStack::Pop() {
if (this->m_level > 0) {
this->m_level--;
}
this->m_dirty = 1;
}
void CGxMatrixStack::Push() {
if (this->m_level < 3) {
this->m_level++;
}
this->m_mtx[this->m_level] = this->m_mtx[this->m_level - 1];
this->m_flags[this->m_level] = this->m_flags[this->m_level - 1];
this->m_dirty = 1;
}
C44Matrix& CGxMatrixStack::Top() {
this->m_dirty = 1;
this->m_flags[this->m_level] &= 0xFFFFFFFE;
return this->m_mtx[this->m_level];
}

22
src/gx/CGxMatrixStack.hpp Normal file
View file

@ -0,0 +1,22 @@
#ifndef GX_C_GX_MATRIX_STACK_HPP
#define GX_C_GX_MATRIX_STACK_HPP
#include <cstdint>
#include <tempest/Matrix.hpp>
class CGxMatrixStack {
public:
// Member variables
uint32_t m_level = 0;
int8_t m_dirty = 0;
C44Matrix m_mtx[4];
uint32_t m_flags[4] = {};
// Member functions
CGxMatrixStack();
void Pop(void);
void Push(void);
C44Matrix& Top(void);
};
#endif

85
src/gx/CGxStateBom.cpp Normal file
View file

@ -0,0 +1,85 @@
#include "gx/CGxStateBom.hpp"
#include <tempest/Vector.hpp>
const CGxStateBom& CGxStateBom::operator=(int32_t value) {
this->m_data.i[0] = value;
return *this;
}
const CGxStateBom& CGxStateBom::operator=(uint32_t value) {
this->m_data.i[0] = value;
return *this;
}
const CGxStateBom& CGxStateBom::operator=(float value) {
this->m_data.f[0] = value;
return *this;
}
const CGxStateBom& CGxStateBom::operator=(void* value) {
this->m_data.p = value;
return *this;
}
const CGxStateBom& CGxStateBom::operator=(C3Vector& value) {
this->m_data.f[0] = value.x;
this->m_data.f[1] = value.y;
this->m_data.f[2] = value.z;
return *this;
}
bool CGxStateBom::operator!=(int32_t value) {
return this->m_data.i[0] != value;
}
bool CGxStateBom::operator!=(uint32_t value) {
return this->m_data.i[0] != value;
}
bool CGxStateBom::operator!=(float value) {
return this->m_data.f[0] != value;
}
bool CGxStateBom::operator!=(void* value) {
return this->m_data.p != value;
}
bool CGxStateBom::operator!=(C3Vector& value) {
return this->m_data.f[0] != value.x
|| this->m_data.f[1] != value.y
|| this->m_data.f[2] != value.z;
}
bool CGxStateBom::operator!=(CGxStateBom& value) {
return (this->m_data.i[0] - value.m_data.i[0])
| (this->m_data.i[1] - value.m_data.i[1])
| (this->m_data.i[2] - value.m_data.i[2])
| (this->filler - value.filler);
}
CGxStateBom::operator CImVector() const {
CImVector color;
color.value = this->m_data.i[0];
return color;
}
CGxStateBom::operator float() const {
return this->m_data.f[0];
}
CGxStateBom::operator int32_t() const {
return this->m_data.i[0];
}
CGxStateBom::operator uint32_t() const {
return this->m_data.i[0];
}
CGxStateBom::operator void*() const {
return this->m_data.p;
}

39
src/gx/CGxStateBom.hpp Normal file
View file

@ -0,0 +1,39 @@
#ifndef GX_C_GX_STATE_BOM_HPP
#define GX_C_GX_STATE_BOM_HPP
#include <cstdint>
class C3Vector;
class CImVector;
class CGxStateBom {
public:
// Member variables
union {
int32_t i[3];
float f[3];
void* p;
} m_data;
int32_t filler;
// Member functions
const CGxStateBom& operator=(float);
const CGxStateBom& operator=(int32_t);
const CGxStateBom& operator=(uint32_t);
const CGxStateBom& operator=(void*);
const CGxStateBom& operator=(C3Vector&);
bool operator!=(float);
bool operator!=(int32_t);
bool operator!=(uint32_t);
bool operator!=(void*);
bool operator!=(C3Vector&);
bool operator!=(CGxStateBom&);
explicit operator CImVector() const;
explicit operator float() const;
explicit operator int32_t() const;
explicit operator uint32_t() const;
explicit operator void*() const;
};
#endif

43
src/gx/CMakeLists.txt Normal file
View file

@ -0,0 +1,43 @@
file(GLOB GX_SOURCES
"*.cpp"
"buffer/*.cpp"
"font/*.cpp"
"shader/*.cpp"
"texture/*.cpp"
)
if(WHOA_SYSTEM_MAC)
file(GLOB GLL_SOURCES "gll/*.cpp" "gll/*.mm")
set_source_files_properties(${GLL_SOURCES}
PROPERTIES COMPILE_FLAGS "-x objective-c++"
)
list(APPEND GX_SOURCES ${GLL_SOURCES})
endif()
add_library(gx STATIC ${GX_SOURCES})
target_include_directories(gx
PRIVATE
${CMAKE_SOURCE_DIR}/src
)
target_link_libraries(gx
PRIVATE
event
math
model
ui
util
PUBLIC
freetype-2.0
storm
tempest
)
if(WHOA_SYSTEM_MAC)
target_link_libraries(gx
PRIVATE
"-framework AppKit"
"-framework OpenGL"
)
endif()

70
src/gx/Camera.cpp Normal file
View file

@ -0,0 +1,70 @@
#include "gx/Camera.hpp"
#include "gx/CCamera.hpp"
#include "gx/Device.hpp"
#include "gx/Transform.hpp"
#include <common/Handle.hpp>
#include <storm/Error.hpp>
HCAMERA CameraCreate() {
void* m = SMemAlloc(sizeof(CCamera), __FILE__, __LINE__, 0x0);
auto camera = new (m) CCamera();
return HandleCreate(camera);
}
void CameraSetupScreenProjection(const CRect& projectionRect, const C2Vector& screenPoint, float depth, int32_t a4) {
float offsetX = (projectionRect.minX + projectionRect.maxX) * 0.5f;
float offsetY = (projectionRect.minY + projectionRect.maxY) * 0.5f;
CRect frustumRect = {
projectionRect.minY - offsetY,
projectionRect.minX - offsetX,
projectionRect.maxY - offsetY,
projectionRect.maxX - offsetX
};
float minZ = -500.0f;
float maxZ = 500.0f;
C44Matrix proj;
if (a4 || !g_theGxDevicePtr->StereoEnabled()) {
GxuXformCreateOrtho(
frustumRect.minX,
frustumRect.maxX,
frustumRect.minY,
frustumRect.maxY,
minZ,
maxZ,
proj
);
C3Vector v50 = { 1.0f, 1.0f, -1.0f };
proj.Scale(v50);
} else {
GxuXformCreateOrthoDepth(
frustumRect.minX,
frustumRect.maxX,
frustumRect.minY,
frustumRect.maxY,
minZ,
maxZ,
proj
);
}
// TODO some caps stuff
GxXformSetProjection(proj);
C44Matrix view;
C3Vector move = { screenPoint.x - offsetX, screenPoint.y - offsetY, 0.0f };
view.Translate(move);
GxXformSetView(view);
}
void CameraSetupWorldProjection(HCAMERA camera, const CRect& projectionRect, uint32_t flags) {
auto cameraPtr = reinterpret_cast<CCamera*>(camera);
STORM_ASSERT(cameraPtr);
cameraPtr->SetupWorldProjection(projectionRect, flags);
}

18
src/gx/Camera.hpp Normal file
View file

@ -0,0 +1,18 @@
#ifndef GX_CAMERA_HPP
#define GX_CAMERA_HPP
#include <cstdint>
#include <common/DataMgr.hpp>
typedef HDATAMGR HCAMERA;
class CRect;
class C2Vector;
HCAMERA CameraCreate(void);
void CameraSetupScreenProjection(const CRect&, const C2Vector&, float, int32_t);
void CameraSetupWorldProjection(HCAMERA camera, const CRect& projectionRect, uint32_t flags);
#endif

58
src/gx/Coordinate.cpp Normal file
View file

@ -0,0 +1,58 @@
#include "gx/Coordinate.hpp"
#include <cmath>
namespace Coordinate {
float s_aspect = 1.333333f;
float s_aspectCompensation = 1.0f;
float s_y = 0.6f;
float s_x = 0.8f;
}
float CoordinateGetAspectCompensation() {
return Coordinate::s_aspectCompensation;
}
void CoordinateSetAspectRatio(float aspect) {
Coordinate::s_aspect = aspect;
Coordinate::s_aspectCompensation = aspect * 0.75;
float v1 = 1.0 / sqrt(aspect * aspect + 1.0);
Coordinate::s_y = v1;
Coordinate::s_x = aspect * v1;
}
void DDCToNDC(float ddcx, float ddcy, float* ndcx, float* ndcy) {
if (ndcx) {
*ndcx = ddcx / Coordinate::s_x;
}
if (ndcy) {
*ndcy = ddcy / Coordinate::s_y;
}
}
float DDCToNDCHeight(float ddcy) {
return ddcy / Coordinate::s_y;
}
float DDCToNDCWidth(float ddcx) {
return ddcx / Coordinate::s_x;
}
void NDCToDDC(float ndcx, float ndcy, float* ddcx, float* ddcy) {
if (ddcx) {
*ddcx = Coordinate::s_x * ndcx;
}
if (ddcy) {
*ddcy = Coordinate::s_y * ndcy;
}
}
float NDCToDDCHeight(float ndcy) {
return Coordinate::s_y * ndcy;
}
float NDCToDDCWidth(float ndcx) {
return Coordinate::s_x * ndcx;
}

20
src/gx/Coordinate.hpp Normal file
View file

@ -0,0 +1,20 @@
#ifndef GX_COORDINATE_HPP
#define GX_COORDINATE_HPP
float CoordinateGetAspectCompensation(void);
void CoordinateSetAspectRatio(float);
void DDCToNDC(float, float, float*, float*);
float DDCToNDCHeight(float);
float DDCToNDCWidth(float);
void NDCToDDC(float, float, float*, float*);
float NDCToDDCHeight(float);
float NDCToDDCWidth(float);
#endif

51
src/gx/Device.cpp Normal file
View file

@ -0,0 +1,51 @@
#include "gx/Device.hpp"
#include "gx/CGxDevice.hpp"
#include "gx/Gx.hpp"
CGxDevice* g_theGxDevicePtr = nullptr;
CGxDevice* GxDevCreate(EGxApi api, long (*windowProc)(void*, uint32_t, uint32_t, long), const CGxFormat& format) {
CGxDevice* device;
#if defined(WHOA_SYSTEM_WIN)
if (api == GxApi_OpenGl) {
device = CGxDevice::NewOpenGl();
} else if (api == GxApi_D3d9) {
device = CGxDevice::NewD3d();
} else if (api == GxApi_D3d9Ex) {
device = CGxDevice::NewD3d9Ex();
} else {
// Error
}
#endif
#if defined(WHOA_SYSTEM_MAC)
if (api == GxApi_OpenGl) {
device = CGxDevice::NewOpenGl();
} else if (api == GxApi_GLL) {
device = CGxDevice::NewGLL();
} else {
// Error
}
#endif
g_theGxDevicePtr = device;
if (g_theGxDevicePtr->DeviceCreate(windowProc, format)) {
return g_theGxDevicePtr;
} else {
if (g_theGxDevicePtr) {
delete g_theGxDevicePtr;
}
return nullptr;
}
}
EGxApi GxDevApi() {
return g_theGxDevicePtr->m_api;
}
int32_t GxMasterEnable(EGxMasterEnables state) {
return g_theGxDevicePtr->MasterEnable(state);
}

18
src/gx/Device.hpp Normal file
View file

@ -0,0 +1,18 @@
#ifndef GX_DEVICE_HPP
#define GX_DEVICE_HPP
#include "gx/CGxDevice.hpp"
#include "gx/Types.hpp"
#include <cstdint>
class CGxFormat;
extern CGxDevice* g_theGxDevicePtr;
CGxDevice* GxDevCreate(EGxApi, long (*)(void*, uint32_t, uint32_t, long), const CGxFormat&);
EGxApi GxDevApi(void);
int32_t GxMasterEnable(EGxMasterEnables state);
#endif

21
src/gx/Draw.cpp Normal file
View file

@ -0,0 +1,21 @@
#include "gx/Draw.hpp"
#include "gx/Device.hpp"
void GxDraw(CGxBatch* batches, int32_t count) {
g_theGxDevicePtr->Draw(batches, count);
}
void GxSceneClear(uint32_t mask, CImVector color) {
g_theGxDevicePtr->SceneClear(mask, color);
}
void GxScenePresent() {
C3Vector v2 = { 0.0f, 0.0f, 0.0f };
GxuFlushDrawList(GxuCat_2, v2);
g_theGxDevicePtr->ScenePresent();
}
void GxuFlushDrawList(EGxuDrawListCategory a1, const C3Vector& a2) {
// TODO
}

19
src/gx/Draw.hpp Normal file
View file

@ -0,0 +1,19 @@
#ifndef GX_DRAW_HPP
#define GX_DRAW_HPP
#include "gx/CGxBatch.hpp"
#include "gx/Types.hpp"
#include <cstdint>
class C3Vector;
class CImVector;
void GxDraw(CGxBatch*, int32_t);
void GxSceneClear(uint32_t, CImVector);
void GxScenePresent(void);
void GxuFlushDrawList(EGxuDrawListCategory, const C3Vector&);
#endif

996
src/gx/Font.cpp Normal file
View file

@ -0,0 +1,996 @@
#include "gx/Font.hpp"
#include "gx/font/CGxFont.hpp"
#include "gx/font/CGxString.hpp"
#include "gx/font/CGxStringBatch.hpp"
#include "gx/font/Wrap.hpp"
#include "gx/Coordinate.hpp"
#include "gx/Device.hpp"
#include "gx/FontInternal.hpp"
#include "gx/Gx.hpp"
#include "gx/Shader.hpp"
#include <algorithm>
#include <cstring>
#include <new>
#include <storm/Error.hpp>
#include <storm/Memory.hpp>
#include <storm/String.hpp>
#include <storm/Unicode.hpp>
#include <tempest/Math.hpp>
CGxShader* g_fontPixelShader[1];
CGxShader* g_fontVertexShader[2];
TSList<CGxFont, TSGetLink<CGxFont>> g_fonts;
TSHashTable<FONTHASHOBJ, HASHKEY_STR> s_fontHash;
uint32_t g_heightPixels;
uint32_t g_widthPixels;
float g_indentPixelWidth;
float g_indentNormWidth;
TSList<CGxStringBatch, TSGetLink<CGxStringBatch>> s_unusedBatches;
STORM_LIST(CGxString) g_freeStrings;
STORM_LIST(CGxString) g_strings;
FONTHASHOBJ::~FONTHASHOBJ() {
if (this->font) {
GxuFontDestroyFont(this->font);
}
}
TEXTBLOCK::~TEXTBLOCK() {
GxuFontDestroyString(this->string);
}
void CalculateYOffset(uint32_t pixelHeight, uint32_t a2, FT_Face face, uint32_t glyphHeight, int32_t* yOffset, int32_t* yStart) {
uint32_t v6 = 0;
int32_t v8 = 0;
if (glyphHeight <= pixelHeight) {
uint32_t v9 = face->glyph->bitmap_top;
if (v9 <= a2) {
v8 = a2 - v9;
} else {
v8 = 0;
v6 = v9 - a2;
}
}
uint32_t v10 = v8 <= 0 ? 0 : v8;
uint32_t v11 = pixelHeight - glyphHeight;
if (v11 >= v10) {
*yOffset = v6;
*yStart = v10;
} else {
*yOffset = pixelHeight - v10 - glyphHeight;
*yStart = v11;
}
}
uint32_t ConvertStringFlags(uint32_t flags) {
uint32_t convertedFlags = 0x0;
if (flags & 0x100) {
convertedFlags |= 0x1;
}
if (flags & 0x200) {
convertedFlags |= 0x4;
}
if (flags & 0x400) {
convertedFlags |= 0x8;
}
if (flags & 0x800) {
convertedFlags |= 0x10;
}
if (flags & 0x40) {
convertedFlags |= 0x2;
}
if (flags & 0x1000) {
convertedFlags |= 0x40;
}
if (flags & 0x2000) {
convertedFlags |= 0x100;
}
if (flags & 0x4000) {
convertedFlags |= 0x200;
}
if (flags & 0x8000) {
convertedFlags |= 0x400;
}
if (flags & 0x80) {
convertedFlags |= 0x800;
}
if (flags & 0x10000) {
convertedFlags |= 0x1000;
}
if (flags & 0x20000) {
convertedFlags |= 0x2000;
}
return convertedFlags;
}
float GetCharacterWidth(const char* text, uint32_t flags, uint32_t prevCode, CGxFont* font, float a5) {
if (!prevCode) {
return 0.0f;
}
float width = 0.0f;
while (*text) {
int32_t advance;
uint32_t code;
QUOTEDCODE quotedCode = GxuDetermineQuotedCode(text, advance, nullptr, flags, code);
text += advance;
if (quotedCode == CODE_INVALIDCODE) {
if (flags & 0x10) {
// TODO
// width = font->ComputeStepFixedWidth(prevCode, code);
} else {
width = font->ComputeStep(prevCode, code);
}
break;
}
if (quotedCode == CODE_NEWLINE) {
break;
}
}
if (width == 0.0f) {
auto glyph = font->NewCodeDesc(prevCode);
if (glyph) {
width = font->GetGlyphBearing(glyph, flags & 0x80, a5) + glyph->bitmapData.m_glyphCellWidth;
}
}
return width;
}
float GetIndentNormWidth() {
return g_indentNormWidth;
}
float GetIndentPixelWidth() {
return g_indentPixelWidth;
}
uint32_t GetScreenPixelHeight() {
return g_heightPixels;
}
uint32_t GetScreenPixelWidth() {
return g_widthPixels;
}
QUOTEDCODE GxuDetermineQuotedCode(const char* text, int32_t& advance, CImVector* color, uint32_t flags, uint32_t& wide) {
wide = SUniSGetUTF8(reinterpret_cast<const uint8_t*>(text), &advance);
switch (wide) {
case 0x0:
case 0xFFFFFFFF:
return CODE_INVALIDCODE;
case '\r':
advance = 2 - (SUniSGetUTF8(reinterpret_cast<const uint8_t*>(text + 1), &advance) != '\n');
return CODE_NEWLINE;
case '\n':
advance = 1;
return CODE_NEWLINE;
}
if (wide != '|' || flags & 0x800) {
return CODE_INVALIDCODE;
}
auto quotedCode = text[advance];
if (!quotedCode) {
return CODE_INVALIDCODE;
}
switch (quotedCode) {
case 'N':
case 'n': {
if (flags & 0x200) {
return CODE_INVALIDCODE;
}
advance = 2;
return CODE_NEWLINE;
}
// TODO handle other control codes
}
// TODO remainder of function
return CODE_INVALIDCODE;
}
int32_t GxuFontAddToBatch(CGxStringBatch* batch, CGxString* string) {
if (batch && string) {
batch->AddString(string);
return 1;
} else {
return 0;
}
}
void GxuFontAddShadow(CGxString* string, const CImVector& color, const C2Vector& offset) {
if (string) {
if (!(string->m_flags & 0x80)) {
string->AddShadow(offset, color);
}
}
}
CGxStringBatch* GxuFontCreateBatch(bool a1, bool a2) {
CGxStringBatch* batch;
if (s_unusedBatches.Head()) {
batch = s_unusedBatches.Head();
s_unusedBatches.UnlinkNode(batch);
} else {
void* m = SMemAlloc(sizeof(CGxStringBatch), __FILE__, __LINE__, 0x8);
batch = new (m) CGxStringBatch();
}
if (a1) {
batch->m_flags |= 0x1;
} else {
batch->m_flags &= ~0x1;
}
if (a2) {
batch->m_flags |= 0x2;
} else {
batch->m_flags &= ~0x2;
}
return batch;
}
int32_t GxuFontCreateFont(const char* name, float fontHeight, CGxFont*& face, uint32_t flags) {
STORM_ASSERT(name);
STORM_ASSERT(*name);
STORM_ASSERT((fontHeight <= 1.0f) && (fontHeight > 0.0f));
CGxFont* newFace = g_fonts.NewNode(2, 0, 0);
uint32_t v12 = flags;
if (flags & 0x8) {
v12 |= 0x1;
}
int32_t v13 = newFace->Initialize(name, v12, fontHeight);
if (!v13) {
g_fonts.DeleteNode(newFace);
newFace = nullptr;
}
face = newFace;
return v13;
}
int32_t GxuFontCreateString(CGxFont* face, const char* text, float fontHeight, const C3Vector& position, float blockWidth, float blockHeight, float spacing, CGxString*& string, EGxFontVJusts vertJustification, EGxFontHJusts horzJustification, uint32_t flags, const CImVector& color, float charSpacing, float scale) {
STORM_ASSERT(face);
STORM_ASSERT(text);
// TODO
// STORM_ASSERT(fontHeight || (flags & EGxStringFlags_FixedSize));
STORM_ASSERT(vertJustification < GxVJ_Last);
STORM_ASSERT(horzJustification < GxHJ_Last);
auto newString = CGxString::GetNewString(1);
int32_t result = newString->Initialize(
fontHeight,
position,
blockWidth,
blockHeight,
face,
text,
vertJustification,
horzJustification,
spacing,
flags & ~0x1,
color,
scale
);
if (result) {
string = newString;
} else {
GxuFontDestroyString(newString);
}
return result;
}
int32_t GxuFontDestroyBatch(CGxStringBatch* batch) {
if (!batch) {
return 0;
}
batch->m_fontBatch.Clear();
s_unusedBatches.LinkToTail(batch);
return 1;
}
void GxuFontDestroyFont(CGxFont*& font) {
if (font) {
g_fonts.DeleteNode(font);
}
font = nullptr;
}
void GxuFontDestroyString(CGxString*& string) {
if (string) {
string->Unlink();
string->Recycle();
string = nullptr;
}
}
uint32_t GxuFontGetFontFlags(CGxFont* font) {
if (font) {
return font->m_flags;
}
return 0;
}
const char* GxuFontGetFontName(CGxFont* font) {
return font
? font->GetName()
: nullptr;
}
uint32_t GxuFontGetMaxCharsWithinWidth(CGxFont* font, const char* text, float height, float maxWidth, uint32_t lineBytes, float* extent, float a7, float scale, float a9, uint32_t flags) {
return InternalGetMaxCharsWithinWidth(
font,
text,
height,
maxWidth,
lineBytes,
extent,
flags,
a7,
scale,
nullptr,
nullptr,
nullptr
);
}
uint32_t GxuFontGetMaxCharsWithinWidthAndHeight(CGxFont* font, const char* text, float fontHeight, float maxWidth, float maxHeight, uint32_t lineBytes, float a7, float scale, float a9, uint32_t flags) {
if (!font) {
return 0;
}
if (!text || !*text) {
return 0;
}
if (fontHeight == 0.0f || maxWidth == 0.0f || maxHeight == 0.0f || g_heightPixels == 0.0f) {
return 0;
}
if (lineBytes == 0) {
return 0;
}
if (flags & 0x4) {
fontHeight = GxuFontGetOneToOneHeight(font);
}
auto v24 = static_cast<float>(g_heightPixels) * a9;
auto v22 = CMath::fuint_pi(v24);
auto v12 = static_cast<float>(v22) / static_cast<float>(g_heightPixels);
bool v26 = true;
auto v27 = v12;
v24 = 0.0f;
auto v13 = fontHeight;
const char* nextText;
uint32_t maxChars = 0;
auto currentText = text;
int32_t v25 = 0;
while (*currentText) {
if (flags & 0x2000 && v25 == 1) {
maxWidth -= g_indentNormWidth;
}
float v21;
CalcWrapPoint(
font,
currentText,
fontHeight,
maxWidth,
&v22,
&v21,
&nextText,
a7,
flags,
&v26,
0,
scale
);
v22 = nextText - currentText;
if (nextText == currentText) {
break;
}
auto v15 = v24;
auto v16 = v25 + 1 < 0;
auto v17 = v24 + fontHeight;
v25++;
float v18 = v25;
if (v16) {
v18 = v18 + 4294967300.0;
}
if (v18 * 0.00000095367431640625 + maxHeight < v17) {
break;
}
maxChars += nextText - currentText;
currentText = nextText;
v24 = fontHeight + v15 + v27;
if (!v26 || !nextText) {
break;
}
}
return maxChars;
}
float GxuFontGetOneToOneHeight(CGxFont* font) {
STORM_ASSERT(font);
return PixelToScreenHeight(font->GetPixelSize());
}
void GxuFontGetTextExtent(CGxFont* font, const char* text, uint32_t numBytes, float a4, float* extent, float a6, float a7, float a8, uint32_t flags) {
InternalGetTextExtent(font, text, numBytes, a4, extent, flags, a6, a7);
}
float GxuFontGetWrappedTextHeight(CGxFont* font, const char* text, float a3, float a4, const C2Vector& a5, float a6, float a7, uint32_t flags) {
STORM_ASSERT(font);
STORM_ASSERT(text);
if (flags & 0x04) {
a3 = GxuFontGetOneToOneHeight(font);
}
int32_t advance;
uint32_t numBytes;
uint32_t code;
int32_t v8 = 0;
float extent = 0.0f;
float v17 = 0.0f;
float v18 = 0.0f;
const char* currentText = text;
const char* nextText = nullptr;
bool v21 = true;
while (currentText && *currentText) {
QUOTEDCODE quotedCode = GxuDetermineQuotedCode(currentText, advance, nullptr, flags, code);
if (flags & 0x2000 && v8 == 1) {
a4 = a4 - g_indentNormWidth;
}
if (quotedCode == CODE_NEWLINE) {
nextText = currentText + advance;
} else {
CalcWrapPoint(
font,
currentText,
a3,
a4,
&numBytes,
&extent,
&nextText,
a5.x,
flags,
&v21,
&v17,
a6
);
if (currentText == nextText) {
break;
}
}
v8++;
currentText = nextText;
float v14 = (float)GetScreenPixelHeight() * a3;
if (v14 < v17) {
v18 = v17 - v14 + v18;
}
if (flags & 0x02) {
break;
}
}
if (!(flags & 0x02) && currentText > text && GxuDetermineQuotedCode(currentText - 1, advance, nullptr, flags, code) == CODE_NEWLINE) {
v8++;
}
if (!v8) {
return 0.0f;
}
float v22 = GetScreenPixelHeight();
float v14 = v22 * a7;
float v13 = v14 + 0.99994999f;
float v23 = v13 / v22;
return (v18 / v22 + v23 * (float)(v8 - 1) + (float)v8 * a3);
}
void GxuFontInitialize() {
g_theGxDevicePtr->ShaderCreate(g_fontVertexShader, GxSh_Vertex, "Shaders\\Vertex", "UI", 2);
g_theGxDevicePtr->ShaderCreate(g_fontPixelShader, GxSh_Pixel, "Shaders\\Pixel", "UI", 1);
BATCHEDRENDERFONTDESC::Initialize();
FreeTypeInitialize();
GxuFontWindowSizeChanged();
// TODO
// sub_6BD160();
}
void GxuFontRenderBatch(CGxStringBatch* batch) {
if (batch) {
batch->RenderBatch();
}
}
int32_t GxuFontSetStringColor(CGxString* string, const CImVector& color) {
STORM_ASSERT(string);
string->SetColor(color);
return 1;
}
void GxuFontSetStringPosition(CGxString* string, const C3Vector& position) {
STORM_ASSERT(string);
string->SetStringPosition(position);
}
void GxuFontUpdate() {
for (auto string = g_strings.Head(); string; string = g_strings.Link(string)->Next()) {
string->Tick();
}
// TODO
}
void GxuFontWindowSizeChanged() {
static CRect s_currentRect = { 0.0f, 0.0f, 0.0f, 0.0f };
CRect rect = { 0.0f, 0.0f, 0.0f, 0.0f };
GxCapsWindowSize(rect);
if (rect.maxY - rect.minY == 0.0f || rect.maxX - rect.minX == 0.0f) {
rect = { 0.0f, 0.0f, 480.0f, 640.0f };
}
if (s_currentRect == rect) {
return;
}
s_currentRect = rect;
g_widthPixels = rect.maxX - rect.minX;
g_heightPixels = rect.maxY - rect.minY;
g_indentPixelWidth = 15.0f;
g_indentNormWidth = 15.0f / (rect.maxX - rect.minX);
// TODO
// - walk s_fonts and trigger HandleScreenSizeChange
}
int32_t IGxuFontGlyphRenderGlyph(FT_Face face, uint32_t pixelHeight, uint32_t code, uint32_t baseline, GLYPHBITMAPDATA* dataPtr, int32_t monochrome, uint32_t a7) {
STORM_ASSERT(face);
STORM_ASSERT(pixelHeight);
STORM_ASSERT(dataPtr);
if (!FT_Get_Char_Index(face, code)) {
return 0;
}
if (!FREETYPE_RenderGlyph(code, monochrome != 0, face)) {
return 0;
}
auto glyph = face->glyph;
uint32_t width = glyph->bitmap.width;
uint32_t height = std::min(static_cast<uint32_t>(glyph->bitmap.rows), pixelHeight);
size_t dataSize = glyph->bitmap.pitch * glyph->bitmap.rows;
auto srcData = glyph->bitmap.buffer;
uint32_t pitch = glyph->bitmap.pitch;
int32_t dummyGlyph = 0;
if (!width || !height || !srcData || !pitch || !dataSize) {
width = (pixelHeight + 3) >> 2;
height = pixelHeight;
if (!width) {
width = pixelHeight;
}
if (monochrome) {
pitch = (width + 7) & 0xFFFFFFF8;
} else {
pitch = width;
}
dataSize = pixelHeight * pitch;
dummyGlyph = 1;
}
void* data = SMemAlloc(dataSize, __FILE__, __LINE__, 0x0);
if (data) {
memset(data, 0, dataSize);
}
if (srcData) {
memcpy(data, srcData, dataSize);
}
dataPtr->m_data = data;
dataPtr->m_dataSize = dataSize;
dataPtr->m_glyphPitch = pitch;
dataPtr->m_glyphWidth = width;
dataPtr->m_glyphHeight = height;
dataPtr->m_glyphCellWidth = width + a7;
dataPtr->m_glyphAdvance = (double)(face->glyph->metrics.horiAdvance / 64) + 1.0;
dataPtr->m_glyphBearing = (double)face->glyph->metrics.horiBearingX * 0.015625;
dataPtr->m_yOffset = 0;
dataPtr->m_yStart = 0;
if (width && height && data && !dummyGlyph) {
CalculateYOffset(pixelHeight, baseline, face, height, &dataPtr->m_yOffset, &dataPtr->m_yStart);
}
return 1;
}
float PixelToScreenHeight(int32_t height) {
return (double)height / (double)g_heightPixels;
}
float PixelToScreenWidth(int32_t width) {
return (double)width / (double)g_widthPixels;
}
float PixelToScreenWidth(float width) {
return width / (double)g_widthPixels;
}
float ScreenToPixelHeight(int32_t billboarded, float height) {
if (billboarded) {
return height;
}
float pixelCoords = static_cast<double>(g_heightPixels) * height;
return CMath::fint_n(pixelCoords);
}
float ScreenToPixelWidth(int32_t billboarded, float width) {
if (billboarded) {
return width;
}
float pixelCoords = static_cast<double>(g_widthPixels) * width;
return CMath::fint_n(pixelCoords);
}
float Sub6C2280(FT_Face face, float height) {
int32_t numFixedSizes = face->num_fixed_sizes;
if (numFixedSizes == 0) {
return height;
}
int32_t v4 = INT_MAX;
auto availableSizes = face->available_sizes;
for (int32_t i = 0; i < numFixedSizes; i++) {
if (v4 >= availableSizes->height) {
v4 = availableSizes->height;
}
availableSizes++;
}
float v7 = PixelToScreenHeight(v4);
return v7 >= height ? v7 : height;
}
void TextBlockAddShadow(HTEXTBLOCK string, CImVector color, const C2Vector& offset) {
STORM_ASSERT(string);
C2Vector ndcOffset;
DDCToNDC(offset.x, offset.y, &ndcOffset.x, &ndcOffset.y);
GxuFontAddShadow(TextBlockGetStringPtr(string), color, offset);
}
HTEXTBLOCK TextBlockCreate(HTEXTFONT font, const char* text, const CImVector& color, const C3Vector& pos, float fontHeight, float blockWidth, float blockHeight, uint32_t flags, float charSpacing, float lineSpacing, float scale) {
STORM_ASSERT(font);
STORM_ASSERT(text);
void* m = SMemAlloc(sizeof(TEXTBLOCK), __FILE__, __LINE__, 0x0);
auto textBlock = new (m) TEXTBLOCK();
C3Vector position = { 0.0f, 0.0f, pos.z };
DDCToNDC(pos.x, pos.y, &position.x, &position.y);
EGxFontHJusts hjust = GxHJ_Center;
if (flags & 0x4) {
hjust = GxHJ_Right;
} else if (!(flags & 0x2) && flags & 0x1) {
hjust = GxHJ_Left;
}
EGxFontVJusts vjust = GxVJ_Middle;
if (flags & 0x8) {
vjust = GxVJ_Top;
} else if (flags & 0x20) {
vjust = GxVJ_Bottom;
}
uint32_t v16 = ConvertStringFlags(flags);
float v15 = DDCToNDCWidth(charSpacing);
float v20 = DDCToNDCHeight(lineSpacing);
float v21 = DDCToNDCHeight(blockHeight);
float v22 = DDCToNDCWidth(blockWidth);
float v23 = DDCToNDCHeight(fontHeight);
GxuFontCreateString(
reinterpret_cast<FONTHASHOBJ*>(font)->font,
text,
v23,
position,
v22,
v21,
v20,
textBlock->string,
vjust,
hjust,
v16,
color,
v15,
scale
);
return HandleCreate(textBlock);
}
HTEXTFONT TextBlockGenerateFont(const char* fontName, uint32_t fontFlags, float fontHeight) {
STORM_ASSERT(fontName);
STORM_ASSERT(*fontName);
float fontHeightNDC = DDCToNDCHeight(fontHeight);
if (fontHeightNDC >= 1.0) {
fontHeightNDC = 1.0;
}
char hashKey[276];
SStrPrintf(hashKey, 276, "%s-%d-%f", fontName, fontFlags, fontHeightNDC);
auto v7 = s_fontHash.Ptr(hashKey);
if (v7) {
return HandleCreate(v7);
}
v7 = s_fontHash.New(hashKey, 0, 0);
uint32_t v14 = 0;
if (fontFlags & FONT_OUTLINE) {
v14 |= 0x1;
}
if (fontFlags & FONT_THICKOUTLINE) {
v14 |= 0x8;
}
if (fontFlags & FONT_MONOCHROME) {
v14 |= 0x2;
}
if (GxuFontCreateFont(fontName, fontHeightNDC, v7->font, v14)) {
return HandleCreate(v7);
} else {
// TODO
// sub_723270(v12);
// (s_fontHash)(&s_fontHash, v12);
return nullptr;
}
}
uint32_t TextBlockGetFontFlags(HTEXTFONT fontHandle) {
STORM_ASSERT(fontHandle);
uint32_t gxFlags = GxuFontGetFontFlags(TextBlockGetFontPtr(fontHandle));
uint32_t flags = 0;
if (gxFlags & 0x1) {
flags |= 0x1;
}
if (gxFlags & 0x2) {
flags |= 0x2;
}
if (gxFlags & 0x8) {
flags |= 0x4;
}
return flags;
}
const char* TextBlockGetFontName(HTEXTFONT fontHandle) {
STORM_ASSERT(fontHandle);
return GxuFontGetFontName(reinterpret_cast<FONTHASHOBJ*>(fontHandle)->font);
}
CGxFont* TextBlockGetFontPtr(HTEXTFONT fontHandle) {
STORM_ASSERT(fontHandle);
return reinterpret_cast<FONTHASHOBJ*>(fontHandle)->font;
}
uint32_t TextBlockGetMaxCharsWithinWidth(HTEXTFONT fontHandle, const char* text, float height, float maxWidth, uint32_t lineBytes, float* extent, float a7, float scale, float a9, uint32_t flags) {
STORM_ASSERT(fontHandle);
STORM_ASSERT(text);
return GxuFontGetMaxCharsWithinWidth(
TextBlockGetFontPtr(fontHandle),
text,
DDCToNDCHeight(height),
DDCToNDCWidth(maxWidth),
lineBytes,
extent,
DDCToNDCWidth(a7),
scale,
DDCToNDCWidth(a9),
ConvertStringFlags(flags)
);
}
uint32_t TextBlockGetMaxCharsWithinWidthAndHeight(HTEXTFONT fontHandle, const char* text, float height, float maxWidth, float maxHeight, uint32_t lineBytes, float a7, float scale, float a9, uint32_t flags) {
STORM_ASSERT(fontHandle);
STORM_ASSERT(text);
return GxuFontGetMaxCharsWithinWidthAndHeight(
TextBlockGetFontPtr(fontHandle),
text,
DDCToNDCHeight(height),
DDCToNDCWidth(maxWidth),
DDCToNDCHeight(maxHeight),
lineBytes,
DDCToNDCWidth(a7),
scale,
DDCToNDCWidth(a9),
ConvertStringFlags(flags)
);
}
CGxString* TextBlockGetStringPtr(HTEXTBLOCK stringHandle) {
STORM_ASSERT(stringHandle);
return reinterpret_cast<TEXTBLOCK*>(stringHandle)->string;
}
void TextBlockGetTextExtent(HTEXTFONT fontHandle, const char* text, uint32_t numChars, float fontHeight, float* extent, float a6, float scale, float a8, uint32_t flags) {
STORM_ASSERT(fontHandle);
STORM_ASSERT(text);
STORM_ASSERT(extent);
*extent = 0.0f;
GxuFontGetTextExtent(
TextBlockGetFontPtr(fontHandle),
text,
numChars,
DDCToNDCHeight(fontHeight),
extent,
DDCToNDCWidth(a6),
scale,
DDCToNDCWidth(a8),
ConvertStringFlags(flags)
);
NDCToDDC(*extent, 0.0f, extent, nullptr);
}
float TextBlockGetWrappedTextHeight(HTEXTFONT fontHandle, const char* text, float a3, float a4, const C2Vector& a5, float a6, float a7, uint32_t flags) {
STORM_ASSERT(fontHandle);
STORM_ASSERT(text);
float shadowWidth;
float shadowHeight;
DDCToNDC(a5.x, a5.y, &shadowWidth, &shadowHeight);
C2Vector shadowSize = { shadowWidth, shadowHeight };
float height = GxuFontGetWrappedTextHeight(
TextBlockGetFontPtr(fontHandle),
text,
DDCToNDCHeight(a3),
DDCToNDCWidth(a4),
shadowSize,
a6,
DDCToNDCHeight(a7),
ConvertStringFlags(flags)
);
return NDCToDDCHeight(height);
}
void TextBlockSetStringPos(HTEXTBLOCK stringHandle, const C3Vector& pos) {
STORM_ASSERT(stringHandle);
C3Vector ndcPos = { 0.0f, 0.0f, pos.z };
DDCToNDC(pos.x, pos.y, &ndcPos.x, &ndcPos.y);
GxuFontSetStringPosition(TextBlockGetStringPtr(stringHandle), ndcPos);
}
void TextBlockUpdateColor(HTEXTBLOCK stringHandle, const CImVector& color) {
STORM_ASSERT(stringHandle);
GxuFontSetStringColor(TextBlockGetStringPtr(stringHandle), color);
}

140
src/gx/Font.hpp Normal file
View file

@ -0,0 +1,140 @@
#ifndef GX_FONT_HPP
#define GX_FONT_HPP
#include "gx/font/FreeType.hpp"
#include "gx/font/Types.hpp"
#include "gx/Types.hpp"
#include <cstdint>
#include <common/Handle.hpp>
#include <storm/Hash.hpp>
#define FONT_OUTLINE 0x1
#define FONT_MONOCHROME 0x2
#define FONT_THICKOUTLINE 0x4
class C2Vector;
class C3Vector;
class CGxFont;
class CGxShader;
class CGxString;
class CGxStringBatch;
class CImVector;
struct GLYPHBITMAPDATA;
class FONTHASHOBJ : public CHandleObject, public TSHashObject<FONTHASHOBJ, HASHKEY_STR> {
public:
CGxFont* font = nullptr;
virtual ~FONTHASHOBJ();
};
class TEXTBLOCK : public CHandleObject {
public:
CGxString* string = nullptr;
virtual ~TEXTBLOCK();
};
extern CGxShader* g_fontPixelShader[1];
extern CGxShader* g_fontVertexShader[2];
extern STORM_LIST(CGxString) g_freeStrings;
extern STORM_LIST(CGxString) g_strings;
void CalculateYOffset(uint32_t, uint32_t, FT_Face, uint32_t, int32_t*, int32_t*);
float GetCharacterWidth(const char*, uint32_t, uint32_t, CGxFont*, float);
float GetIndentNormWidth();
float GetIndentPixelWidth(void);
uint32_t GetScreenPixelHeight(void);
uint32_t GetScreenPixelWidth(void);
QUOTEDCODE GxuDetermineQuotedCode(const char*, int32_t&, CImVector*, uint32_t, uint32_t&);
int32_t GxuFontAddToBatch(CGxStringBatch*, CGxString*);
void GxuFontAddShadow(CGxString* string, const CImVector& color, const C2Vector& offset);
CGxStringBatch* GxuFontCreateBatch(bool, bool);
int32_t GxuFontCreateFont(const char*, float, CGxFont*&, uint32_t);
int32_t GxuFontCreateString(CGxFont*, const char*, float, const C3Vector&, float, float, float, CGxString*&, EGxFontVJusts, EGxFontHJusts, uint32_t, const CImVector&, float, float);
int32_t GxuFontDestroyBatch(CGxStringBatch*);
void GxuFontDestroyFont(CGxFont*& font);
void GxuFontDestroyString(CGxString*&);
uint32_t GxuFontGetFontFlags(CGxFont*);
const char* GxuFontGetFontName(CGxFont*);
uint32_t GxuFontGetMaxCharsWithinWidth(CGxFont*, const char*, float, float, uint32_t, float*, float, float, float, uint32_t);
uint32_t GxuFontGetMaxCharsWithinWidthAndHeight(CGxFont*, const char*, float, float, float, uint32_t, float, float, float, uint32_t);
float GxuFontGetOneToOneHeight(CGxFont*);
void GxuFontGetTextExtent(CGxFont*, const char*, uint32_t, float, float*, float, float, float, uint32_t);
float GxuFontGetWrappedTextHeight(CGxFont*, const char*, float, float, const C2Vector&, float, float, uint32_t);
void GxuFontInitialize(void);
void GxuFontRenderBatch(CGxStringBatch*);
int32_t GxuFontSetStringColor(CGxString*, const CImVector&);
void GxuFontSetStringPosition(CGxString* string, const C3Vector& position);
void GxuFontUpdate();
void GxuFontWindowSizeChanged(void);
int32_t IGxuFontGlyphRenderGlyph(FT_Face, uint32_t, uint32_t, uint32_t, GLYPHBITMAPDATA*, int32_t, uint32_t);
void TextBlockAddShadow(HTEXTBLOCK, CImVector, const C2Vector&);
HTEXTBLOCK TextBlockCreate(HTEXTFONT, const char*, const CImVector&, const C3Vector&, float, float, float, uint32_t, float, float, float);
HTEXTFONT TextBlockGenerateFont(const char*, uint32_t, float);
uint32_t TextBlockGetFontFlags(HTEXTFONT);
const char* TextBlockGetFontName(HTEXTFONT);
CGxFont* TextBlockGetFontPtr(HTEXTFONT);
uint32_t TextBlockGetMaxCharsWithinWidth(HTEXTFONT, const char*, float, float, uint32_t, float*, float, float, float, uint32_t);
uint32_t TextBlockGetMaxCharsWithinWidthAndHeight(HTEXTFONT, const char*, float, float, float, uint32_t, float, float, float, uint32_t);
CGxString* TextBlockGetStringPtr(HTEXTBLOCK);
void TextBlockGetTextExtent(HTEXTFONT, const char*, uint32_t, float, float*, float, float, float, uint32_t);
float TextBlockGetWrappedTextHeight(HTEXTFONT, const char*, float, float, const C2Vector&, float, float, uint32_t);
void TextBlockSetStringPos(HTEXTBLOCK stringHandle, const C3Vector& pos);
void TextBlockUpdateColor(HTEXTBLOCK, const CImVector&);
float PixelToScreenHeight(int32_t);
float PixelToScreenWidth(int32_t);
float PixelToScreenWidth(float);
float ScreenToPixelHeight(int32_t, float);
float ScreenToPixelWidth(int32_t, float);
float Sub6C2280(FT_Face, float);
#endif

200
src/gx/FontInternal.cpp Normal file
View file

@ -0,0 +1,200 @@
#include "gx/FontInternal.hpp"
#include "gx/Font.hpp"
#include "gx/font/CGxFont.hpp"
#include <cmath>
#include <storm/Error.hpp>
#include <tempest/Math.hpp>
uint32_t InternalGetMaxCharsWithinWidth(CGxFont* face, const char* text, float height, float maxWidth, uint32_t lineBytes, float* extent, uint32_t flags, float a8, float scale, uint32_t* bytesInString, float* widthArray, float* widthArrayGuard) {
STORM_ASSERT(face);
STORM_ASSERT(text);
STORM_ASSERT(extent);
uint32_t numChars = 0;
int32_t billboarded = (flags & 0x80) != 0;
if (!billboarded && (height == 0.0f || flags & 0x4)) {
height = GxuFontGetOneToOneHeight(face);
}
float width = 0.0f;
if (a8 > 0.0f) {
width += ceil(ScreenToPixelWidth(0, a8));
}
if (face->m_flags & 0x8) {
width += 4.0f;
} else if (face->m_flags & 0x1) {
width += 2.0f;
}
float pixelSize = face->GetPixelSize();
float pixelHeight = ScreenToPixelHeight(billboarded, height);
float pixelScale = pixelHeight / pixelSize;
float pixelMaxWidth = CMath::fuint_pi((pixelSize * GetScreenPixelWidth() * maxWidth) / std::max(pixelHeight, 1.0f));
const char* originalText = text;
float lastWidth = 0.0f;
int32_t advance;
uint32_t code;
uint32_t prevCode = 0;
while (*text && lineBytes) {
QUOTEDCODE quotedCode = GxuDetermineQuotedCode(text, advance, nullptr, flags, code);
text += advance;
lineBytes -= advance;
switch (quotedCode) {
case CODE_COLORON:
case CODE_COLORRESTORE:
case CODE_HYPERLINKSTART:
case CODE_HYPERLINKSTOP:
case CODE_TEXTURESTOP:
break;
case CODE_NEWLINE: {
goto DONE;
}
case CODE_TEXTURESTART: {
// TODO
}
default: {
if (face->NewCodeDesc(code)) {
float stepWidth = 0.0f;
if (prevCode) {
stepWidth = flags & 0x10
? face->ComputeStepFixedWidth(prevCode, code)
: face->ComputeStep(prevCode, code);
}
float characterWidth = GetCharacterWidth(text, flags, code, face, height);
if (pixelMaxWidth < width + stepWidth + characterWidth) {
text -= advance;
goto DONE;
}
width += stepWidth;
numChars++;
prevCode = code;
lastWidth = characterWidth;
if (widthArray) {
float v34 = (lastWidth + width) * pixelScale;
if (billboarded) {
*widthArray = v34;
} else {
*widthArray = v34 / GetScreenPixelWidth();
}
widthArray++;
}
} else {
numChars++;
}
}
}
}
DONE:
float v26 = (lastWidth + width) * pixelScale;
if (billboarded) {
*extent = v26;
} else {
*extent = v26 / GetScreenPixelWidth();
}
if (bytesInString) {
*bytesInString = text - originalText;
}
return numChars;
}
void InternalGetTextExtent(CGxFont* font, const char* text, uint32_t numBytes, float height, float* extent, uint32_t flags, float a7, float a8) {
STORM_ASSERT(font);
STORM_ASSERT(text);
STORM_ASSERT(extent);
int32_t billboarded = (flags & 0x80) != 0;
if (height == 0.0f || flags & 0x4) {
height = GxuFontGetOneToOneHeight(font);
}
float width = 0.0f;
float lastWidth = 0.0f;
float maxWidth = 0.0f;
if (a7 > 0.0f) {
width = ceil(ScreenToPixelWidth(0, a7));
}
if (font->m_flags & 0x8) {
width += 4.0f;
} else if (font->m_flags & 0x1) {
width += 2.0f;
}
uint32_t prevCode = 0;
while (numBytes && *text) {
int32_t advance;
uint32_t code;
CImVector quotedColor;
QUOTEDCODE quotedCode = GxuDetermineQuotedCode(text, advance, nullptr, flags, code);
numBytes -= advance;
text += advance;
if (
quotedCode == CODE_COLORON
|| quotedCode == CODE_COLORRESTORE
|| quotedCode == CODE_HYPERLINKSTART
|| quotedCode == CODE_HYPERLINKSTOP
|| quotedCode == CODE_TEXTURESTOP
) {
continue;
}
if (quotedCode == CODE_NEWLINE || code == '\n') {
maxWidth = std::max(maxWidth, lastWidth + width);
lastWidth = 0.0f;
width = 0.0f;
} else if (quotedCode == CODE_TEXTURESTART) {
// TODO
} else if (font->NewCodeDesc(code)) {
float stepWidth = 0.0f;
if (prevCode) {
stepWidth = flags & 0x10
? font->ComputeStepFixedWidth(prevCode, code)
: font->ComputeStep(prevCode, code);
}
lastWidth = GetCharacterWidth(text, flags, code, font, height);
width += stepWidth;
prevCode = code;
}
}
float pixelSize = font->GetPixelSize();
float pixelHeight = ScreenToPixelHeight(billboarded, height);
float pixelScale = pixelHeight / pixelSize;
maxWidth = std::max(maxWidth, lastWidth + width);
maxWidth *= pixelScale;
*extent = billboarded ? maxWidth : PixelToScreenWidth(maxWidth);
}

12
src/gx/FontInternal.hpp Normal file
View file

@ -0,0 +1,12 @@
#ifndef GX_FONT_INTERNAL_HPP
#define GX_FONT_INTERNAL_HPP
#include <cstdint>
class CGxFont;
uint32_t InternalGetMaxCharsWithinWidth(CGxFont*, const char*, float, float, uint32_t, float*, uint32_t, float, float, uint32_t*, float*, float*);
void InternalGetTextExtent(CGxFont*, const char*, uint32_t, float, float*, uint32_t, float, float);
#endif

Some files were not shown because too many files have changed in this diff Show more