181 Commits

Author SHA1 Message Date
rtw1x1
d5c659d404 Reverted horse rotation speed 2026-01-05 15:29:02 +00:00
rtw1x1
625849e0e4 Merge pull request #70 from savisxss/main 2026-01-04 19:51:40 +00:00
savis
074a05bb9b Optimize terrain 2026-01-04 19:44:59 +01:00
rtw1x1
b4171084c3 Merge pull request #68 from savisxss/main
Add parallel race/motion loading and thread-safe Pack/Pool managers
2026-01-04 16:30:19 +00:00
savis
d5624a8cdd Add parallel race/motion loading and thread-safe Pack/Pool managers 2026-01-04 17:27:32 +01:00
rtw1x1
fa96b25dad Merge pull request #46 from rfdomingues98/fix/client-freeze-on-drag
Added Amun fix for window freeze on drag
2026-01-04 11:10:38 +00:00
rtw1x1
9b57cd1414 Merge branch 'main' into fix/client-freeze-on-drag 2026-01-04 11:10:28 +00:00
rtw1x1
54b6f8c4a9 Merge pull request #67 from savisxss/main
eliminate freeze when encountering players by preloading race motions
2026-01-04 09:43:36 +00:00
savis
2550008f6d eliminate freeze when encountering players by preloading race motions 2026-01-04 10:41:48 +01:00
rtw1x1
4c21fe697c Merge pull request #66 from rfdomingues98/feat/add-bravery-cape-effect
Added new effect for Bravery Cape
2026-01-04 09:29:14 +00:00
rtw1x1
3d8a8f8e3b Merge pull request #65 from savisxss/main
A bit late, but Happy New Year!
2026-01-04 09:29:02 +00:00
rtw1x1
3b359393d1 Merge pull request #63 from MindRapist/mr-7
MR-7
2026-01-04 09:28:48 +00:00
Ricardo Domingues
117f1234b5 Added new effect for Bravery Cape 2026-01-03 20:47:56 +00:00
savis
6fcf2c58e2 Parallelize pack file initialization
- Load pack files across multiple threads
- Scales to CPU core count
- Load root.pck first, then parallelize remaining packs
- Track and report failed pack loads
2026-01-03 20:38:21 +01:00
savis
de0b8052fe Batch terrain texture loading
- Pre-request all textures for async loading
- Reduces sequential blocking during terrain load
2026-01-03 20:38:10 +01:00
savis
6984fef736 Integrate async loading infrastructure
- Initialize FileLoaderThreadPool and TextureCache
- Route file requests through thread pool
- Handle pre-decoded images from worker threads
- Reduce loading delay from 20ms to 1ms
- 512MB texture cache (up from 256MB)
2026-01-03 20:38:02 +01:00
savis
f702b4953d Add support for pre-decoded image loading
- OnLoadFromDecodedData method for async decoded images
- Bypasses redundant decoding when data comes from worker thread
- Integrates with FileLoaderThreadPool pipeline
2026-01-03 20:37:52 +01:00
savis
3f0f3c792d Add SIMD-optimized texture color conversion
- SSE2/SSSE3 RGBA to BGRA conversion (10x faster)
- Processes 4 pixels per iteration
- Automatic fallback for non-x86 platforms
- Applied to both STB and decoded image paths
2026-01-03 20:37:41 +01:00
savis
e55fc4db17 Optimize pack file loading
- Add thread-local ZSTD decompression context reuse
- Integrate BufferPool for temporary buffers
- PackManager auto-uses BufferPool for all GetFile calls
- Thread-safe pack loading with mutex
2026-01-03 20:37:32 +01:00
savis
0958ea6214 Add multi-threaded file loader pool
- 4-16 worker threads based on CPU core count
- Auto-detects and decodes images on worker threads
- SPSC queues: 16K request, 32K completion
- Atomic task counter for fast idle checks
- Smart idle handling with yield and minimal sleep
2026-01-03 20:37:22 +01:00
savis
049eca38a4 Add LRU texture cache
- 512MB default cache size for decoded textures
- Thread-safe LRU eviction policy
- Tracks hit/miss statistics
- Prevents re-decoding frequently used textures
2026-01-03 20:37:08 +01:00
savis
fd1218bd4e Add worker-thread image decoder
- Decodes DDS, PNG, JPG, TGA, BMP formats
- Thread-safe for use in worker threads
- Uses stb_image for common formats
- Custom DDS header parsing
2026-01-03 20:36:37 +01:00
savis
c6aa6b4149 Add decoded image data structure
- Stores decoded pixel data ready for GPU upload
- Supports RGBA8, RGB8, and DDS formats
- Separates CPU decoding from GPU upload phases
2026-01-03 20:35:45 +01:00
savis
7fb832ad6b Add buffer pool for I/O operations
- Reuses vector<uint8_t> buffers to reduce allocations
- Thread-safe with mutex protection
- Max 64 buffers, 64MB buffer size limit
- Tracks allocation statistics and pooled memory
2026-01-03 20:35:06 +01:00
savis
33ac4b69f4 Add lock-free SPSC queue implementation
- Single producer/single consumer bounded queue
- Cache-line aligned atomics to prevent false sharing
- Used for async file loading communication
2026-01-03 20:34:47 +01:00
rtw1x1
6d0fe59d50 Merge pull request #64 from savisxss/main 2026-01-02 14:25:06 +00:00
savis
5fce64f978 Fix minimap radius calculations and atlas waypoint positioning 2026-01-02 06:56:12 +01:00
savis
2372599578 Fix quest marker alignment on minimap 2026-01-02 06:28:49 +01:00
Mind Rapist
efbdf9155e Minor fixes & corrections 2026-01-02 06:33:57 +02:00
rtw1x1
9f6348ad8c Merge pull request #61 from rtw1x1/main
fix: BiDi logic & broken cursor & auto-detect LTR/RTL input
2025-12-31 21:08:00 +00:00
rtw1x1
85763c9f81 fix: Auto-detect LTR / RTL in input 2025-12-31 20:56:02 +00:00
rtw1x1
73958b4f62 fix: Broken cursor and tag logic from BiDi 2025-12-31 20:23:40 +00:00
rtw1x1
acc83c9aab Merge pull request #60 from rtw1x1/main
fix: CheckMeshIndex bounds check to use actual mesh count
2025-12-31 10:12:44 +00:00
rtw1x1
541519d702 Merge branch 'main' of https://github.com/rtw1x1/m2dev-client-src 2025-12-31 10:10:28 +00:00
rtw1x1
846fab02dc fix: CheckMeshIndex bounds check to use actual mesh count 2025-12-31 10:10:11 +00:00
rtw1x1
b364d4a39a Merge pull request #59 from rtw1x1/main
Revert "Stop crashing on bad meshes like it's the end of the world"
2025-12-31 09:58:30 +00:00
rtw1x1
999a0929a6 Revert "Stop crashing on bad meshes like it's the end of the world"
This reverts commit b201fd6dd6.
2025-12-31 09:58:06 +00:00
rtw1x1
fb4ba5960e Merge pull request #56 from MindRapist/mr-6
PK Mode fix
2025-12-31 09:09:56 +00:00
rtw1x1
7c835fb461 Merge pull request #58 from rtw1x1/main
fix: BiDi and bad meshes crash
2025-12-31 09:07:44 +00:00
rtw1x1
b201fd6dd6 Stop crashing on bad meshes like it's the end of the world
Pushing this on behalf of savis
2025-12-31 09:05:58 +00:00
Mind Rapist
54a5dde037 PK Mode fix 2025-12-31 04:14:02 +02:00
rtw1x1
e7a113885a fix: Better BiDi logic for formatting 2025-12-30 22:20:04 +00:00
Ricardo Domingues
e881517775 Merge branch 'main' into fix/client-freeze-on-drag 2025-12-30 17:51:50 +00:00
Ricardo Domingues
96876420d1 Increased horse rotation speed 2025-12-30 17:37:42 +00:00
rtw1x1
18073e7193 Merge pull request #53 from MindRapist/mr-5
MR-5: FlyTarget fixes
2025-12-29 16:47:27 +00:00
Mind Rapist
08228b1ff9 MR-5: FlyTarget fixes 2025-12-29 18:37:39 +02:00
rtw1x1
d82f72ed41 Merge pull request #52 from savisxss/main 2025-12-29 06:09:16 +00:00
Mind Rapist
55b2d70459 MR-5: FlyTarget fixes 2025-12-29 00:21:32 +02:00
savis
fff15def3c Fix PONG sequence sent as separate packet causing mismatch 2025-12-28 17:17:47 +01:00
rtw1x1
387d7bf72d Merge pull request #51 from rtw1x1/main
fix: Better support UTF8 & Arabic
2025-12-27 18:54:17 +00:00
rtw1x1
a4112cd128 fix: Better support UTF8 & Arabic 2025-12-27 18:50:42 +00:00
rtw1x1
67bda2c286 Merge pull request #49 from savisxss/Garvage
perf: optimize terrain garbage collector with early exit
2025-12-27 08:14:54 +00:00
rtw1x1
abefd13f68 Merge pull request #50 from MindRapist/mr-4
Fixed PK mode bugs
2025-12-27 08:14:41 +00:00
Mind Rapist
2422af51a8 Fixed PK mode bugs 2025-12-27 10:12:27 +02:00
savis
977e273764 perf: optimize terrain garbage collector with early exit 2025-12-27 08:31:54 +01:00
rtw1x1
5179261a47 Merge pull request #48 from rtw1x1/main
Full unicode support ft. RTL & BiDi
2025-12-27 07:14:55 +00:00
rtw1x1
308511bd22 Fix hyperlink tags in Arabic 2025-12-27 07:09:57 +00:00
Ricardo Domingues
46f2c9de0f Updated README 2025-12-26 19:18:41 +00:00
Ricardo Domingues
2a8d881ef3 Added Amun fix for window freeze on drag 2025-12-26 19:13:40 +00:00
rtw1x1
d3017b0ab0 Macro removal 2025-12-26 16:09:30 +00:00
rtw1x1
5d73d79eb8 Full unicode hotfix Debug mode 2025-12-26 16:02:34 +00:00
rtw1x1
4729dafc12 Full Unicode patch with RTL Support & BiDi logic #3 2025-12-26 14:53:52 +00:00
rtw1x1
a955c50744 Full Unicode patch with RTL Support & BiDi logic.
This commit is well documented, so no need to tell you my life story.

Full Unicode patch with RTL Support & BiDi logic.

Removed the legacy codePage, normalised to UTF8 (65001).

It also comes with:

CTRL + A : select text (highlighted)
CTRL + C : copy
CTRL + V : paste
CTRL + X : cut
CTRL + Y : redo
CTRL + Z : undo
2025-12-26 12:32:43 +00:00
rtw1x1
d37607baa1 Merge pull request #45 from savisxss/opti2 2025-12-26 07:05:06 +00:00
rtw1x1
b56f55ce7c Merge pull request #43 from savisxss/socket 2025-12-26 07:04:52 +00:00
rtw1x1
e578f05986 Merge pull request #42 from SunTrustDev/bugfix/std-1 2025-12-26 07:04:38 +00:00
rtw1x1
0208398731 Merge pull request #41 from savisxss/main 2025-12-26 07:04:27 +00:00
savis
9ac8e3e4d7 Optimize collision detection loops and distance calculations 2025-12-26 06:36:22 +01:00
savis
9907febf28 enable async loading, optimize rendering and distance checks 2025-12-26 06:21:13 +01:00
savis
f9e1f8b7af increase socket buffers 2025-12-26 06:19:50 +01:00
savis
25601d4b28 Enable TCP_NODELAY to reduce network latency 2025-12-26 04:55:23 +01:00
Simone Romano
4b6cdc8003 Fix: Add quest dialog cancelation packet handling 2025-12-25 21:59:50 +01:00
savis
b25de40e07 Add missing intrin.h include for __cpuid 2025-12-25 20:37:02 +01:00
rtw1x1
1592ec93f6 Merge pull request #40 from MindRapist/mr-3
MR-3: Bunch of fixes
2025-12-25 16:00:54 +00:00
Mind Rapist
99bd5103a3 MR-3: Bunch of fixes 2025-12-25 17:51:09 +02:00
Mind Rapist
ef7c946cfb MR-3: Bunch of fixes 2025-12-25 08:39:58 +02:00
d1str4ught
76b0dc793d FIX_POS_SYNC removed 2025-12-25 03:26:57 +01:00
d1str4ught
45fdb49d63 Merge pull request #39 from MindRapist/mr-2
MR-2: Macro leftovers removed
2025-12-25 02:50:56 +01:00
Mind Rapist
b344e5505e MR-2: Macro leftovers removed 2025-12-20 15:55:39 +02:00
d1str4ught
8df71d0bb2 Merge pull request #38 from MindRapist/mr-2
MR-2
2025-12-20 01:31:56 +01:00
Mind Rapist
7580e4278c MR-2: Realtime character level updates + Macros removed 2025-12-20 02:28:41 +02:00
Mind Rapist
e0df09ea28 MR-2: Realtime character level updates + Macros removed 2025-12-20 01:58:56 +02:00
d1str4ught
2799b72d6d Merge pull request #37 from MindRapist/mr-2
MR-2
2025-12-20 00:23:59 +01:00
d1str4ught
0ecfea8e1e Merge pull request #36 from MindRapist/mrmj-1
MRMJ-1: Messenger & Skills fixes
2025-12-20 00:22:39 +01:00
Mind Rapist
06c8e6f9b0 MR-2: Realtime character level updates 2025-12-19 22:15:38 +02:00
Mind Rapist
e3ae5541ba MRMJ-1: Messenger & Skills fixes 2025-12-14 06:39:06 +02:00
Mind Rapist
08ed73b29c MRMJ-1: Messenger & Skills fixes 2025-12-14 05:26:24 +02:00
Mind Rapist
a29e43224a MRMJ-1: Messenger & Skills fixes 2025-12-14 05:23:58 +02:00
Mind Rapist
7b08687023 MRMJ-1: Messenger & Skills fixes 2025-12-14 05:12:39 +02:00
d1str4ught
c0548bc98e fix for packer 2025-12-11 17:42:59 +01:00
d1str4ught
436db01a80 Merge pull request #33 from nbsnl/fix/fullscreen-wasapi-crash
Fix fullscreen startup crash caused by WASAPI audio initialization
2025-11-21 22:44:56 +01:00
d1str4ught
1b693488ba Merge pull request #31 from MindRapist/fix/locale-texture-loading-errors
Locale selection for RelWithDebInfo fix and dragon_rock/mobs textures
2025-11-21 22:43:37 +01:00
nbsnl
6227fed5be Fix fullscreen startup crash caused by WASAPI audio initialization
The client was crashing during fullscreen initialization due to a NULL 
IMMDeviceEnumerator pointer inside miniaudio’s WASAPI backend.

Crash location:
ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint
(inlined in ma_device_init_internal__wasapi)

Disassembly showed a null vtable dereference:
call qword ptr [rax+20h]

On some systems, WASAPI fails to create or retrieve the default audio endpoint
(especially in VMs, RDP sessions, missing/disabled audio devices, or timing
issues during fullscreen initialization). This results in a NULL COM pointer 
being used, causing a 0xC0000005 access violation before the game window fully 
appears.

Solution:
WASAPI backend has been disabled and the client now falls back to the more stable 
DirectSound/WinMM audio backends.

Applied definitions:
#define MA_NO_WASAPI
#define MA_ENABLE_DSOUND
#define MA_ENABLE_WINMM

Results:
✔ Fullscreen crash completely resolved
✔ Audio still works through DirectSound
✔ Improved stability across fullscreen/windowed modes
✔ No functional drawbacks observed
2025-11-15 23:48:28 +03:00
Mind Rapist
d5c8f05457 Update README.md 2025-11-15 16:23:18 +02:00
Mind Rapist
a49dec1c87 fix: Locale selection for RelWithDebInfo and dragon_rock/mobs textures 2025-11-14 18:42:07 +02:00
d1str4ught
2eee9aead2 Merge pull request #26 from rtw1x1/main
QoL Equipment slots
2025-11-13 18:54:08 +01:00
d1str4ught
6ea69eb2d5 Merge pull request #28 from savisxss/main
removed matrix
2025-11-13 18:53:39 +01:00
savis
0b60aac3e8 removed matrix 2025-10-13 19:18:16 +02:00
d1str4ught
c461023c4b Merge pull request #27 from amun3808/new-audio-system
Audio Engine volume bug & small update
2025-10-10 15:08:34 +02:00
Amun
7caf9639e0 Audio engine: small bug(see desc)
The music wouldn't play if the sound was 0 and you changed the song because it would be stopped by the fade during the next frame.
2025-10-08 21:34:43 +03:00
Amun
01f4417d80 Audio Engine volume bug & small update
Fixed a bug where the volume change would be ignored if the sound was fading
Added SoundEngine::GetMusicVolume
Removed volume factor
Removed unused SetListenerVelocity
2025-10-05 22:08:37 +03:00
d1str4ught
de6817c338 guild packets same size 2025-09-30 11:27:10 +02:00
rtw1x1
a808d1d102 Syncronise Wear/Wearable client - server. 2025-09-29 07:36:29 +01:00
rtw1x1
7c86b64dc3 Let CItemData handle equipment slot instead of keeping track of indexes every time. 2025-09-28 20:23:22 +01:00
d1str4ught
ab0ee95a19 Merge pull request #24 from heroesf/main
removed cpostit, unused files, small fix warning
2025-09-26 00:03:08 +02:00
heroesf
133ac6fc41 removed cpostit, unused files, small fix warning 2025-09-25 12:45:14 +02:00
d1str4ught
7f42fc2c3f Merge pull request #23 from mq1n/main
fix build error in latest VS
2025-09-24 03:02:15 +02:00
d1str4ught
c0ea439b6d Merge pull request #21 from ThorsDev/features/scissor-rect
Added scissor rect for UI
2025-09-24 03:01:04 +02:00
mq1n
4894b0db9d fix build error in latest VS
https://i.imgur.com/ymbN7Vm.png
2025-09-23 18:19:31 +03:00
d1str4ught
892eb8acd1 Merge pull request #20 from mq1n/main
fix MSAA and backbuffer format handling in device creation
2025-09-22 20:30:21 +02:00
ThorsDev
c5feaaf2d9 scissor rect 2025-09-22 17:48:21 +02:00
mq1n
255212e906 fix MSAA and backbuffer format handling in device creation 2025-09-22 17:59:54 +03:00
d1str4ught
f7e9bc41e6 Update README.md 2025-09-22 15:09:49 +02:00
d1str4ught
252f06bd0c Merge pull request #19 from mq1n/main
crash fixes, ASan support and setup GitHub actions workflow
2025-09-22 14:57:09 +02:00
d1str4ught
f0af67cf96 Merge pull request #18 from ThorsDev/fixes/packer-locale
locale fix
2025-09-22 14:54:34 +02:00
mq1n
082d8fb3a6 GitHub actions workflow added 2025-09-22 12:32:03 +03:00
mq1n
acaaf6fc91 ASan support added 2025-09-22 11:27:05 +03:00
mq1n
51ee5feb78 fixed some crashes 2025-09-22 11:25:58 +03:00
ThorsDev
ef97bbc54b locale fix 2025-09-22 05:55:39 +02:00
d1str4ught
bdcb68619a guild mark uploading fixed 2025-09-22 02:44:22 +02:00
d1str4ught
81c61692f1 LoadImageFromFile for CImageBox 2025-09-22 01:43:01 +02:00
d1str4ught
cc98bdb2da gitignore fixed 2025-09-22 01:17:13 +02:00
d1str4ught
b4637e4782 client sources moved to C++20 2025-09-22 00:45:08 +02:00
d1str4ught
5b1d3c6bce new pack system 2025-09-21 05:28:55 +02:00
d1str4ught
775cb2f927 some missing stuff 2025-09-21 01:32:59 +02:00
d1str4ught
7509eeb93b encryption for .py files in PackMaker 2025-09-21 01:24:05 +02:00
d1str4ught
3b1d0fd10a custom PackMaker 2025-09-21 01:09:06 +02:00
d1str4ught
2bd4072ad8 Merge pull request #17 from mq1n/main
migrate to DirectX 9Ex from DirectX 9
2025-09-20 22:16:04 +02:00
mq1n
fb7e53b909 migrate to DirectX 9Ex from DirectX 9 2025-09-19 16:12:33 +03:00
d1str4ught
df346e156b Merge pull request #16 from mq1n/main
fix cipher desync issue
2025-09-08 15:20:56 +02:00
mq1n
eaecf67d33 fix cipher desync issue
update the handshake phase to call the new method after activating the cipher, ensuring buffered data (likely from a second login attempt, GC_PHASE) is properly decrypted, and fix a logging format issue.
2025-09-07 20:24:38 +03:00
d1str4ught
397e2b1890 Merge pull request #15 from mq1n/main
enabled detailed packet logs for easier debugging
2025-09-06 18:04:08 +02:00
mq1n
b3aba3d280 enabled detailed packet logs for easier debugging 2025-09-02 19:40:05 +03:00
d1str4ught
dcf45e3a6e last packet log for not enough packet size error log 2025-09-02 14:53:38 +02:00
d1str4ught
e1eb805f8a Merge pull request #13 from savisxss/main
removed unused code
2025-09-02 12:07:34 +02:00
d1str4ught
cfae08b973 Merge pull request #12 from sndth/fix-audio-casting-warnings
Fix potential casting warnings inside AudioLib
2025-09-02 12:07:03 +02:00
d1str4ught
b24a3ab17d Merge pull request #9 from sndth/fix-audio-pointer-dangling-2
Fix issue with dangling playSoundInstance pointer
2025-09-02 12:06:45 +02:00
d1str4ught
99138293ed Merge pull request #8 from amun3808/new-audio-system
Sound engine update
2025-09-02 12:06:29 +02:00
savis
252df67871 removed passpod 2025-09-01 21:36:42 +02:00
Amun
1432d4c8ea Removed playSoundInstance->Stop
A new instance is acquired whenever a new sound is played in the area. The previous instance might be acquired by another part of the game, stopping it was a mistake on my side.
2025-09-01 18:36:22 +03:00
sndth
99f04c27d4 Fix potential casting warnings inside AudioLib 2025-09-01 17:28:25 +02:00
sndth
64ed7f2bd5 Fix issue with dangling playSoundInstance pointer 2025-09-01 17:15:18 +02:00
Amun
f6c9422048 Sound engine update 2025-09-01 14:46:23 +03:00
d1str4ught
8c349d4a0f quest image ptr fixed 2025-08-29 00:15:32 +02:00
d1str4ught
d690de0b5a auction removed 2025-08-28 22:52:08 +02:00
d1str4ught
85920e442d item_set and item_del packets normalized to server 2025-08-28 22:41:41 +02:00
d1str4ught
6b97701f0e dirline render states fixed 2025-08-28 21:24:02 +02:00
d1str4ught
f0ce190550 flytrace restorevertexshader fixed 2025-08-28 21:20:49 +02:00
d1str4ught
f791ab6d8c world editor defines removed 2025-08-28 21:03:15 +02:00
d1str4ught
b66e045d80 particle rendering: render all visible particles 2025-08-28 20:52:54 +02:00
d1str4ught
a418f8616d include paths normalized 2025-08-28 20:50:20 +02:00
d1str4ught
f19cb2f118 openid python constants removed 2025-08-28 20:15:58 +02:00
d1str4ught
3c8a5750f5 openid removed 2025-08-28 20:13:47 +02:00
d1str4ught
7651d8cf65 some more unused defines removed 2025-08-28 20:02:30 +02:00
d1str4ught
a83fc7e642 check latest files removed 2025-08-28 19:59:25 +02:00
d1str4ught
06d9a3671d nprotect gameguard removed 2025-08-28 19:56:39 +02:00
d1str4ught
d4a1591a50 hackshield and xtrap codes removed 2025-08-28 19:54:23 +02:00
d1str4ught
b9783bec79 Merge pull request #6 from mq1n/mem-leak-fix
fix some memory leaks
2025-08-28 18:41:51 +02:00
d1str4ught
cb0c5d8fc9 Merge pull request #5 from mq1n/main
fix camera glitch issue
2025-08-28 18:38:54 +02:00
d1str4ught
6315ca3639 adding error log back when dynamic packet size is not enough 2025-08-28 00:01:27 +02:00
mq1n
e5bd21ff75 fix some memory leaks 2025-08-27 23:37:19 +03:00
d1str4ught
6582927612 LinearInterpolation and HermiteInterpolation added to Utils.h 2025-08-27 22:30:57 +02:00
mq1n
e4a321698e fix camera glitch issue 2025-08-27 23:30:28 +03:00
d1str4ught
6459c9fa03 Merge pull request #4 from amun3808/new-audio-system
New sound system & removed miles
2025-08-27 21:41:38 +02:00
Amun
71e906b8f2 New sound system & removed miles 2025-08-27 21:55:11 +03:00
d1str4ught
eedc2a0748 sequence table removed -> deterministic random for sequence generation
to change the seed search for SEQUENCE_SEED
2025-08-27 16:56:22 +02:00
d1str4ught
685cc02fc7 image loading reworked 2025-08-27 16:23:19 +02:00
d1str4ught
a479d5a57b log files moved under log folder 2025-08-27 14:36:08 +02:00
d1str4ught
5aad7c88f5 PyTuple_GetPointer fixed 2025-08-27 14:35:56 +02:00
d1str4ught
f7e0248edd Merge pull request #2 from amun3808/main
More pyvalue pointers
2025-08-27 13:43:22 +02:00
Amun
d3991c0775 Small mem leak 2025-08-27 14:34:57 +03:00
Amun
f33d8fc183 More pyvalue pointers 2025-08-27 14:32:26 +03:00
d1str4ught
4385a2c709 PyTuple_GetPointer introduced 2025-08-27 13:22:41 +02:00
d1str4ught
4e6a7f1b08 some ptr type conversions fixed 2025-08-27 12:56:02 +02:00
d1str4ught
67cabc3c89 removed all defines which are defined in the CMakeLists.txt 2025-08-27 12:48:33 +02:00
d1str4ught
f6ac84f91f Merge pull request #1 from mq1n/main
Fix some build problems
2025-08-27 12:39:28 +02:00
d1str4ught
58b1def270 libs moved to normal repo from LFS 2025-08-27 12:29:59 +02:00
d1str4ught
15053eb86b lib files moved from LFS to normal repo 2025-08-27 12:29:24 +02:00
d1str4ught
fb7eba799e new mesh deformer using SSE2 instructions 2025-08-26 04:40:28 +02:00
mq1n
3090b79139 Fix WIN32_LEAN_AND_MEAN warning spam
Added a check before defining WIN32_LEAN_AND_MEAN to prevent redefinition warnings or errors
2025-08-23 09:29:38 +03:00
mq1n
e172d6cff6 Update CMake minimum required version to 3.10
Raised the minimum required CMake version to 3.10 in cryptopp and zlib CMakeLists.txt files to ensure compatibility with newer CMake features and improve build consistency
2025-08-23 09:28:17 +03:00
1123 changed files with 293028 additions and 47538 deletions

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
*.lib filter=lfs diff=lfs merge=lfs -text

35
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: build
on:
push:
branches:
- main
jobs:
win:
name: "Windows Build"
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Build project
id: build_project
shell: pwsh
working-directory: ${{ github.workspace }}
run: |
mkdir build
cd build
cmake ..
cmake --build . --config RelWithDebInfo
- name: Collect outputs
run: |
mkdir _output
cp build/bin/* _output
- name: Upload
uses: actions/upload-artifact@v4
with:
name: output_win
path: _output

64
.gitignore vendored
View File

@@ -1 +1,63 @@
build
/build/
# =======================================================
# FULLY CASE-INSENSITIVE BACKUP EXCLUSIONS
# Matches all files and folders ending in:
# _BK, _BAK, .BK, .BAK (and all case permutations)
# =======================================================
# -------------------------------------------------------
# 1. EXCLUSIONS ENDING IN .BK / _BK
# -------------------------------------------------------
# Files/Folders ending in _BK (e.g., File_Bk, Folder_bK)
*_BK
*_Bk
*_bK
*_bk
# Files ending in .BK (e.g., File.BK, File.bK)
*.BK
*.Bk
*.bK
*.bk
# Files ending in "double extension" .X.BK (e.g., File.txt.Bk)
*.*.BK
*.*.Bk
*.*.bK
*.*.bk
# -------------------------------------------------------
# 2. EXCLUSIONS ENDING IN .BAK / _BAK
# -------------------------------------------------------
# Files/Folders ending in _BAK (e.g., File_BAK, Folder_bak)
*_BAK
*_BAk
*_BaK
*_Bak
*_bAK
*_bAk
*_baK
*_bak
# Files ending in .BAK (e.g., File.BAK, File.bak)
*.BAK
*.BAk
*.BaK
*.Bak
*.bAK
*.bAk
*.baK
*.bak
# Files ending in "double extension" .X.BAK (e.g., File.txt.Bak)
*.*.BAK
*.*.BAk
*.*.BaK
*.*.Bak
*.*.bAK
*.*.bAk
*.*.baK
*.*.bak

View File

@@ -2,9 +2,12 @@
project(m2dev-client-src)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# ASan support
option(ENABLE_ASAN "Enable AddressSanitizer" OFF)
set(CMAKE_MODULE_PATH
${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/buildtool"
@@ -23,11 +26,28 @@ set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
add_compile_options(/MP)
if(MSVC)
add_compile_definitions(UNICODE _UNICODE)
endif()
add_compile_options(
$<$<CXX_COMPILER_ID:MSVC>:/wd4828>
$<$<CXX_COMPILER_ID:MSVC>:/wd4996>
)
# ASan flags
if(ENABLE_ASAN)
if(MSVC)
add_compile_options(/fsanitize=address)
add_link_options(/fsanitize=address)
add_definitions(-D_DISABLE_VECTOR_ANNOTATION)
add_definitions(-D_DISABLE_STRING_ANNOTATION)
else()
add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
add_link_options(-fsanitize=address)
endif()
endif()
add_definitions(-DNOMINMAX)
add_definitions(-DWIN32_LEAN_AND_MEAN)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)

View File

@@ -1 +1,19 @@
# m2dev-client-src
# Client Source Repository
This repository contains the source code necessary to compile the game client executable.
## How to build
> cmake -S . -B build
>
> cmake --build build
---
## 📋 Changelog
### 🐛 Bug Fixes
* **Amun's freeze on drag window**: Fixed a bug where the client window would freeze while we are dragging it around.
* **Debug mode:** Fly effects are now registering when using Debug mode.
* **Fix effect rendering in low opacity models:** Effects now appear normally on semi-transparent meshes.
* **Fly targeting fixed for buff/healing skills:** Fixed an issue where fly target effect would render in the buffer's selected target even if the target was unbuffable (if viewing from another client).

8421
extern/include/MSS.H vendored

File diff suppressed because it is too large Load Diff

2589
extern/include/argparse.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

2
extern/include/miniaudio.c vendored Normal file
View File

@@ -0,0 +1,2 @@
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"

93468
extern/include/miniaudio.h vendored Normal file

File diff suppressed because it is too large Load Diff

666
extern/include/pcg_extras.hpp vendored Normal file
View File

@@ -0,0 +1,666 @@
/*
* PCG Random Number Generation for C++
*
* Copyright 2014-2017 Melissa O'Neill <oneill@pcg-random.org>,
* and the PCG Project contributors.
*
* SPDX-License-Identifier: (Apache-2.0 OR MIT)
*
* Licensed under the Apache License, Version 2.0 (provided in
* LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0)
* or under the MIT license (provided in LICENSE-MIT.txt and at
* http://opensource.org/licenses/MIT), at your option. This file may not
* be copied, modified, or distributed except according to those terms.
*
* Distributed on an "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See your chosen license for details.
*
* For additional information about the PCG random number generation scheme,
* visit http://www.pcg-random.org/.
*/
/*
* This file provides support code that is useful for random-number generation
* but not specific to the PCG generation scheme, including:
* - 128-bit int support for platforms where it isn't available natively
* - bit twiddling operations
* - I/O of 128-bit and 8-bit integers
* - Handling the evilness of SeedSeq
* - Support for efficiently producing random numbers less than a given
* bound
*/
#ifndef PCG_EXTRAS_HPP_INCLUDED
#define PCG_EXTRAS_HPP_INCLUDED 1
#include <cinttypes>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <limits>
#include <iostream>
#include <type_traits>
#include <utility>
#include <locale>
#include <iterator>
#ifdef __GNUC__
#include <cxxabi.h>
#endif
/*
* Abstractions for compiler-specific directives
*/
#ifdef __GNUC__
#define PCG_NOINLINE __attribute__((noinline))
#else
#define PCG_NOINLINE
#endif
/*
* Some members of the PCG library use 128-bit math. When compiling on 64-bit
* platforms, both GCC and Clang provide 128-bit integer types that are ideal
* for the job.
*
* On 32-bit platforms (or with other compilers), we fall back to a C++
* class that provides 128-bit unsigned integers instead. It may seem
* like we're reinventing the wheel here, because libraries already exist
* that support large integers, but most existing libraries provide a very
* generic multiprecision code, but here we're operating at a fixed size.
* Also, most other libraries are fairly heavyweight. So we use a direct
* implementation. Sadly, it's much slower than hand-coded assembly or
* direct CPU support.
*
*/
#if __SIZEOF_INT128__ && !PCG_FORCE_EMULATED_128BIT_MATH
namespace pcg_extras {
typedef __uint128_t pcg128_t;
}
#define PCG_128BIT_CONSTANT(high,low) \
((pcg_extras::pcg128_t(high) << 64) + low)
#else
#include "pcg_uint128.hpp"
namespace pcg_extras {
typedef pcg_extras::uint_x4<uint32_t,uint64_t> pcg128_t;
}
#define PCG_128BIT_CONSTANT(high,low) \
pcg_extras::pcg128_t(high,low)
#define PCG_EMULATED_128BIT_MATH 1
#endif
namespace pcg_extras {
/*
* We often need to represent a "number of bits". When used normally, these
* numbers are never greater than 128, so an unsigned char is plenty.
* If you're using a nonstandard generator of a larger size, you can set
* PCG_BITCOUNT_T to have it define it as a larger size. (Some compilers
* might produce faster code if you set it to an unsigned int.)
*/
#ifndef PCG_BITCOUNT_T
typedef uint8_t bitcount_t;
#else
typedef PCG_BITCOUNT_T bitcount_t;
#endif
/*
* C++ requires us to be able to serialize RNG state by printing or reading
* it from a stream. Because we use 128-bit ints, we also need to be able
* ot print them, so here is code to do so.
*
* This code provides enough functionality to print 128-bit ints in decimal
* and zero-padded in hex. It's not a full-featured implementation.
*/
template <typename CharT, typename Traits>
std::basic_ostream<CharT,Traits>&
operator<<(std::basic_ostream<CharT,Traits>& out, pcg128_t value)
{
auto desired_base = out.flags() & out.basefield;
bool want_hex = desired_base == out.hex;
if (want_hex) {
uint64_t highpart = uint64_t(value >> 64);
uint64_t lowpart = uint64_t(value);
auto desired_width = out.width();
if (desired_width > 16) {
out.width(desired_width - 16);
}
if (highpart != 0 || desired_width > 16)
out << highpart;
CharT oldfill = '\0';
if (highpart != 0) {
out.width(16);
oldfill = out.fill('0');
}
auto oldflags = out.setf(decltype(desired_base){}, out.showbase);
out << lowpart;
out.setf(oldflags);
if (highpart != 0) {
out.fill(oldfill);
}
return out;
}
constexpr size_t MAX_CHARS_128BIT = 40;
char buffer[MAX_CHARS_128BIT];
char* pos = buffer+sizeof(buffer);
*(--pos) = '\0';
constexpr auto BASE = pcg128_t(10ULL);
do {
auto div = value / BASE;
auto mod = uint32_t(value - (div * BASE));
*(--pos) = '0' + char(mod);
value = div;
} while(value != pcg128_t(0ULL));
return out << pos;
}
template <typename CharT, typename Traits>
std::basic_istream<CharT,Traits>&
operator>>(std::basic_istream<CharT,Traits>& in, pcg128_t& value)
{
typename std::basic_istream<CharT,Traits>::sentry s(in);
if (!s)
return in;
constexpr auto BASE = pcg128_t(10ULL);
pcg128_t current(0ULL);
bool did_nothing = true;
bool overflow = false;
for(;;) {
CharT wide_ch = in.get();
if (!in.good()) {
in.clear(std::ios::eofbit);
break;
}
auto ch = in.narrow(wide_ch, '\0');
if (ch < '0' || ch > '9') {
in.unget();
break;
}
did_nothing = false;
pcg128_t digit(uint32_t(ch - '0'));
pcg128_t timesbase = current*BASE;
overflow = overflow || timesbase < current;
current = timesbase + digit;
overflow = overflow || current < digit;
}
if (did_nothing || overflow) {
in.setstate(std::ios::failbit);
if (overflow)
current = ~pcg128_t(0ULL);
}
value = current;
return in;
}
/*
* Likewise, if people use tiny rngs, we'll be serializing uint8_t.
* If we just used the provided IO operators, they'd read/write chars,
* not ints, so we need to define our own. We *can* redefine this operator
* here because we're in our own namespace.
*/
template <typename CharT, typename Traits>
std::basic_ostream<CharT,Traits>&
operator<<(std::basic_ostream<CharT,Traits>&out, uint8_t value)
{
return out << uint32_t(value);
}
template <typename CharT, typename Traits>
std::basic_istream<CharT,Traits>&
operator>>(std::basic_istream<CharT,Traits>& in, uint8_t& target)
{
uint32_t value = 0xdecea5edU;
in >> value;
if (!in && value == 0xdecea5edU)
return in;
if (value > uint8_t(~0)) {
in.setstate(std::ios::failbit);
value = ~0U;
}
target = uint8_t(value);
return in;
}
/* Unfortunately, the above functions don't get found in preference to the
* built in ones, so we create some more specific overloads that will.
* Ugh.
*/
inline std::ostream& operator<<(std::ostream& out, uint8_t value)
{
return pcg_extras::operator<< <char>(out, value);
}
inline std::istream& operator>>(std::istream& in, uint8_t& value)
{
return pcg_extras::operator>> <char>(in, value);
}
/*
* Useful bitwise operations.
*/
/*
* XorShifts are invertable, but they are someting of a pain to invert.
* This function backs them out. It's used by the whacky "inside out"
* generator defined later.
*/
template <typename itype>
inline itype unxorshift(itype x, bitcount_t bits, bitcount_t shift)
{
if (2*shift >= bits) {
return x ^ (x >> shift);
}
itype lowmask1 = (itype(1U) << (bits - shift*2)) - 1;
itype highmask1 = ~lowmask1;
itype top1 = x;
itype bottom1 = x & lowmask1;
top1 ^= top1 >> shift;
top1 &= highmask1;
x = top1 | bottom1;
itype lowmask2 = (itype(1U) << (bits - shift)) - 1;
itype bottom2 = x & lowmask2;
bottom2 = unxorshift(bottom2, bits - shift, shift);
bottom2 &= lowmask1;
return top1 | bottom2;
}
/*
* Rotate left and right.
*
* In ideal world, compilers would spot idiomatic rotate code and convert it
* to a rotate instruction. Of course, opinions vary on what the correct
* idiom is and how to spot it. For clang, sometimes it generates better
* (but still crappy) code if you define PCG_USE_ZEROCHECK_ROTATE_IDIOM.
*/
template <typename itype>
inline itype rotl(itype value, bitcount_t rot)
{
constexpr bitcount_t bits = sizeof(itype) * 8;
constexpr bitcount_t mask = bits - 1;
#if PCG_USE_ZEROCHECK_ROTATE_IDIOM
return rot ? (value << rot) | (value >> (bits - rot)) : value;
#else
return (value << rot) | (value >> ((- rot) & mask));
#endif
}
template <typename itype>
inline itype rotr(itype value, bitcount_t rot)
{
constexpr bitcount_t bits = sizeof(itype) * 8;
constexpr bitcount_t mask = bits - 1;
#if PCG_USE_ZEROCHECK_ROTATE_IDIOM
return rot ? (value >> rot) | (value << (bits - rot)) : value;
#else
return (value >> rot) | (value << ((- rot) & mask));
#endif
}
/* Unfortunately, both Clang and GCC sometimes perform poorly when it comes
* to properly recognizing idiomatic rotate code, so for we also provide
* assembler directives (enabled with PCG_USE_INLINE_ASM). Boo, hiss.
* (I hope that these compilers get better so that this code can die.)
*
* These overloads will be preferred over the general template code above.
*/
#if PCG_USE_INLINE_ASM && __GNUC__ && (__x86_64__ || __i386__)
inline uint8_t rotr(uint8_t value, bitcount_t rot)
{
asm ("rorb %%cl, %0" : "=r" (value) : "0" (value), "c" (rot));
return value;
}
inline uint16_t rotr(uint16_t value, bitcount_t rot)
{
asm ("rorw %%cl, %0" : "=r" (value) : "0" (value), "c" (rot));
return value;
}
inline uint32_t rotr(uint32_t value, bitcount_t rot)
{
asm ("rorl %%cl, %0" : "=r" (value) : "0" (value), "c" (rot));
return value;
}
#if __x86_64__
inline uint64_t rotr(uint64_t value, bitcount_t rot)
{
asm ("rorq %%cl, %0" : "=r" (value) : "0" (value), "c" (rot));
return value;
}
#endif // __x86_64__
#elif defined(_MSC_VER)
// Use MSVC++ bit rotation intrinsics
#pragma intrinsic(_rotr, _rotr64, _rotr8, _rotr16)
inline uint8_t rotr(uint8_t value, bitcount_t rot)
{
return _rotr8(value, rot);
}
inline uint16_t rotr(uint16_t value, bitcount_t rot)
{
return _rotr16(value, rot);
}
inline uint32_t rotr(uint32_t value, bitcount_t rot)
{
return _rotr(value, rot);
}
inline uint64_t rotr(uint64_t value, bitcount_t rot)
{
return _rotr64(value, rot);
}
#endif // PCG_USE_INLINE_ASM
/*
* The C++ SeedSeq concept (modelled by seed_seq) can fill an array of
* 32-bit integers with seed data, but sometimes we want to produce
* larger or smaller integers.
*
* The following code handles this annoyance.
*
* uneven_copy will copy an array of 32-bit ints to an array of larger or
* smaller ints (actually, the code is general it only needing forward
* iterators). The copy is identical to the one that would be performed if
* we just did memcpy on a standard little-endian machine, but works
* regardless of the endian of the machine (or the weirdness of the ints
* involved).
*
* generate_to initializes an array of integers using a SeedSeq
* object. It is given the size as a static constant at compile time and
* tries to avoid memory allocation. If we're filling in 32-bit constants
* we just do it directly. If we need a separate buffer and it's small,
* we allocate it on the stack. Otherwise, we fall back to heap allocation.
* Ugh.
*
* generate_one produces a single value of some integral type using a
* SeedSeq object.
*/
/* uneven_copy helper, case where destination ints are less than 32 bit. */
template<class SrcIter, class DestIter>
SrcIter uneven_copy_impl(
SrcIter src_first, DestIter dest_first, DestIter dest_last,
std::true_type)
{
typedef typename std::iterator_traits<SrcIter>::value_type src_t;
typedef typename std::iterator_traits<DestIter>::value_type dest_t;
constexpr bitcount_t SRC_SIZE = sizeof(src_t);
constexpr bitcount_t DEST_SIZE = sizeof(dest_t);
constexpr bitcount_t DEST_BITS = DEST_SIZE * 8;
constexpr bitcount_t SCALE = SRC_SIZE / DEST_SIZE;
size_t count = 0;
src_t value = 0;
while (dest_first != dest_last) {
if ((count++ % SCALE) == 0)
value = *src_first++; // Get more bits
else
value >>= DEST_BITS; // Move down bits
*dest_first++ = dest_t(value); // Truncates, ignores high bits.
}
return src_first;
}
/* uneven_copy helper, case where destination ints are more than 32 bit. */
template<class SrcIter, class DestIter>
SrcIter uneven_copy_impl(
SrcIter src_first, DestIter dest_first, DestIter dest_last,
std::false_type)
{
typedef typename std::iterator_traits<SrcIter>::value_type src_t;
typedef typename std::iterator_traits<DestIter>::value_type dest_t;
constexpr auto SRC_SIZE = sizeof(src_t);
constexpr auto SRC_BITS = SRC_SIZE * 8;
constexpr auto DEST_SIZE = sizeof(dest_t);
constexpr auto SCALE = (DEST_SIZE+SRC_SIZE-1) / SRC_SIZE;
while (dest_first != dest_last) {
dest_t value(0UL);
unsigned int shift = 0;
for (size_t i = 0; i < SCALE; ++i) {
value |= dest_t(*src_first++) << shift;
shift += SRC_BITS;
}
*dest_first++ = value;
}
return src_first;
}
/* uneven_copy, call the right code for larger vs. smaller */
template<class SrcIter, class DestIter>
inline SrcIter uneven_copy(SrcIter src_first,
DestIter dest_first, DestIter dest_last)
{
typedef typename std::iterator_traits<SrcIter>::value_type src_t;
typedef typename std::iterator_traits<DestIter>::value_type dest_t;
constexpr bool DEST_IS_SMALLER = sizeof(dest_t) < sizeof(src_t);
return uneven_copy_impl(src_first, dest_first, dest_last,
std::integral_constant<bool, DEST_IS_SMALLER>{});
}
/* generate_to, fill in a fixed-size array of integral type using a SeedSeq
* (actually works for any random-access iterator)
*/
template <size_t size, typename SeedSeq, typename DestIter>
inline void generate_to_impl(SeedSeq&& generator, DestIter dest,
std::true_type)
{
generator.generate(dest, dest+size);
}
template <size_t size, typename SeedSeq, typename DestIter>
void generate_to_impl(SeedSeq&& generator, DestIter dest,
std::false_type)
{
typedef typename std::iterator_traits<DestIter>::value_type dest_t;
constexpr auto DEST_SIZE = sizeof(dest_t);
constexpr auto GEN_SIZE = sizeof(uint32_t);
constexpr bool GEN_IS_SMALLER = GEN_SIZE < DEST_SIZE;
constexpr size_t FROM_ELEMS =
GEN_IS_SMALLER
? size * ((DEST_SIZE+GEN_SIZE-1) / GEN_SIZE)
: (size + (GEN_SIZE / DEST_SIZE) - 1)
/ ((GEN_SIZE / DEST_SIZE) + GEN_IS_SMALLER);
// this odd code ^^^^^^^^^^^^^^^^^ is work-around for
// a bug: http://llvm.org/bugs/show_bug.cgi?id=21287
if (FROM_ELEMS <= 1024) {
uint32_t buffer[FROM_ELEMS];
generator.generate(buffer, buffer+FROM_ELEMS);
uneven_copy(buffer, dest, dest+size);
} else {
uint32_t* buffer = static_cast<uint32_t*>(malloc(GEN_SIZE * FROM_ELEMS));
generator.generate(buffer, buffer+FROM_ELEMS);
uneven_copy(buffer, dest, dest+size);
free(static_cast<void*>(buffer));
}
}
template <size_t size, typename SeedSeq, typename DestIter>
inline void generate_to(SeedSeq&& generator, DestIter dest)
{
typedef typename std::iterator_traits<DestIter>::value_type dest_t;
constexpr bool IS_32BIT = sizeof(dest_t) == sizeof(uint32_t);
generate_to_impl<size>(std::forward<SeedSeq>(generator), dest,
std::integral_constant<bool, IS_32BIT>{});
}
/* generate_one, produce a value of integral type using a SeedSeq
* (optionally, we can have it produce more than one and pick which one
* we want)
*/
template <typename UInt, size_t i = 0UL, size_t N = i+1UL, typename SeedSeq>
inline UInt generate_one(SeedSeq&& generator)
{
UInt result[N];
generate_to<N>(std::forward<SeedSeq>(generator), result);
return result[i];
}
template <typename RngType>
auto bounded_rand(RngType& rng, typename RngType::result_type upper_bound)
-> typename RngType::result_type
{
typedef typename RngType::result_type rtype;
rtype threshold = (RngType::max() - RngType::min() + rtype(1) - upper_bound)
% upper_bound;
for (;;) {
rtype r = rng() - RngType::min();
if (r >= threshold)
return r % upper_bound;
}
}
template <typename Iter, typename RandType>
void shuffle(Iter from, Iter to, RandType&& rng)
{
typedef typename std::iterator_traits<Iter>::difference_type delta_t;
typedef typename std::remove_reference<RandType>::type::result_type result_t;
auto count = to - from;
while (count > 1) {
delta_t chosen = delta_t(bounded_rand(rng, result_t(count)));
--count;
--to;
using std::swap;
swap(*(from + chosen), *to);
}
}
/*
* Although std::seed_seq is useful, it isn't everything. Often we want to
* initialize a random-number generator some other way, such as from a random
* device.
*
* Technically, it does not meet the requirements of a SeedSequence because
* it lacks some of the rarely-used member functions (some of which would
* be impossible to provide). However the C++ standard is quite specific
* that actual engines only called the generate method, so it ought not to be
* a problem in practice.
*/
template <typename RngType>
class seed_seq_from {
private:
RngType rng_;
typedef uint_least32_t result_type;
public:
template<typename... Args>
seed_seq_from(Args&&... args) :
rng_(std::forward<Args>(args)...)
{
// Nothing (else) to do...
}
template<typename Iter>
void generate(Iter start, Iter finish)
{
for (auto i = start; i != finish; ++i)
*i = result_type(rng_());
}
constexpr size_t size() const
{
return (sizeof(typename RngType::result_type) > sizeof(result_type)
&& RngType::max() > ~size_t(0UL))
? ~size_t(0UL)
: size_t(RngType::max());
}
};
/*
* Sometimes you might want a distinct seed based on when the program
* was compiled. That way, a particular instance of the program will
* behave the same way, but when recompiled it'll produce a different
* value.
*/
template <typename IntType>
struct static_arbitrary_seed {
private:
static constexpr IntType fnv(IntType hash, const char* pos) {
return *pos == '\0'
? hash
: fnv((hash * IntType(16777619U)) ^ *pos, (pos+1));
}
public:
static constexpr IntType value = fnv(IntType(2166136261U ^ sizeof(IntType)),
__DATE__ __TIME__ __FILE__);
};
// Sometimes, when debugging or testing, it's handy to be able print the name
// of a (in human-readable form). This code allows the idiom:
//
// cout << printable_typename<my_foo_type_t>()
//
// to print out my_foo_type_t (or its concrete type if it is a synonym)
#if __cpp_rtti || __GXX_RTTI
template <typename T>
struct printable_typename {};
template <typename T>
std::ostream& operator<<(std::ostream& out, printable_typename<T>) {
const char *implementation_typename = typeid(T).name();
#ifdef __GNUC__
int status;
char* pretty_name =
abi::__cxa_demangle(implementation_typename, nullptr, nullptr, &status);
if (status == 0)
out << pretty_name;
free(static_cast<void*>(pretty_name));
if (status == 0)
return out;
#endif
out << implementation_typename;
return out;
}
#endif // __cpp_rtti || __GXX_RTTI
} // namespace pcg_extras
#endif // PCG_EXTRAS_HPP_INCLUDED

1951
extern/include/pcg_random.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

1006
extern/include/pcg_uint128.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

840
extern/include/utf8.h vendored Normal file
View File

@@ -0,0 +1,840 @@
#pragma once
#include <string>
#include <windows.h>
#include <vector>
#include <algorithm>
#include <cmath>
#include <EterLocale/Arabic.h>
// ============================================================================
// CONFIGURATION CONSTANTS
// ============================================================================
// Maximum text length for security/performance (prevent DoS attacks)
constexpr size_t MAX_TEXT_LENGTH = 65536; // 64KB of text
constexpr size_t MAX_CHAT_TEXT_LENGTH = 4096; // 4KB for chat messages
// Arabic shaping buffer size calculations
constexpr size_t ARABIC_SHAPING_EXPANSION_FACTOR = 2;
constexpr size_t ARABIC_SHAPING_SAFETY_MARGIN = 16;
constexpr size_t ARABIC_SHAPING_EXPANSION_FACTOR_RETRY = 4;
constexpr size_t ARABIC_SHAPING_SAFETY_MARGIN_RETRY = 64;
// ============================================================================
// DEBUG LOGGING (Only enabled in Debug builds)
// ============================================================================
#ifdef _DEBUG
#define DEBUG_BIDI // Enabled in debug builds for diagnostics
#endif
#ifdef DEBUG_BIDI
#include <cstdio>
#define BIDI_LOG(fmt, ...) printf("[BiDi] " fmt "\n", __VA_ARGS__)
#define BIDI_LOG_SIMPLE(msg) printf("[BiDi] %s\n", msg)
#else
#define BIDI_LOG(fmt, ...) ((void)0)
#define BIDI_LOG_SIMPLE(msg) ((void)0)
#endif
// ============================================================================
// UNICODE VALIDATION HELPERS
// ============================================================================
// Check if codepoint is a valid Unicode scalar value (not surrogate, not non-character)
static inline bool IsValidUnicodeScalar(wchar_t ch)
{
// Reject surrogate pairs (UTF-16 encoding artifacts, invalid in UTF-8)
if (ch >= 0xD800 && ch <= 0xDFFF)
return false;
// Reject non-characters (reserved by Unicode standard)
if ((ch >= 0xFDD0 && ch <= 0xFDEF) || // Arabic Presentation Forms non-chars
(ch & 0xFFFE) == 0xFFFE) // U+FFFE, U+FFFF, etc.
return false;
// Accept everything else in BMP (0x0000-0xFFFF)
return true;
}
// Sanitize a wide string by removing invalid Unicode codepoints
static inline void SanitizeWideString(std::wstring& ws)
{
ws.erase(std::remove_if(ws.begin(), ws.end(),
[](wchar_t ch) { return !IsValidUnicodeScalar(ch); }),
ws.end());
}
// UTF-8 -> UTF-16 (Windows wide)
inline std::wstring Utf8ToWide(const std::string& s)
{
if (s.empty())
return L"";
// Validate size limits (prevent DoS and INT_MAX overflow)
if (s.size() > MAX_TEXT_LENGTH || s.size() > INT_MAX)
{
BIDI_LOG("Utf8ToWide: String too large (%zu bytes)", s.size());
return L""; // String too large
}
int wlen = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), (int)s.size(), nullptr, 0);
if (wlen <= 0)
{
BIDI_LOG("Utf8ToWide: Invalid UTF-8 sequence (error %d)", GetLastError());
return L"";
}
std::wstring out(wlen, L'\0');
int written = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), (int)s.size(), out.data(), wlen);
if (written <= 0 || written != wlen)
{
BIDI_LOG("Utf8ToWide: Second conversion failed (written=%d, expected=%d, error=%d)", written, wlen, GetLastError());
return L""; // Conversion failed unexpectedly
}
// Optional: Sanitize to remove invalid Unicode codepoints (surrogates, non-characters)
// Uncomment if you want strict validation
// SanitizeWideString(out);
return out;
}
// Convenience overload for char*
inline std::wstring Utf8ToWide(const char* s)
{
if (!s || !*s)
return L"";
int wlen = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s, -1, nullptr, 0);
if (wlen <= 0)
return L"";
// wlen includes terminating NUL
std::wstring out(wlen, L'\0');
int written = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s, -1, out.data(), wlen);
if (written <= 0 || written != wlen)
{
BIDI_LOG("Utf8ToWide(char*): Conversion failed (written=%d, expected=%d, error=%d)", written, wlen, GetLastError());
return L"";
}
// Drop the terminating NUL from std::wstring length
if (!out.empty() && out.back() == L'\0')
out.pop_back();
// Optional: Sanitize to remove invalid Unicode codepoints
// SanitizeWideString(out);
return out;
}
// UTF-16 (Windows wide) -> UTF-8
inline std::string WideToUtf8(const std::wstring& ws)
{
if (ws.empty())
return "";
// Validate size limits (prevent DoS and INT_MAX overflow)
if (ws.size() > MAX_TEXT_LENGTH || ws.size() > INT_MAX)
return ""; // String too large
int len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ws.data(), (int)ws.size(), nullptr, 0, nullptr, nullptr);
if (len <= 0)
return "";
std::string out(len, '\0');
int written = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ws.data(), (int)ws.size(), out.data(), len, nullptr, nullptr);
if (written <= 0 || written != len)
{
BIDI_LOG("WideToUtf8: Conversion failed (written=%d, expected=%d, error=%d)", written, len, GetLastError());
return ""; // Conversion failed
}
return out;
}
// Convenience overload for wchar_t*
inline std::string WideToUtf8(const wchar_t* ws)
{
if (!ws)
return "";
return WideToUtf8(std::wstring(ws));
}
// ============================================================================
// RTL & BiDi formatting for RTL UI
// ============================================================================
enum class EBidiDir { LTR, RTL };
enum class ECharDir : unsigned char { Neutral, LTR, RTL };
struct TBidiRun
{
EBidiDir dir;
std::vector<wchar_t> text; // logical order
};
static inline bool IsRTLCodepoint(wchar_t ch)
{
// Directional marks / isolates / embeddings that affect bidi
if (ch == 0x200F || ch == 0x061C) return true; // RLM, ALM
if (ch >= 0x202B && ch <= 0x202E) return true; // RLE/RLO/PDF/LRE/LRO
if (ch >= 0x2066 && ch <= 0x2069) return true; // isolates
// Hebrew + Arabic blocks (BMP)
if (ch >= 0x0590 && ch <= 0x08FF) return true;
// Presentation forms
if (ch >= 0xFB1D && ch <= 0xFDFF) return true;
if (ch >= 0xFE70 && ch <= 0xFEFF) return true;
return false;
}
static inline bool IsStrongAlpha(wchar_t ch)
{
// Use thread-local cache for BMP (Thread safety)
thread_local static unsigned char cache[65536] = {}; // 0=unknown, 1=true, 2=false
unsigned char& v = cache[(unsigned short)ch];
if (v == 1) return true;
if (v == 2) return false;
WORD type = 0;
bool ok = GetStringTypeW(CT_CTYPE1, &ch, 1, &type) && (type & C1_ALPHA);
v = ok ? 1 : 2;
return ok;
}
static inline bool IsDigit(wchar_t ch)
{
// Fast path for ASCII digits (90%+ of digit checks)
if (ch >= L'0' && ch <= L'9')
return true;
// For non-ASCII, use cache (Arabic-Indic digits, etc.)
thread_local static unsigned char cache[65536] = {}; // 0=unknown, 1=true, 2=false
unsigned char& v = cache[(unsigned short)ch];
if (v == 1) return true;
if (v == 2) return false;
WORD type = 0;
bool ok = GetStringTypeW(CT_CTYPE1, &ch, 1, &type) && (type & C1_DIGIT);
v = ok ? 1 : 2;
return ok;
}
static inline bool IsNameTokenPunct(wchar_t ch)
{
switch (ch)
{
case L'#':
case L'@':
case L'$':
case L'%':
case L'&':
case L'*':
case L'+':
case L'-':
case L'_':
case L'=':
case L'.':
case L',':
case L'/':
case L'\\':
case L'(':
case L')':
// Brackets are handled specially - see GetCharDirSmart
// case L'[':
// case L']':
case L'{':
case L'}':
case L'<':
case L'>':
return true;
default:
return false;
}
}
// Check RTL first to avoid classifying Arabic as LTR
static inline bool IsStrongLTR(wchar_t ch)
{
if (IsRTLCodepoint(ch))
return false;
return IsStrongAlpha(ch) || IsDigit(ch);
}
static inline bool HasStrongLTRNeighbor(const wchar_t* s, int n, int i)
{
// Skip neutral characters (spaces, punctuation) to find nearest strong character
// This fixes mixed-direction text like "english + arabic"
// Search backwards for strong character (skip neutrals/whitespace)
for (int j = i - 1; j >= 0; --j)
{
wchar_t ch = s[j];
// Skip spaces and common neutral punctuation
if (ch == L' ' || ch == L'\t' || ch == L'\n')
continue;
// Found strong LTR
if (IsStrongLTR(ch))
return true;
// Found strong RTL or other strong character
if (IsRTLCodepoint(ch) || IsStrongAlpha(ch))
break;
}
// Search forwards for strong character (skip neutrals/whitespace)
for (int j = i + 1; j < n; ++j)
{
wchar_t ch = s[j];
// Skip spaces and common neutral punctuation
if (ch == L' ' || ch == L'\t' || ch == L'\n')
continue;
// Found strong LTR
if (IsStrongLTR(ch))
return true;
// Found strong RTL or other strong character
if (IsRTLCodepoint(ch) || IsStrongAlpha(ch))
break;
}
return false;
}
static inline ECharDir GetCharDir(wchar_t ch)
{
if (IsRTLCodepoint(ch))
return ECharDir::RTL;
// Use IsStrongLTR which now correctly excludes RTL
if (IsStrongLTR(ch))
return ECharDir::LTR;
return ECharDir::Neutral;
}
static inline ECharDir GetCharDirSmart(const wchar_t* s, int n, int i)
{
wchar_t ch = s[i];
// True RTL letters/marks
if (IsRTLCodepoint(ch))
return ECharDir::RTL;
// True LTR letters/digits (now correctly excludes RTL)
if (IsStrongLTR(ch))
return ECharDir::LTR;
// Parentheses: always LTR to keep them with their content
if (ch == L'(' || ch == L')')
return ECharDir::LTR;
// Common punctuation: treat as strong LTR to prevent jumping around in mixed text
// This makes "Hello + اختبار" and "اختبار + Hello" both keep punctuation in place
if (ch == L'+' || ch == L'-' || ch == L'=' || ch == L'*' || ch == L'/' ||
ch == L'<' || ch == L'>' || ch == L'&' || ch == L'|' || ch == L'@' || ch == L'#')
return ECharDir::LTR;
// Percentage sign: attach to numbers (scan nearby for digits/minus/plus)
// Handles: "%20", "20%", "-6%", "%d%%", etc.
if (ch == L'%')
{
// Look backward for digit, %, -, or +
for (int j = i - 1; j >= 0 && (i - j) < 5; --j)
{
wchar_t prev = s[j];
if (IsDigit(prev) || prev == L'%' || prev == L'-' || prev == L'+')
return ECharDir::LTR;
if (prev != L' ' && prev != L'\t')
break; // Stop if we hit non-numeric character
}
// Look forward for digit, %, -, or +
for (int j = i + 1; j < n && (j - i) < 5; ++j)
{
wchar_t next = s[j];
if (IsDigit(next) || next == L'%' || next == L'-' || next == L'+')
return ECharDir::LTR;
if (next != L' ' && next != L'\t')
break; // Stop if we hit non-numeric character
}
return ECharDir::Neutral;
}
// Minus/dash: attach to numbers (scan nearby for digits/%)
// Handles: "-6", "5-10", "-6%%", etc.
if (ch == L'-')
{
// Look backward for digit or %
for (int j = i - 1; j >= 0 && (i - j) < 3; --j)
{
wchar_t prev = s[j];
if (IsDigit(prev) || prev == L'%')
return ECharDir::LTR;
if (prev != L' ' && prev != L'\t')
break;
}
// Look forward for digit or %
for (int j = i + 1; j < n && (j - i) < 3; ++j)
{
wchar_t next = s[j];
if (IsDigit(next) || next == L'%')
return ECharDir::LTR;
if (next != L' ' && next != L'\t')
break;
}
return ECharDir::Neutral;
}
// Colon: attach to preceding text direction
// Look backward to find strong character
if (ch == L':')
{
for (int j = i - 1; j >= 0; --j)
{
if (s[j] == L' ' || s[j] == L'\t')
continue; // Skip spaces
if (IsRTLCodepoint(s[j]))
return ECharDir::RTL; // Attach to RTL text
if (IsStrongLTR(s[j]))
return ECharDir::LTR; // Attach to LTR text
}
return ECharDir::Neutral;
}
// Enhancement marker: '+' followed by digit(s) should attach to preceding text
// If preceded by RTL, treat as RTL to keep "+9" with the item name
// Otherwise treat as LTR
if (ch == L'+' && i + 1 < n && IsDigit(s[i + 1]))
{
// Look backward for the last strong character
for (int j = i - 1; j >= 0; --j)
{
if (IsRTLCodepoint(s[j]))
return ECharDir::RTL; // Attach to preceding RTL text
if (IsStrongLTR(s[j]))
return ECharDir::LTR; // Attach to preceding LTR text
// Skip neutral characters
}
return ECharDir::LTR; // Default to LTR if no strong character found
}
// Brackets: always attach to the content inside them
// This fixes hyperlinks like "[درع فولاذي أسود+9]"
if (ch == L'[' || ch == L']')
{
// Opening bracket '[': look forward for strong character
if (ch == L'[')
{
for (int j = i + 1; j < n; ++j)
{
wchar_t next = s[j];
if (next == L']') break; // End of bracket content
if (IsRTLCodepoint(next)) return ECharDir::RTL;
if (IsStrongLTR(next)) return ECharDir::LTR;
}
}
// Closing bracket ']': look backward for strong character
else if (ch == L']')
{
for (int j = i - 1; j >= 0; --j)
{
wchar_t prev = s[j];
if (prev == L'[') break; // Start of bracket content
if (IsRTLCodepoint(prev)) return ECharDir::RTL;
if (IsStrongLTR(prev)) return ECharDir::LTR;
}
}
// If we can't determine, treat as neutral
return ECharDir::Neutral;
}
// Spaces should attach to adjacent strong characters to avoid fragmentation
// This fixes "english + arabic" by keeping " + " with "english"
if (ch == L' ' || ch == L'\t')
{
if (HasStrongLTRNeighbor(s, n, i))
return ECharDir::LTR;
// Note: We don't check for RTL neighbor because ResolveNeutralDir handles that
}
// Name-token punctuation: if adjacent to LTR, treat as LTR to keep token intact
if (IsNameTokenPunct(ch) && HasStrongLTRNeighbor(s, n, i))
return ECharDir::LTR;
return ECharDir::Neutral;
}
// Pre-computed strong character lookup for O(1) neutral resolution
struct TStrongDirCache
{
std::vector<EBidiDir> nextStrong; // nextStrong[i] = direction of next strong char after position i
EBidiDir baseDir;
TStrongDirCache(const wchar_t* s, int n, EBidiDir base) : nextStrong(n), baseDir(base)
{
// Build reverse lookup: scan from end to beginning
// Use GetCharDirSmart for context-aware character classification
EBidiDir lastSeen = baseDir;
for (int i = n - 1; i >= 0; --i)
{
ECharDir cd = GetCharDirSmart(s, n, i);
if (cd == ECharDir::LTR)
lastSeen = EBidiDir::LTR;
else if (cd == ECharDir::RTL)
lastSeen = EBidiDir::RTL;
nextStrong[i] = lastSeen;
}
}
EBidiDir GetNextStrong(int i) const
{
if (i + 1 < (int)nextStrong.size())
return nextStrong[i + 1];
return baseDir;
}
};
static inline EBidiDir ResolveNeutralDir(const wchar_t* s, int n, int i, EBidiDir baseDir, EBidiDir lastStrong, const TStrongDirCache* cache = nullptr)
{
// Use pre-computed cache if available (O(1) instead of O(n))
EBidiDir nextStrong = baseDir;
if (cache)
{
nextStrong = cache->GetNextStrong(i);
}
else
{
// Linear scan (slower, but works without cache)
for (int j = i + 1; j < n; ++j)
{
ECharDir cd = GetCharDirSmart(s, n, j);
if (cd == ECharDir::LTR) { nextStrong = EBidiDir::LTR; break; }
if (cd == ECharDir::RTL) { nextStrong = EBidiDir::RTL; break; }
}
}
// If both sides agree, neutral adopts that direction
if (lastStrong == nextStrong)
return lastStrong;
// Handle edge cases for leading/trailing punctuation
if (nextStrong == baseDir && lastStrong != baseDir)
return lastStrong;
if (lastStrong == baseDir && nextStrong != baseDir)
return nextStrong;
// Otherwise fall back to base direction
return baseDir;
}
static EBidiDir DetectBaseDir_FirstStrong(const wchar_t* s, int n)
{
if (!s || n <= 0)
return EBidiDir::LTR;
for (int i = 0; i < n; ++i)
{
const wchar_t ch = s[i];
// Check RTL first, then alpha
if (IsRTLCodepoint(ch))
return EBidiDir::RTL;
if (IsStrongAlpha(ch))
return EBidiDir::LTR;
}
return EBidiDir::LTR;
}
static std::vector<wchar_t> BuildVisualBidiText_Tagless(const wchar_t* s, int n, bool forceRTL)
{
if (!s || n <= 0)
return {};
// 1) base direction
EBidiDir base = forceRTL ? EBidiDir::RTL : DetectBaseDir_FirstStrong(s, n);
// Pre-compute strong character positions for O(1) neutral resolution
TStrongDirCache strongCache(s, n, base);
// 2) split into runs
// Estimate runs based on text length (~1 per 50 chars, min 4)
std::vector<TBidiRun> runs;
const size_t estimatedRuns = (size_t)std::max(4, n / 50);
runs.reserve(estimatedRuns);
auto push_run = [&](EBidiDir d)
{
if (runs.empty() || runs.back().dir != d)
runs.push_back(TBidiRun{ d, {} });
};
// start with base so leading neutrals attach predictably
push_run(base);
EBidiDir lastStrong = base;
for (int i = 0; i < n; ++i)
{
wchar_t ch = s[i];
EBidiDir d;
ECharDir cd = GetCharDirSmart(s, n, i);
if (cd == ECharDir::RTL)
{
d = EBidiDir::RTL;
lastStrong = EBidiDir::RTL;
}
else if (cd == ECharDir::LTR)
{
d = EBidiDir::LTR;
lastStrong = EBidiDir::LTR;
}
else
{
// Pass cache for O(1) lookup instead of O(n) scan
d = ResolveNeutralDir(s, n, i, base, lastStrong, &strongCache);
}
#ifdef DEBUG_BIDI
if (i < 50) // Only log first 50 chars to avoid spam
{
BIDI_LOG("Char[%d] U+%04X '%lc' → CharDir=%s, RunDir=%s",
i, (unsigned int)ch, (ch >= 32 && ch < 127) ? ch : L'?',
cd == ECharDir::RTL ? "RTL" : (cd == ECharDir::LTR ? "LTR" : "Neutral"),
d == EBidiDir::RTL ? "RTL" : "LTR");
}
#endif
push_run(d);
runs.back().text.push_back(ch);
}
// 3) shape RTL runs in logical order (Arabic shaping)
for (auto& r : runs)
{
if (r.dir != EBidiDir::RTL)
continue;
if (r.text.empty())
continue;
// Check for potential integer overflow before allocation
if (r.text.size() > SIZE_MAX / ARABIC_SHAPING_EXPANSION_FACTOR_RETRY - ARABIC_SHAPING_SAFETY_MARGIN_RETRY)
{
BIDI_LOG("BuildVisualBidiText: RTL run too large for shaping (%zu chars)", r.text.size());
continue; // Text too large to process safely
}
std::vector<wchar_t> shaped(r.text.size() * ARABIC_SHAPING_EXPANSION_FACTOR + ARABIC_SHAPING_SAFETY_MARGIN, 0);
int outLen = Arabic_MakeShape(r.text.data(), (int)r.text.size(), shaped.data(), (int)shaped.size());
if (outLen <= 0)
{
BIDI_LOG("Arabic_MakeShape FAILED for RTL run of %zu characters", r.text.size());
BIDI_LOG(" WARNING: This RTL text segment will NOT be displayed!");
BIDI_LOG(" First few characters: U+%04X U+%04X U+%04X U+%04X",
r.text.size() > 0 ? (unsigned int)r.text[0] : 0,
r.text.size() > 1 ? (unsigned int)r.text[1] : 0,
r.text.size() > 2 ? (unsigned int)r.text[2] : 0,
r.text.size() > 3 ? (unsigned int)r.text[3] : 0);
continue;
}
// Retry once if buffer too small
if (outLen >= (int)shaped.size())
{
shaped.assign(r.text.size() * ARABIC_SHAPING_EXPANSION_FACTOR_RETRY + ARABIC_SHAPING_SAFETY_MARGIN_RETRY, 0);
outLen = Arabic_MakeShape(r.text.data(), (int)r.text.size(), shaped.data(), (int)shaped.size());
if (outLen <= 0)
continue;
// Add error check instead of silent truncation
if (outLen > (int)shaped.size())
{
BIDI_LOG("Arabic_MakeShape: Buffer still too small after retry (%d > %zu)", outLen, shaped.size());
// Shaping failed critically, use unshaped text
continue;
}
}
r.text.assign(shaped.begin(), shaped.begin() + outLen);
}
// 4) produce visual order:
// - reverse RTL runs internally
// - reverse run sequence if base RTL
std::vector<wchar_t> visual;
visual.reserve((size_t)n);
auto emit_run = [&](const TBidiRun& r)
{
if (r.dir == EBidiDir::RTL)
{
for (int k = (int)r.text.size() - 1; k >= 0; --k)
visual.push_back(r.text[(size_t)k]);
}
else
{
visual.insert(visual.end(), r.text.begin(), r.text.end());
}
};
if (base == EBidiDir::LTR)
{
for (const auto& r : runs)
emit_run(r);
}
else
{
for (int i = (int)runs.size() - 1; i >= 0; --i)
emit_run(runs[(size_t)i]);
}
return visual;
}
// ============================================================================
// Chat Message BiDi Processing (Separate name/message handling)
// ============================================================================
// Build visual BiDi text for chat messages with separate name and message
// This avoids fragile " : " detection and handles cases where username contains " : "
//
// RECOMMENDED USAGE:
// Instead of: SetValue("PlayerName : Message")
// Use this function with separated components:
// - name: "PlayerName" (without " : ")
// - msg: "Message" (without " : ")
//
// INTEGRATION NOTES:
// To use this properly, you need to:
// 1. Modify the server/network code to send chat name and message separately
// 2. Or parse the chat string in PythonNetworkStreamPhaseGame.cpp BEFORE passing to GrpTextInstance
// 3. Then call this function instead of BuildVisualBidiText_Tagless
//
static inline std::vector<wchar_t> BuildVisualChatMessage(
const wchar_t* name, int nameLen,
const wchar_t* msg, int msgLen,
bool forceRTL)
{
if (!name || !msg || nameLen <= 0 || msgLen <= 0)
return {};
// Check if message contains RTL or hyperlink tags
bool msgHasRTL = false;
bool msgHasTags = false;
for (int i = 0; i < msgLen; ++i)
{
if (IsRTLCodepoint(msg[i]))
msgHasRTL = true;
if (msg[i] == L'|')
msgHasTags = true;
if (msgHasRTL && msgHasTags)
break;
}
// Build result based on UI direction (pre-reserve exact size)
std::vector<wchar_t> visual;
visual.reserve((size_t)(nameLen + msgLen + 3)); // +3 for " : "
// Decision: UI direction determines order (for visual consistency)
// RTL UI: "Message : Name" (message on right, consistent with RTL reading flow)
// LTR UI: "Name : Message" (name on left, consistent with LTR reading flow)
if (forceRTL)
{
// RTL UI: "Message : Name"
// Don't apply BiDi if message has tags (hyperlinks are pre-formatted)
if (msgHasTags)
{
visual.insert(visual.end(), msg, msg + msgLen);
}
else
{
// Apply BiDi to message with auto-detection (don't force RTL)
// Let the BiDi algorithm detect base direction from first strong character
std::vector<wchar_t> msgVisual = BuildVisualBidiText_Tagless(msg, msgLen, false);
visual.insert(visual.end(), msgVisual.begin(), msgVisual.end());
}
visual.push_back(L' ');
visual.push_back(L':');
visual.push_back(L' ');
visual.insert(visual.end(), name, name + nameLen); // Name on left side
}
else
{
// LTR UI: "Name : Message"
visual.insert(visual.end(), name, name + nameLen); // Name on left side
visual.push_back(L' ');
visual.push_back(L':');
visual.push_back(L' ');
// Don't apply BiDi if message has tags (hyperlinks are pre-formatted)
if (msgHasTags)
{
visual.insert(visual.end(), msg, msg + msgLen);
}
else
{
// Apply BiDi to message with auto-detection (don't force RTL)
// Let the BiDi algorithm detect base direction from first strong character
std::vector<wchar_t> msgVisual = BuildVisualBidiText_Tagless(msg, msgLen, false);
visual.insert(visual.end(), msgVisual.begin(), msgVisual.end());
}
}
return visual;
}
// ============================================================================
// TextTail formatting for RTL UI
// ============================================================================
enum class EPlaceDir
{
Left, // place block to the LEFT of the cursor (cursor is a right edge)
Right // place block to the RIGHT of the cursor (cursor is a left edge)
};
template <typename TText>
inline float TextTailBiDi(TText* t, float cursorX, float y, float z, float fxAdd, EPlaceDir dir)
{
if (!t)
return cursorX;
int w = 0, h = 0;
t->GetTextSize(&w, &h);
const float fw = static_cast<float>(w);
float x;
if (dir == EPlaceDir::Left)
{
x = t->IsRTL() ? cursorX : (cursorX - fw);
// advance cursor left
cursorX = cursorX - fw - fxAdd;
}
else
{
x = t->IsRTL() ? (cursorX + fw) : cursorX;
// advance cursor right
cursorX = cursorX + fw + fxAdd;
}
// SNAP to pixel grid to avoid "broken pixels"
x = floorf(x + 0.5f);
y = floorf(y + 0.5f);
t->SetPosition(x, y, z);
t->Update();
return cursorX;
}

View File

@@ -1,6 +1,5 @@
add_subdirectory(DirectX)
add_subdirectory(Granny)
add_subdirectory(MilesSoundSystem)
add_subdirectory(Python)
add_subdirectory(SpeedTree)
add_subdirectory(WebView)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,6 +0,0 @@
add_library(MilesSoundSystem STATIC IMPORTED GLOBAL)
set_target_properties(MilesSoundSystem PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/extern/include"
IMPORTED_LOCATION "${CMAKE_CURRENT_LIST_DIR}/mss64.lib"
)

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ea999a3c3f5e22bea81b4f2658dfbe074fa1c63d3073de789735fc383cbe0f05
size 3145894

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,10 @@
file(GLOB_RECURSE FILE_SOURCES "*.h" "*.c" "*.cpp")
add_library(AudioLib STATIC ${FILE_SOURCES})
target_link_libraries(AudioLib
cryptopp-static
mio
)
GroupSourcesByFolder(AudioLib)

View File

@@ -0,0 +1,177 @@
#include "stdafx.h"
#include "MaSoundInstance.h"
#include <miniaudio.c>
bool MaSoundInstance::InitFromBuffer(ma_engine& engine, const std::vector<uint8_t>& buffer, const std::string& identity)
{
if (!m_Initialized)
{
ma_decoder_config decoderConfig = ma_decoder_config_init_default();
ma_result result = ma_decoder_init_memory(buffer.data(), buffer.size(),
&decoderConfig, &m_Decoder);
if (!MD_ASSERT(result == MA_SUCCESS))
{
TraceError("Failed to initialize decoder memory.");
return false;
}
ma_sound_config soundConfig = ma_sound_config_init();
soundConfig.pDataSource = &m_Decoder;
result = ma_sound_init_ex(&engine, &soundConfig, &m_Sound);
if (!MD_ASSERT(result == MA_SUCCESS))
{
TraceError("Failed to initialize sound.");
return false;
}
m_Identity = identity;
m_Initialized = true;
}
return m_Initialized;
}
// Basically c&p
bool MaSoundInstance::InitFromFile(ma_engine& engine, const std::string& filePathOnDisk)
{
if (!m_Initialized)
{
ma_decoder_config decoderConfig = ma_decoder_config_init_default();
ma_result result = ma_decoder_init_file(filePathOnDisk.c_str(), &decoderConfig, &m_Decoder);
if (!MD_ASSERT(result == MA_SUCCESS))
{
TraceError("Failed to initialize sound file decoder.");
return false;
}
ma_sound_config soundConfig = ma_sound_config_init();
soundConfig.pDataSource = &m_Decoder;
result = ma_sound_init_ex(&engine, &soundConfig, &m_Sound);
if (!MD_ASSERT(result == MA_SUCCESS))
{
TraceError("Failed to initialize sound.");
return false;
}
m_Identity = filePathOnDisk;
m_Initialized = true;
}
return m_Initialized;
}
void MaSoundInstance::Destroy()
{
if (m_Initialized)
{
ma_sound_uninit(&m_Sound);
ma_decoder_uninit(&m_Decoder);
}
m_Initialized = false;
m_Identity = "";
m_FadeTargetVolume = 0.0f;
m_FadeRatePerFrame = 0.0f;
}
bool MaSoundInstance::IsInitialized() const
{
return m_Initialized;
}
bool MaSoundInstance::IsPlaying() const
{
return ma_sound_is_playing(&m_Sound) == MA_TRUE;
}
bool MaSoundInstance::Play()
{
return m_Initialized && ma_sound_seek_to_pcm_frame(&m_Sound, 0) == MA_SUCCESS && ma_sound_start(&m_Sound) == MA_SUCCESS;
}
bool MaSoundInstance::Resume()
{
return m_Initialized && ma_sound_start(&m_Sound) == MA_SUCCESS;
}
bool MaSoundInstance::Stop()
{
return m_Initialized && ma_sound_stop(&m_Sound) == MA_SUCCESS;
}
void MaSoundInstance::Loop()
{
ma_sound_set_looping(&m_Sound, MA_TRUE);
}
float MaSoundInstance::GetVolume() const
{
return ma_sound_get_volume(&m_Sound);
}
void MaSoundInstance::SetVolume(float volume)
{
ma_sound_set_volume(&m_Sound, volume);
}
void MaSoundInstance::SetPitch(float pitch)
{
ma_sound_set_pitch(&m_Sound, pitch);
}
void MaSoundInstance::SetPosition(float x, float y, float z)
{
ma_sound_set_position(&m_Sound, x, y, z);
}
const std::string& MaSoundInstance::GetIdentity() const
{
return m_Identity;
}
void MaSoundInstance::Config3D(bool toggle, float minDist, float maxDist)
{
ma_sound_set_spatialization_enabled(&m_Sound, toggle);
ma_sound_set_rolloff(&m_Sound, 1.0f);
ma_sound_set_min_distance(&m_Sound, minDist);
ma_sound_set_max_distance(&m_Sound, maxDist);
ma_sound_set_attenuation_model(&m_Sound, ma_attenuation_model_linear);
}
void MaSoundInstance::Fade(float toVolume, float secDurationFromMinMax)
{
m_FadeTargetVolume = std::clamp<float>(toVolume, 0.0f, 1.0f);
if (m_FadeTargetVolume != GetVolume())
{
const float rate = 1.0f / CS_CLIENT_FPS / secDurationFromMinMax;
m_FadeRatePerFrame = GetVolume() > m_FadeTargetVolume ? -rate : rate;
}
}
void MaSoundInstance::StopFading()
{
m_FadeRatePerFrame = 0.0f;
m_FadeTargetVolume = 0.0f;
}
bool MaSoundInstance::IsFading() const
{
return m_FadeRatePerFrame != 0.0f;
}
void MaSoundInstance::Update()
{
if (m_FadeRatePerFrame != 0.0f)
{
float targetVolume = std::clamp<float>(m_FadeTargetVolume, 0.0f, 1.0f);
float volume = std::clamp<float>(GetVolume() + m_FadeRatePerFrame, 0.0f, 1.0f);
if ((m_FadeRatePerFrame > 0.0f && volume >= targetVolume) || (m_FadeRatePerFrame < 0.0f && volume <= targetVolume))
{
volume = m_FadeTargetVolume;
m_FadeRatePerFrame = 0.0f;
if (m_FadeTargetVolume <= 0.0f)
ma_sound_stop(&m_Sound);
}
ma_sound_set_volume(&m_Sound, volume);
}
}

View File

@@ -0,0 +1,57 @@
#pragma once
#define MA_NO_WASAPI
#define MA_ENABLE_DSOUND
#define MA_ENABLE_WINMM
#include <miniaudio.h>
inline constexpr float CS_CLIENT_FPS = 61.0f;
class MaSoundInstance
{
public:
bool InitFromBuffer(ma_engine& engine, const std::vector<uint8_t>& buffer, const std::string& identity);
bool InitFromFile(ma_engine& engine, const std::string& filePathOnDisk);
void Destroy();
bool IsInitialized() const;
bool IsPlaying() const;
bool Play();
bool Resume();
bool Stop();
void Loop();
float GetVolume() const;
void SetVolume(float volume);
void SetPitch(float pitch);
void SetPosition(float x, float y, float z);
const std::string& GetIdentity() const;
void Config3D(bool toggle, float minDist = 100.0f/*1m*/, float maxDist = 4000.0f/*40m*/);
void Fade(float toVolume, float secDurationFromMinMax);
void StopFading();
bool IsFading() const;
void Update();
private:
std::string m_Identity;
ma_sound m_Sound{};
ma_decoder m_Decoder{};
bool m_Initialized{};
float m_FadeTargetVolume{};
float m_FadeRatePerFrame{};
};

View File

@@ -0,0 +1,258 @@
#include "stdafx.h"
#include "SoundEngine.h"
#include "EterBase/Random.h"
#include "EterBase/Timer.h"
#include "PackLib/PackManager.h"
SoundEngine::SoundEngine()
{
}
SoundEngine::~SoundEngine()
{
for (auto& [name, instance] : m_Sounds2D)
instance.Destroy();
for (auto& instance : m_Sounds3D)
instance.Destroy();
ma_engine_uninit(&m_Engine);
m_Files.clear();
m_Sounds2D.clear();
}
bool SoundEngine::Initialize()
{
if (!MD_ASSERT(ma_engine_init(NULL, &m_Engine) == MA_SUCCESS))
{
TraceError("SoundEngine::Initialize: Failed to initialize engine.");
return false;
}
ma_engine_listener_set_position(&m_Engine, 0, 0, 0, 0); // engine
SetListenerPosition(0.0f, 0.0f, 0.0f); // character
SetListenerOrientation(0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f);
return true;
}
void SoundEngine::SetSoundVolume(float volume)
{
m_SoundVolume = std::clamp<float>(volume, 0.0, 1.0);
}
bool SoundEngine::PlaySound2D(const std::string& name)
{
if (!Internal_LoadSoundFromPack(name))
return false;
auto& instance = m_Sounds2D[name]; // 2d sounds are persistent, no need to destroy
instance.InitFromBuffer(m_Engine, m_Files[name], name);
instance.Config3D(false);
instance.SetVolume(m_SoundVolume);
return instance.Play();
}
MaSoundInstance* SoundEngine::PlaySound3D(const std::string& name, float fx, float fy, float fz)
{
if (auto instance = Internal_GetInstance3D(name))
{
constexpr float minDist = 100.0f; // 1m
constexpr float maxDist = 5000.0f; // 50m
instance->SetPosition(fx - m_CharacterPosition.x,
fy - m_CharacterPosition.y,
fz - m_CharacterPosition.z);
instance->Config3D(true, minDist, maxDist);
instance->SetVolume(m_SoundVolume);
instance->Play();
return instance;
}
return nullptr;
}
MaSoundInstance* SoundEngine::PlayAmbienceSound3D(float fx, float fy, float fz, const std::string& name, int loopCount)
{
auto vec3 = ma_engine_listener_get_position(&m_Engine, 0);
float dx = fx - vec3.x;
float dy = fy - vec3.y;
float dz = fz - vec3.z;
float distance = sqrtf(dx * dx + dy * dy + dz * dz);
return PlaySound3D(name, fx, fy, fz);
}
void SoundEngine::StopAllSound3D()
{
for (auto& instance : m_Sounds3D)
instance.Stop();
}
void SoundEngine::UpdateSoundInstance(float fx, float fy, float fz, uint32_t dwcurFrame, const NSound::TSoundInstanceVector* c_pSoundInstanceVector, bool checkFrequency)
{
for (uint32_t i = 0; i < c_pSoundInstanceVector->size(); ++i)
{
const NSound::TSoundInstance& c_rSoundInstance = c_pSoundInstanceVector->at(i);
if (c_rSoundInstance.dwFrame == dwcurFrame)
{
if (checkFrequency)
{
float& lastPlay = m_PlaySoundHistoryMap[c_rSoundInstance.strSoundFileName];
float diff = CTimer::Instance().GetCurrentSecond() - lastPlay;
if (CTimer::Instance().GetCurrentSecond() - lastPlay < 0.3f)
return;
lastPlay = CTimer::Instance().GetCurrentSecond();
}
PlaySound3D(c_rSoundInstance.strSoundFileName, fx, fy, fz);
}
}
}
bool SoundEngine::FadeInMusic(const std::string& path, float targetVolume /* 1.0f by default */, float fadeInDurationSecondsFromMin)
{
if (path.empty())
return false;
auto& fadeOutMusic = m_Music[m_CurrentMusicIndex];
if (fadeOutMusic.IsPlaying() && path == fadeOutMusic.GetIdentity())
{
fadeOutMusic.Fade(targetVolume, fadeInDurationSecondsFromMin);
return fadeOutMusic.Resume();
}
// We're basically just swapping
FadeOutMusic(fadeOutMusic.GetIdentity());
m_CurrentMusicIndex = int(!m_CurrentMusicIndex);
auto& music = m_Music[m_CurrentMusicIndex];
music.Destroy();
music.InitFromFile(m_Engine, path);
music.Config3D(false);
music.Loop();
music.SetVolume(0.0f);
music.Fade(targetVolume, fadeInDurationSecondsFromMin);
return music.Play();
}
void SoundEngine::FadeOutMusic(const std::string& name, float targetVolume, float fadeOutDurationSecondsFromMax)
{
for (auto& music : m_Music)
{
if (music.GetIdentity() == name)
music.Fade(targetVolume, fadeOutDurationSecondsFromMax);
}
}
void SoundEngine::FadeOutAllMusic()
{
for (auto& music : m_Music)
FadeOutMusic(music.GetIdentity());
}
void SoundEngine::SetMusicVolume(float volume)
{
m_MusicVolume = std::clamp<float>(volume, 0.0f, 1.0f);
m_Music[m_CurrentMusicIndex].StopFading();
m_Music[m_CurrentMusicIndex].SetVolume(m_MusicVolume);
}
float SoundEngine::GetMusicVolume() const
{
return m_MusicVolume;
}
void SoundEngine::SaveVolume(bool isMinimized)
{
constexpr float ratePerSecond = 1.0f / CS_CLIENT_FPS;
// 1.0 to 0 in 1s if minimized, 3s if just out of focus
const float durationOnFullVolume = isMinimized ? 1.0f : 3.0f;
float outOfFocusVolume = 0.35f;
if (m_MasterVolume <= outOfFocusVolume)
outOfFocusVolume = m_MasterVolume;
m_MasterVolumeFadeTarget = isMinimized ? 0.0f : outOfFocusVolume;
m_MasterVolumeFadeRatePerFrame = -ratePerSecond / durationOnFullVolume;
}
void SoundEngine::RestoreVolume()
{
constexpr float ratePerSecond = 1.0f / CS_CLIENT_FPS;
constexpr float durationToFullVolume = 4.0f; // 0 to 1.0 in 4s
m_MasterVolumeFadeTarget = m_MasterVolume;
m_MasterVolumeFadeRatePerFrame = ratePerSecond / durationToFullVolume;
}
void SoundEngine::SetMasterVolume(float volume)
{
m_MasterVolume = volume;
ma_engine_set_volume(&m_Engine, volume);
}
void SoundEngine::SetListenerPosition(float x, float y, float z)
{
m_CharacterPosition.x = x;
m_CharacterPosition.y = y;
m_CharacterPosition.z = z;
}
void SoundEngine::SetListenerOrientation(float forwardX, float forwardY, float forwardZ,
float upX, float upY, float upZ)
{
ma_engine_listener_set_direction(&m_Engine, 0, forwardX, forwardY, -forwardZ);
ma_engine_listener_set_world_up(&m_Engine, 0, upX, -upY, upZ);
}
void SoundEngine::Update()
{
for (auto& music : m_Music)
music.Update();
if (m_MasterVolumeFadeRatePerFrame)
{
float volume = ma_engine_get_volume(&m_Engine) + m_MasterVolumeFadeRatePerFrame;
if ((m_MasterVolumeFadeRatePerFrame > 0.0f && volume >= m_MasterVolumeFadeTarget) || (m_MasterVolumeFadeRatePerFrame < 0.0f && volume <= m_MasterVolumeFadeTarget))
{
volume = m_MasterVolumeFadeTarget;
m_MasterVolumeFadeRatePerFrame = 0.0f;
}
ma_engine_set_volume(&m_Engine, volume);
}
}
MaSoundInstance* SoundEngine::Internal_GetInstance3D(const std::string& name)
{
if (Internal_LoadSoundFromPack(name))
{
for (auto& instance : m_Sounds3D)
{
if (!instance.IsPlaying())
{
instance.Destroy();
instance.InitFromBuffer(m_Engine, m_Files[name], name);
return &instance;
}
}
}
return nullptr;
}
bool SoundEngine::Internal_LoadSoundFromPack(const std::string& name)
{
if (m_Files.find(name) == m_Files.end())
{
TPackFile soundFile;
if (!CPackManager::Instance().GetFile(name, soundFile))
{
TraceError("Internal_LoadSoundFromPack: SoundEngine: Failed to register file '%s' - not found.", name.c_str());
return false;
}
auto& buffer = m_Files[name];
buffer.resize(soundFile.size());
memcpy(buffer.data(), soundFile.data(), soundFile.size());
}
return true;
}

View File

@@ -0,0 +1,98 @@
#pragma once
#include "EterBase/Singleton.h"
#include "Type.h"
#include "MaSoundInstance.h"
//#include <miniaudio.h>
#include <array>
#include <unordered_map>
struct SoundFile
{
std::string name;
std::vector<std::byte> buffer; // raw file data.
};
class SoundEngine : public CSingleton<SoundEngine>
{
public:
enum ESoundConfig
{
SOUND_INSTANCE_3D_MAX_NUM = 32,
};
// enum ESoundType
// {
// SOUND_TYPE_INTERFACE, // Interface sounds. Loaded on game opening, unloaded when the game ends.
// SOUND_TYPE_CHARACTER, // Character sounds(hit, damage, etc). Loaded on login, unloaded when the game ends.
// SOUND_TYPE_MONSTER, // monster attacks, hits, etc. Loaded and unloaded on warp
// SOUND_TYPE_AMBIENCE, // Wind, rain, birds, etc. Loaded and unloaded on warp
// SOUND_TYPE_MUSIC, // Bg music played on demand
// SOUND_TYPE_MAX_NUM,
// };
public:
SoundEngine();
~SoundEngine();
bool Initialize();
void SetSoundVolume(float volume);
bool PlaySound2D(const std::string& name);
MaSoundInstance* PlaySound3D(const std::string& name, float fx, float fy, float fz);
MaSoundInstance* PlayAmbienceSound3D(float fx, float fy, float fz, const std::string& name, int loopCount = 1);
void StopAllSound3D();
void UpdateSoundInstance(float fx, float fy, float fz, uint32_t dwcurFrame, const NSound::TSoundInstanceVector* c_pSoundInstanceVector, bool checkFrequency = false);
bool FadeInMusic(const std::string& path, float targetVolume = 1.0f, float fadeInDurationSecondsFromMin = 1.5f);
void FadeOutMusic(const std::string& name, float targetVolume = 0.0f, float fadeOutDurationSecondsFromMax = 1.5f);
void FadeOutAllMusic();
void SetMusicVolume(float volume);
float GetMusicVolume() const;
void SaveVolume(bool isMinimized);
void RestoreVolume();
void SetMasterVolume(float volume);
void SetListenerPosition(float x, float y, float z);
void SetListenerOrientation(float forwardX, float forwardY, float forwardZ,
float upX, float upY, float upZ);
void Update();
private:
MaSoundInstance* Internal_GetInstance3D(const std::string& name);
bool Internal_LoadSoundFromPack(const std::string& name);
private:
struct { float x, y, z; } m_CharacterPosition{};
ma_engine m_Engine{};
std::unordered_map<std::string, std::vector<uint8_t>> m_Files;
std::unordered_map<std::string, MaSoundInstance> m_Sounds2D;
std::array<MaSoundInstance, SOUND_INSTANCE_3D_MAX_NUM> m_Sounds3D;
std::unordered_map<std::string, float> m_PlaySoundHistoryMap;
// One song at a time, but holding both current and previous for graceful fading
std::array<MaSoundInstance, 2> m_Music;
int m_CurrentMusicIndex{};
float m_MusicVolume{ 1.0f };
float m_SoundVolume{ 1.0f };
float m_MasterVolume{ 1.0f };
float m_MasterVolumeFadeTarget{};
float m_MasterVolumeFadeRatePerFrame{};
};

9
src/AudioLib/Stdafx.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
//#include <windows.h>
#include "EterBase/CRC32.h"
#include "EterBase/Utils.h"
#include "EterBase/Debug.h"
#include <algorithm>

141
src/AudioLib/Type.cpp Normal file
View File

@@ -0,0 +1,141 @@
#include "StdAfx.h"
#include "Type.h"
#include "EterLib/TextFileLoader.h"
#include <utf8.h>
std::string NSound::strResult;
const char* NSound::GetResultString()
{
return strResult.c_str();
}
void NSound::SetResultString(const char* c_pszStr)
{
strResult.assign(c_pszStr);
}
bool NSound::LoadSoundInformationPiece(const char* c_szFileName, NSound::TSoundDataVector& rSoundDataVector, const char* c_szPathHeader)
{
std::string strResult;
strResult = c_szFileName;
CTextFileLoader* pkTextFileLoader = CTextFileLoader::Cache(c_szFileName);
if (!pkTextFileLoader)
return false;
CTextFileLoader& rkTextFileLoader = *pkTextFileLoader;
if (rkTextFileLoader.IsEmpty())
{
SetResultString((strResult + " Can not open file for reading").c_str());
return false;
}
rkTextFileLoader.SetTop();
int iCount;
if (!rkTextFileLoader.GetTokenInteger("sounddatacount", &iCount))
{
SetResultString((strResult + " File format error, SoundDataCount Unable to find.").c_str());
return false;
}
rSoundDataVector.clear();
rSoundDataVector.resize(iCount);
char szSoundDataHeader[32 + 1];
for (uint32_t i = 0; i < rSoundDataVector.size(); ++i)
{
_snprintf_s(szSoundDataHeader, sizeof(szSoundDataHeader), "sounddata%02d", i);
CTokenVector* pTokenVector;
if (!rkTextFileLoader.GetTokenVector(szSoundDataHeader, &pTokenVector))
{
SetResultString((strResult + " File format error: " + szSoundDataHeader + " Unable to find").c_str());
return false;
}
if (2 != pTokenVector->size())
{
SetResultString((strResult + " File format error: The size of the vector is not 2").c_str());
return false;
}
rSoundDataVector[i].fTime = (float)atof(pTokenVector->at(0).c_str());
if (c_szPathHeader)
{
rSoundDataVector[i].strSoundFileName = c_szPathHeader;
rSoundDataVector[i].strSoundFileName += pTokenVector->at(1).c_str();
}
else
{
rSoundDataVector[i].strSoundFileName = pTokenVector->at(1).c_str();
}
//TraceError("LoadSoundInformation %s -- %f -- %s", c_szFileName, rSoundDataVector[i].fTime, rSoundDataVector[i].strSoundFileName.c_str());
}
SetResultString((strResult + " Loaded").c_str());
return true;
}
bool NSound::SaveSoundInformationPiece(const char* c_szFileName, NSound::TSoundDataVector& rSoundDataVector)
{
if (rSoundDataVector.empty()) // If no data is considered success
{
if (IsFile(c_szFileName)) // If the data is empty but there is a file
{
_unlink(c_szFileName); // erase.
}
return true;
}
std::string strResult;
strResult = c_szFileName;
// UTF-8 → UTF-16 conversion for Unicode path support
std::wstring wFileName = Utf8ToWide(c_szFileName);
FILE* File = _wfopen(wFileName.c_str(), L"wt");
if (!File)
{
char szErrorText[256 + 1];
_snprintf_s(szErrorText, sizeof(szErrorText), "Failed to save file (%s).\nPlease check if it is read-only or you have no space on the disk.\n", c_szFileName);
LogBox(szErrorText, "Error");
SetResultString((strResult + " Cannot open file for writing").c_str());
return false;
}
fprintf(File, "ScriptType CharacterSoundInformation\n");
fprintf(File, "\n");
fprintf(File, "SoundDataCount %llu\n", rSoundDataVector.size());
for (uint32_t i = 0; i < rSoundDataVector.size(); ++i)
{
NSound::TSoundData& rSoundData = rSoundDataVector[i];
fprintf(File, "SoundData%02d %f \"%s\"\n", i, rSoundData.fTime, rSoundData.strSoundFileName.c_str());
}
fclose(File);
return true;
}
void NSound::DataToInstance(const TSoundDataVector& c_rSoundDataVector, TSoundInstanceVector* pSoundInstanceVector)
{
if (c_rSoundDataVector.empty())
return;
uint32_t dwFPS = 60;
const float c_fFrameTime = 1.0f / float(dwFPS);
pSoundInstanceVector->clear();
pSoundInstanceVector->resize(c_rSoundDataVector.size());
for (uint32_t i = 0; i < c_rSoundDataVector.size(); ++i)
{
const TSoundData& c_rSoundData = c_rSoundDataVector[i];
TSoundInstance& rSoundInstance = pSoundInstanceVector->at(i);
rSoundInstance.dwFrame = (uint32_t)(c_rSoundData.fTime / c_fFrameTime);
rSoundInstance.strSoundFileName = c_rSoundData.strSoundFileName;
}
}

29
src/AudioLib/Type.h Normal file
View File

@@ -0,0 +1,29 @@
#pragma once
#include <vector>
#include <string>
namespace NSound
{
extern std::string strResult;
typedef struct SSoundData
{
float fTime;
std::string strSoundFileName;
} TSoundData;
typedef struct SSoundInstance
{
uint32_t dwFrame;
std::string strSoundFileName;
} TSoundInstance;
typedef std::vector<TSoundData> TSoundDataVector;
typedef std::vector<TSoundInstance> TSoundInstanceVector;
bool LoadSoundInformationPiece(const char* c_szFileName, TSoundDataVector& rSoundDataVector, const char* c_szPathHeader = NULL);
bool SaveSoundInformationPiece(const char* c_szFileName, TSoundDataVector& rSoundDataVector);
void DataToInstance(const TSoundDataVector& c_rSoundDataVector, TSoundInstanceVector* pSoundInstanceVector);
const char* GetResultString();
void SetResultString(const char* c_pszStr);
};

View File

@@ -1,3 +1,4 @@
add_subdirectory(AudioLib)
add_subdirectory(Discord)
add_subdirectory(EffectLib)
add_subdirectory(EterBase)
@@ -5,12 +6,12 @@ add_subdirectory(EterGrnLib)
add_subdirectory(EterImageLib)
add_subdirectory(EterLib)
add_subdirectory(EterLocale)
add_subdirectory(EterPack)
add_subdirectory(EterPythonLib)
add_subdirectory(GameLib)
add_subdirectory(MilesLib)
add_subdirectory(PRTerrainLib)
add_subdirectory(ScriptLib)
add_subdirectory(SpeedTreeLib)
add_subdirectory(SphereLib)
add_subdirectory(UserInterface)
add_subdirectory(PackMaker)
add_subdirectory(PackLib)

View File

@@ -1,6 +1,5 @@
#include "connection.h"
#define WIN32_LEAN_AND_MEAN
#define NOMCX
#define NOSERVICE
#define NOIME

View File

@@ -1,7 +1,6 @@
#include "discord_rpc.h"
#include "discord_register.h"
#define WIN32_LEAN_AND_MEAN
#define NOMCX
#define NOSERVICE
#define NOIME
@@ -134,27 +133,36 @@ static void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* comma
extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command)
{
wchar_t appId[32];
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
int app = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, applicationId, -1, appId, 32);
if (app <= 0)
return;
wchar_t openCommand[1024];
const wchar_t* wcommand = nullptr;
if (command && command[0]) {
const auto commandBufferLen = sizeof(openCommand) / sizeof(*openCommand);
MultiByteToWideChar(CP_UTF8, 0, command, -1, openCommand, commandBufferLen);
int ok = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, command, -1, openCommand, commandBufferLen);
if (ok <= 0)
return;
wcommand = openCommand;
}
Discord_RegisterW(appId, wcommand);
}
extern "C" DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId,
const char* steamId)
extern "C" DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, const char* steamId)
{
wchar_t appId[32];
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
int app = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, applicationId, -1, appId, 32);
if (app <= 0)
return;
wchar_t wSteamId[32];
MultiByteToWideChar(CP_UTF8, 0, steamId, -1, wSteamId, 32);
int steam = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, steamId, -1, wSteamId, 32);
if (steam <= 0)
return;
HKEY key;
auto status = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", 0, KEY_READ, &key);

View File

@@ -3,7 +3,8 @@
add_library(EffectLib STATIC ${FILE_SOURCES})
target_link_libraries(EffectLib
lzo2
cryptopp-static
mio
)
GroupSourcesByFolder(EffectLib)

View File

@@ -96,7 +96,7 @@ bool CEffectData::LoadScript(const char * c_szFileName)
bool CEffectData::LoadSoundScriptData(const char * c_szFileName)
{
TSoundDataVector SoundDataVector;
NSound::TSoundDataVector SoundDataVector;
if (LoadSoundInformationPiece(c_szFileName, SoundDataVector))
{
@@ -164,7 +164,7 @@ CEffectMeshScript * CEffectData::GetMeshPointer(DWORD dwPosition)
return m_MeshVector[dwPosition];
}
TSoundInstanceVector * CEffectData::GetSoundInstanceVector()
NSound::TSoundInstanceVector * CEffectData::GetSoundInstanceVector()
{
return &m_SoundInstanceVector;
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include "../milesLib/Type.h"
#include "AudioLib/Type.h"
#include "ParticleSystemData.h"
#include "EffectMesh.h"
@@ -30,7 +30,7 @@ class CEffectData
DWORD GetLightCount();
CLightData * GetLightPointer(DWORD dwPosition);
TSoundInstanceVector * GetSoundInstanceVector();
NSound::TSoundInstanceVector * GetSoundInstanceVector();
float GetBoundingSphereRadius();
D3DXVECTOR3 GetBoundingSpherePosition();
@@ -52,7 +52,7 @@ class CEffectData
TParticleVector m_ParticleVector;
TMeshVector m_MeshVector;
TLightVector m_LightVector;
TSoundInstanceVector m_SoundInstanceVector;
NSound::TSoundInstanceVector m_SoundInstanceVector;
float m_fBoundingSphereRadius;
D3DXVECTOR3 m_v3BoundingSpherePosition;

View File

@@ -90,6 +90,14 @@ void CEffectElementBaseInstance::Destroy()
}
CEffectElementBaseInstance::CEffectElementBaseInstance()
: mc_pmatLocal(nullptr)
, m_isActive(false)
, m_fLocalTime(0.0f)
, m_dwStartTime(0)
, m_fElapsedTime(0.0f)
, m_fRemainingTime(0.0f)
, m_bStart(false)
, m_pBase(nullptr)
{
}
CEffectElementBaseInstance::~CEffectElementBaseInstance()

View File

@@ -3,9 +3,9 @@
#include "ParticleSystemInstance.h"
#include "SimpleLightInstance.h"
#include "../eterBase/Stl.h"
#include "../eterLib/StateManager.h"
#include "../MilesLib/SoundManager.h"
#include "EterBase/Stl.h"
#include "EterLib/StateManager.h"
#include "AudioLib/SoundEngine.h"
CDynamicPool<CEffectInstance> CEffectInstance::ms_kPool;
int CEffectInstance::ms_iRenderingEffectCount = 0;
@@ -50,12 +50,12 @@ void CEffectInstance::UpdateSound()
{
if (m_pSoundInstanceVector)
{
UpdateSoundInstance(m_dwFrame,
*m_pSoundInstanceVector,
m_matGlobal._41,
m_matGlobal._42,
m_matGlobal._43,
false);
SoundEngine::Instance().UpdateSoundInstance(m_matGlobal._41,
m_matGlobal._42,
m_matGlobal._43,
m_dwFrame,
m_pSoundInstanceVector,
false);
// NOTE : 매트릭스에서 위치를 직접 얻어온다 - [levites]
}
++m_dwFrame;
@@ -80,11 +80,7 @@ void CEffectInstance::OnUpdate()
{
Transform();
#ifdef WORLD_EDITOR
FEffectUpdator f(CTimer::Instance().GetElapsedSecond());
#else
FEffectUpdator f(CTimer::Instance().GetCurrentSecond()-m_fLastTime);
#endif
f = std::for_each(m_ParticleInstanceVector.begin(), m_ParticleInstanceVector.end(),f);
f = std::for_each(m_MeshInstanceVector.begin(), m_MeshInstanceVector.end(),f);
f = std::for_each(m_LightInstanceVector.begin(), m_LightInstanceVector.end(),f);
@@ -95,7 +91,7 @@ void CEffectInstance::OnUpdate()
void CEffectInstance::OnRender()
{
STATEMANAGER.SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
STATEMANAGER.SetFVF(D3DFVF_XYZ | D3DFVF_TEX1);
STATEMANAGER.SaveSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_NONE);
STATEMANAGER.SaveSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_NONE);
@@ -106,30 +102,19 @@ void CEffectInstance::OnRender()
STATEMANAGER.SaveRenderState(D3DRS_ALPHATESTENABLE, FALSE);
STATEMANAGER.SaveRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
STATEMANAGER.SaveRenderState(D3DRS_ZWRITEENABLE, FALSE);
STATEMANAGER.SaveRenderState(D3DRS_LIGHTING, FALSE);
/////
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
std::for_each(m_ParticleInstanceVector.begin(),m_ParticleInstanceVector.end(),std::mem_fn(&CEffectElementBaseInstance::Render));
STATEMANAGER.SetFVF(D3DFVF_XYZ | D3DFVF_TEX1);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
std::for_each(m_ParticleInstanceVector.begin(),m_ParticleInstanceVector.end(),std::mem_fn(&CEffectElementBaseInstance::Render));
std::for_each(m_MeshInstanceVector.begin(),m_MeshInstanceVector.end(),std::mem_fn(&CEffectElementBaseInstance::Render));
/////
STATEMANAGER.RestoreSamplerState(0, D3DSAMP_MINFILTER);
STATEMANAGER.RestoreSamplerState(0, D3DSAMP_MAGFILTER);
@@ -139,7 +124,6 @@ void CEffectInstance::OnRender()
STATEMANAGER.RestoreRenderState(D3DRS_ALPHATESTENABLE);
STATEMANAGER.RestoreRenderState(D3DRS_CULLMODE);
STATEMANAGER.RestoreRenderState(D3DRS_ZWRITEENABLE);
STATEMANAGER.RestoreRenderState(D3DRS_LIGHTING);
++ms_iRenderingEffectCount;
}
@@ -283,18 +267,10 @@ void CEffectInstance::Clear()
__Initialize();
}
void CEffectInstance::BatchParticles()
{
std::for_each(m_ParticleInstanceVector.begin(), m_ParticleInstanceVector.end(), std::mem_fn(&CParticleSystemInstance::BatchParticles));
}
void CEffectInstance::RenderMeshes()
{
std::for_each(m_MeshInstanceVector.begin(), m_MeshInstanceVector.end(), std::mem_fn(&CEffectElementBaseInstance::Render));
}
void CEffectInstance::__Initialize()
{
ReleaseAlwaysHidden();
m_isAlive = FALSE;
m_dwFrame = 0;
m_pSoundInstanceVector = NULL;

View File

@@ -1,9 +1,10 @@
#pragma once
#include "UserInterface/Locale_inc.h"
#include "Eterlib/GrpObjectInstance.h"
#include "Eterlib/Pool.h"
#include "Mileslib/Type.h"
#include "AudioLib/Type.h"
#include "StdAfx.h"
#include "EffectElementBaseInstance.h"
#include "EffectData.h"
#include "EffectMeshInstance.h"
@@ -41,6 +42,12 @@ class CEffectInstance : public CGraphicObjectInstance
bool LessRenderOrder(CEffectInstance* pkEftInst);
void SetEffectDataPointer(CEffectData * pEffectData);
// Returns the pointer to the effect data associated with this instance.
CEffectData* GetEffectDataPointer() const
{
return m_pkEftData;
}
void Clear();
BOOL isAlive();
@@ -55,9 +62,6 @@ class CEffectInstance : public CGraphicObjectInstance
void OnRenderShadow() {} // Not used
void OnRenderPCBlocker() {} // Not used
void BatchParticles();
void RenderMeshes();
protected:
void __Initialize();
@@ -80,7 +84,7 @@ class CEffectInstance : public CGraphicObjectInstance
std::vector<CEffectMeshInstance*> m_MeshInstanceVector;
std::vector<CLightInstance*> m_LightInstanceVector;
TSoundInstanceVector * m_pSoundInstanceVector;
NSound::TSoundInstanceVector * m_pSoundInstanceVector;
float m_fBoundingSphereRadius;
D3DXVECTOR3 m_v3BoundingSpherePosition;
@@ -88,6 +92,7 @@ class CEffectInstance : public CGraphicObjectInstance
float m_fLastTime;
public:
static CDynamicPool<CEffectInstance> ms_kPool;
static int ms_iRenderingEffectCount;
};

View File

@@ -1,15 +1,13 @@
#include "StdAfx.h"
#include "../eterBase/Random.h"
#include "../eterlib/StateManager.h"
#include "EterBase/Random.h"
#include "Eterlib/StateManager.h"
#include "EffectManager.h"
extern std::unordered_map<LPDIRECT3DTEXTURE9, std::unordered_map<uint32_t, std::vector<TPDTVertex>>> g_particleVertexBatch;
void CEffectManager::GetInfo(std::string* pstInfo)
{
char szInfo[256];
sprintf(szInfo, "Effect: Inst - ED %d, EI %d Pool - PSI %d, MI %d, LI %d, PI %d, EI %d, ED %d, PSD %d, EM %d, LD %d",
sprintf(szInfo, "Effect: Inst - ED %zd, EI %zd Pool - PSI %zd, MI %zd, LI %zd, PI %zd, EI %zd, ED %zd, PSD %zd, EM %zd, LD %zd",
m_kEftDataMap.size(),
m_kEftInstMap.size(),
CParticleSystemInstance::ms_kPool.GetCapacity(),
@@ -82,15 +80,50 @@ void CEffectManager::Update()
}
}
struct CEffectManager_LessEffectInstancePtrRenderOrder
{
bool operator() (CEffectInstance* pkLeft, CEffectInstance* pkRight)
{
return pkLeft->LessRenderOrder(pkRight);
}
};
struct CEffectManager_FEffectInstanceRender
{
inline void operator () (CEffectInstance * pkEftInst)
{
pkEftInst->Render();
}
};
void CEffectManager::Render()
{
STATEMANAGER.SetTexture(0, NULL);
STATEMANAGER.SetTexture(1, NULL);
if (m_isDisableSortRendering)
{
for (TEffectInstanceMap::iterator itor = m_kEftInstMap.begin(); itor != m_kEftInstMap.end();)
{
CEffectInstance * pEffectInstance = itor->second;
pEffectInstance->Render();
++itor;
}
}
else
{
static std::vector<CEffectInstance*> s_kVct_pkEftInstSort;
s_kVct_pkEftInstSort.clear();
g_particleVertexBatch.clear();
TEffectInstanceMap& rkMap_pkEftInstSrc=m_kEftInstMap;
TEffectInstanceMap::iterator i;
for (i=rkMap_pkEftInstSrc.begin(); i!=rkMap_pkEftInstSrc.end(); ++i)
s_kVct_pkEftInstSort.push_back(i->second);
__RenderParticles();
__RenderMeshes();
std::sort(s_kVct_pkEftInstSort.begin(), s_kVct_pkEftInstSort.end(), CEffectManager_LessEffectInstancePtrRenderOrder());
std::for_each(s_kVct_pkEftInstSort.begin(), s_kVct_pkEftInstSort.end(), CEffectManager_FEffectInstanceRender());
}
}
BOOL CEffectManager::RegisterEffect(const char * c_szFileName,bool isExistDelete,bool isNeedCache)
@@ -318,6 +351,33 @@ void CEffectManager::HideEffect()
m_pSelectedEffectInstance->Hide();
}
// MR-5: Fix effect rendering when actor is semi-transparent
// Credits to d1str4ught
void CEffectManager::RenderEffect()
{
if (!m_pSelectedEffectInstance)
return;
m_pSelectedEffectInstance->Render();
}
// MR-5: -- END OF -- Fix effect rendering when actor is semi-transparent
void CEffectManager::ApplyAlwaysHidden()
{
if (!m_pSelectedEffectInstance)
return;
m_pSelectedEffectInstance->ApplyAlwaysHidden();
}
void CEffectManager::ReleaseAlwaysHidden()
{
if (!m_pSelectedEffectInstance)
return;
m_pSelectedEffectInstance->ReleaseAlwaysHidden();
}
bool CEffectManager::GetEffectData(DWORD dwID, CEffectData ** ppEffect)
{
TEffectDataMap::iterator itor = m_kEftDataMap.find(dwID);
@@ -404,122 +464,6 @@ void CEffectManager::__DestroyEffectDataMap()
m_kEftDataMap.clear();
}
void CEffectManager::__RenderParticles()
{
STATEMANAGER.SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
STATEMANAGER.SaveSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_NONE);
STATEMANAGER.SaveSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_NONE);
STATEMANAGER.SaveRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
STATEMANAGER.SaveRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
STATEMANAGER.SaveRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
STATEMANAGER.SaveRenderState(D3DRS_ALPHATESTENABLE, FALSE);
STATEMANAGER.SaveRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
STATEMANAGER.SaveRenderState(D3DRS_ZWRITEENABLE, FALSE);
STATEMANAGER.SaveRenderState(D3DRS_LIGHTING, FALSE);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
for (auto itor = m_kEftInstMap.begin(); itor != m_kEftInstMap.end(); ++itor) {
itor->second->BatchParticles();
}
for (auto& [pTexture, keyMap] : g_particleVertexBatch) {
if (keyMap.empty())
continue;
STATEMANAGER.SetTexture(0, pTexture);
for (auto& [opKey, vtxBatch] : keyMap) {
if (vtxBatch.empty())
continue;
uint8_t* pKeyPart = (uint8_t*)&opKey;
STATEMANAGER.SetRenderState(D3DRS_SRCBLEND, pKeyPart[0]);
STATEMANAGER.SetRenderState(D3DRS_DESTBLEND, pKeyPart[1]);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, pKeyPart[2]);
STATEMANAGER.DrawPrimitiveUP(
D3DPT_TRIANGLELIST,
vtxBatch.size() / 3,
vtxBatch.data(),
sizeof(TPDTVertex));
}
}
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_COLORARG1);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_COLORARG2);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_COLOROP);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_ALPHAARG1);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_ALPHAARG2);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_ALPHAOP);
STATEMANAGER.RestoreSamplerState(0, D3DSAMP_MINFILTER);
STATEMANAGER.RestoreSamplerState(0, D3DSAMP_MAGFILTER);
STATEMANAGER.RestoreRenderState(D3DRS_ALPHABLENDENABLE);
STATEMANAGER.RestoreRenderState(D3DRS_SRCBLEND);
STATEMANAGER.RestoreRenderState(D3DRS_DESTBLEND);
STATEMANAGER.RestoreRenderState(D3DRS_ALPHATESTENABLE);
STATEMANAGER.RestoreRenderState(D3DRS_CULLMODE);
STATEMANAGER.RestoreRenderState(D3DRS_ZWRITEENABLE);
STATEMANAGER.RestoreRenderState(D3DRS_LIGHTING);
}
void CEffectManager::__RenderMeshes()
{
STATEMANAGER.SetFVF(D3DFVF_XYZ | D3DFVF_TEX1);
STATEMANAGER.SaveSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_NONE);
STATEMANAGER.SaveSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_NONE);
STATEMANAGER.SaveRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
STATEMANAGER.SaveRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
STATEMANAGER.SaveRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
STATEMANAGER.SaveRenderState(D3DRS_ALPHATESTENABLE, FALSE);
STATEMANAGER.SaveRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
STATEMANAGER.SaveRenderState(D3DRS_ZWRITEENABLE, FALSE);
STATEMANAGER.SaveRenderState(D3DRS_LIGHTING, FALSE);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
STATEMANAGER.SaveTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
for (auto itor = m_kEftInstMap.begin(); itor != m_kEftInstMap.end(); ++itor) {
itor->second->RenderMeshes();
}
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_COLORARG1);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_COLORARG2);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_COLOROP);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_ALPHAARG1);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_ALPHAARG2);
STATEMANAGER.RestoreTextureStageState(0, D3DTSS_ALPHAOP);
STATEMANAGER.RestoreSamplerState(0, D3DSAMP_MINFILTER);
STATEMANAGER.RestoreSamplerState(0, D3DSAMP_MAGFILTER);
STATEMANAGER.RestoreRenderState(D3DRS_ALPHABLENDENABLE);
STATEMANAGER.RestoreRenderState(D3DRS_SRCBLEND);
STATEMANAGER.RestoreRenderState(D3DRS_DESTBLEND);
STATEMANAGER.RestoreRenderState(D3DRS_ALPHATESTENABLE);
STATEMANAGER.RestoreRenderState(D3DRS_CULLMODE);
STATEMANAGER.RestoreRenderState(D3DRS_ZWRITEENABLE);
STATEMANAGER.RestoreRenderState(D3DRS_LIGHTING);
}
void CEffectManager::Destroy()
{
__DestroyEffectInstanceMap();
@@ -545,5 +489,26 @@ CEffectManager::~CEffectManager()
Destroy();
}
DWORD CEffectManager::GetSelectedEffectDataCRC() const
{
if (!m_pSelectedEffectInstance)
return 0;
CEffectData* pData = m_pSelectedEffectInstance->GetEffectDataPointer();
if (!pData)
return 0;
const char* cszFile = pData->GetFileName();
if (!cszFile || !cszFile[0])
return 0;
std::string str;
StringPath(cszFile, str);
return GetCaseCRC32(str.c_str(), (int)str.length());
}
// just for map effect

View File

@@ -1,5 +1,6 @@
#pragma once
#include "StdAfx.h"
#include "EffectInstance.h"
class CEffectManager : public CScreen, public CSingleton<CEffectManager>
@@ -55,6 +56,13 @@ class CEffectManager : public CScreen, public CSingleton<CEffectManager>
void ShowEffect();
void HideEffect();
// MR-5: Fix effect rendering when actor is semi-transparent
// Credits to d1str4ught
void RenderEffect();
// MR-5: -- END OF -- Fix effect rendering when actor is semi-transparent
void ApplyAlwaysHidden();
void ReleaseAlwaysHidden();
// Temporary function
DWORD GetRandomEffect();
@@ -69,6 +77,9 @@ class CEffectManager : public CScreen, public CSingleton<CEffectManager>
int GetRenderingEffectCount();
// Return the CRC of the effect-data for the selected effect instance.
DWORD GetSelectedEffectDataCRC() const;
protected:
void __Initialize();
@@ -76,9 +87,6 @@ class CEffectManager : public CScreen, public CSingleton<CEffectManager>
void __DestroyEffectCacheMap();
void __DestroyEffectDataMap();
void __RenderParticles();
void __RenderMeshes();
protected:
bool m_isDisableSortRendering;
TEffectDataMap m_kEftDataMap;

View File

@@ -1,7 +1,7 @@
#include "StdAfx.h"
#include "../eterlib/StateManager.h"
#include "../eterlib/ResourceManager.h"
#include "../eterpack/EterPackManager.h"
#include "Eterlib/StateManager.h"
#include "Eterlib/ResourceManager.h"
#include "PackLib/PackManager.h"
#include "EffectMesh.h"
CDynamicPool<CEffectMesh::SEffectMeshData> CEffectMesh::SEffectMeshData::ms_kPool;
@@ -192,15 +192,14 @@ BOOL CEffectMesh::__LoadData_Ver002(int iSize, const BYTE * c_pbBuf)
if (0 == strExtension.compare("ifl"))
{
LPCVOID pMotionData;
CMappedFile File;
TPackFile File;
if (CEterPackManager::Instance().Get(File, pMeshData->szDiffuseMapFileName, &pMotionData))
if (CPackManager::Instance().GetFile(pMeshData->szDiffuseMapFileName, File))
{
CMemoryTextFileLoader textFileLoader;
std::vector<std::string> stTokenVector;
textFileLoader.Bind(File.Size(), pMotionData);
textFileLoader.Bind(File.size(), File.data());
std::string strPathName;
GetOnlyPathName(pMeshData->szDiffuseMapFileName, strPathName);
@@ -337,15 +336,14 @@ BOOL CEffectMesh::__LoadData_Ver001(int iSize, const BYTE * c_pbBuf)
if (0 == strExtension.compare("ifl"))
{
LPCVOID pMotionData;
CMappedFile File;
TPackFile File;
if (CEterPackManager::Instance().Get(File, pMeshData->szDiffuseMapFileName, &pMotionData))
if (CPackManager::Instance().GetFile(pMeshData->szDiffuseMapFileName, File))
{
CMemoryTextFileLoader textFileLoader;
std::vector<std::string> stTokenVector;
textFileLoader.Bind(File.Size(), pMotionData);
textFileLoader.Bind(File.size(), File.data());
std::string strPathName;
GetOnlyPathName(pMeshData->szDiffuseMapFileName, strPathName);

View File

@@ -2,10 +2,10 @@
#include <d3dx9.h>
#include "../eterlib/GrpScreen.h"
#include "../eterlib/Resource.h"
#include "../eterlib/GrpImageInstance.h"
#include "../eterLib/TextFileLoader.h"
#include "Eterlib/GrpScreen.h"
#include "Eterlib/Resource.h"
#include "Eterlib/GrpImageInstance.h"
#include "EterLib/TextFileLoader.h"
#include "Type.h"
#include "EffectElementBase.h"

View File

@@ -1,8 +1,8 @@
#include "StdAfx.h"
#include "../eterLib/StateManager.h"
#include "../eterLib/ResourceManager.h"
#include "EterLib/StateManager.h"
#include "EterLib/ResourceManager.h"
#include "EffectMeshInstance.h"
#include "../eterlib/GrpMath.h"
#include "Eterlib/GrpMath.h"
CDynamicPool<CEffectMeshInstance> CEffectMeshInstance::ms_kPool;
@@ -167,7 +167,8 @@ void CEffectMeshInstance::OnRender()
}
Color.a = fAlpha * rFrameData.fVisibility;
STATEMANAGER.SetRenderState(D3DRS_TEXTUREFACTOR, Color);
STATEMANAGER.SetRenderState(D3DRS_TEXTUREFACTOR, DWORD(Color));
STATEMANAGER.SetFVF(D3DFVF_XYZ | D3DFVF_TEX1);
STATEMANAGER.DrawPrimitiveUP(D3DPT_TRIANGLELIST,
rFrameData.dwIndexCount/3,
&rFrameData.PDTVertexVector[0],

View File

@@ -1,7 +1,7 @@
#pragma once
#include "../eterlib/GrpScreen.h"
#include "../eterlib/GrpImageInstance.h"
#include "Eterlib/GrpScreen.h"
#include "Eterlib/GrpImageInstance.h"
#include "EffectElementBaseInstance.h"
#include "FrameController.h"
#include "EffectMesh.h"

View File

@@ -156,12 +156,6 @@ void CParticleInstance::UpdateColor(float time, float elapsedTime)
return;
m_Color = GetTimeEventBlendValue(time, m_pParticleProperty->m_TimeEventColor);
#ifdef ENABLE_BATCHED_PARTICLE_RENDERING
for (auto& vtx : m_ParticleMesh) {
vtx.diffuse = m_Color;
}
#endif
}
void CParticleInstance::UpdateGravity(float time, float elapsedTime)
@@ -185,10 +179,7 @@ void CParticleInstance::UpdateAirResistance(float time, float elapsedTime)
void CParticleInstance::Transform(const D3DXMATRIX * c_matLocal)
{
#ifndef ENABLE_BATCHED_PARTICLE_RENDERING
STATEMANAGER.SetRenderState(D3DRS_TEXTUREFACTOR, m_Color);
#endif
/////
D3DXVECTOR3 v3Up;
D3DXVECTOR3 v3Cross;
@@ -322,63 +313,24 @@ void CParticleInstance::Transform(const D3DXMATRIX * c_matLocal)
{
D3DXVECTOR3 v3Position;
D3DXVec3TransformCoord(&v3Position, &m_v3Position, c_matLocal);
D3DXVECTOR3 p0 = v3Position - v3Up + v3Cross; // bottom-left
D3DXVECTOR3 p1 = v3Position - v3Up - v3Cross; // bottom-right
D3DXVECTOR3 p2 = v3Position + v3Up + v3Cross; // top-left
D3DXVECTOR3 p3 = v3Position + v3Up - v3Cross; // top-right
#ifdef ENABLE_BATCHED_PARTICLE_RENDERING
// triangle 1: p0, p1, p2
m_ParticleMesh[0].position = p0;
m_ParticleMesh[1].position = p1;
m_ParticleMesh[2].position = p2;
// triangle 2: p2, p1, p3
m_ParticleMesh[3].position = p2;
m_ParticleMesh[4].position = p1;
m_ParticleMesh[5].position = p3;
#else
m_ParticleMesh[0].position = p0;
m_ParticleMesh[1].position = p1;
m_ParticleMesh[2].position = p2;
m_ParticleMesh[3].position = p3;
#endif
m_ParticleMesh[0].position = v3Position - v3Up + v3Cross;
m_ParticleMesh[1].position = v3Position - v3Up - v3Cross;
m_ParticleMesh[2].position = v3Position + v3Up + v3Cross;
m_ParticleMesh[3].position = v3Position + v3Up - v3Cross;
}
else
{
D3DXVECTOR3 p0 = m_v3Position - v3Up + v3Cross; // bottom-left
D3DXVECTOR3 p1 = m_v3Position - v3Up - v3Cross; // bottom-right
D3DXVECTOR3 p2 = m_v3Position + v3Up + v3Cross; // top-left
D3DXVECTOR3 p3 = m_v3Position + v3Up - v3Cross; // top-right
#ifdef ENABLE_BATCHED_PARTICLE_RENDERING
// triangle 1: p0, p1, p2
m_ParticleMesh[0].position = p0;
m_ParticleMesh[1].position = p1;
m_ParticleMesh[2].position = p2;
// triangle 2: p2, p1, p3
m_ParticleMesh[3].position = p2;
m_ParticleMesh[4].position = p1;
m_ParticleMesh[5].position = p3;
#else
m_ParticleMesh[0].position = p0;
m_ParticleMesh[1].position = p1;
m_ParticleMesh[2].position = p2;
m_ParticleMesh[3].position = p3;
#endif
m_ParticleMesh[0].position = m_v3Position - v3Up + v3Cross;
m_ParticleMesh[1].position = m_v3Position - v3Up - v3Cross;
m_ParticleMesh[2].position = m_v3Position + v3Up + v3Cross;
m_ParticleMesh[3].position = m_v3Position + v3Up - v3Cross;
}
}
void CParticleInstance::Transform(const D3DXMATRIX * c_matLocal, const float c_fZRotation)
{
#ifndef ENABLE_BATCHED_PARTICLE_RENDERING
STATEMANAGER.SetRenderState(D3DRS_TEXTUREFACTOR, m_Color);
#endif
/////
D3DXVECTOR3 v3Up;
D3DXVECTOR3 v3Cross;
@@ -510,52 +462,17 @@ void CParticleInstance::Transform(const D3DXMATRIX * c_matLocal, const float c_f
{
D3DXVECTOR3 v3Position;
D3DXVec3TransformCoord(&v3Position, &m_v3Position, c_matLocal);
D3DXVECTOR3 p0 = v3Position - v3Up + v3Cross; // bottom-left
D3DXVECTOR3 p1 = v3Position - v3Up - v3Cross; // bottom-right
D3DXVECTOR3 p2 = v3Position + v3Up + v3Cross; // top-left
D3DXVECTOR3 p3 = v3Position + v3Up - v3Cross; // top-right
#ifdef ENABLE_BATCHED_PARTICLE_RENDERING
// triangle 1: p0, p1, p2
m_ParticleMesh[0].position = p0;
m_ParticleMesh[1].position = p1;
m_ParticleMesh[2].position = p2;
// triangle 2: p2, p1, p3
m_ParticleMesh[3].position = p2;
m_ParticleMesh[4].position = p1;
m_ParticleMesh[5].position = p3;
#else
m_ParticleMesh[0].position = p0;
m_ParticleMesh[1].position = p1;
m_ParticleMesh[2].position = p2;
m_ParticleMesh[3].position = p3;
#endif
m_ParticleMesh[0].position = v3Position - v3Up + v3Cross;
m_ParticleMesh[1].position = v3Position - v3Up - v3Cross;
m_ParticleMesh[2].position = v3Position + v3Up + v3Cross;
m_ParticleMesh[3].position = v3Position + v3Up - v3Cross;
}
else
{
D3DXVECTOR3 p0 = m_v3Position - v3Up + v3Cross; // bottom-left
D3DXVECTOR3 p1 = m_v3Position - v3Up - v3Cross; // bottom-right
D3DXVECTOR3 p2 = m_v3Position + v3Up + v3Cross; // top-left
D3DXVECTOR3 p3 = m_v3Position + v3Up - v3Cross; // top-right
#ifdef ENABLE_BATCHED_PARTICLE_RENDERING
// triangle 1: p0, p1, p2
m_ParticleMesh[0].position = p0;
m_ParticleMesh[1].position = p1;
m_ParticleMesh[2].position = p2;
// triangle 2: p2, p1, p3
m_ParticleMesh[3].position = p2;
m_ParticleMesh[4].position = p1;
m_ParticleMesh[5].position = p3;
#else
m_ParticleMesh[0].position = p0;
m_ParticleMesh[1].position = p1;
m_ParticleMesh[2].position = p2;
m_ParticleMesh[3].position = p3;
#endif
m_ParticleMesh[0].position = m_v3Position - v3Up + v3Cross;
m_ParticleMesh[1].position = m_v3Position - v3Up - v3Cross;
m_ParticleMesh[2].position = m_v3Position + v3Up + v3Cross;
m_ParticleMesh[3].position = m_v3Position + v3Up - v3Cross;
}
}
@@ -573,29 +490,14 @@ void CParticleInstance::__Initialize()
m_v2Scale = D3DXVECTOR2(1.0f, 1.0f);
m_Color = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
#ifdef ENABLE_BATCHED_PARTICLE_RENDERING
for (auto& vtx : m_ParticleMesh) {
vtx.diffuse = m_Color;
}
#endif
m_byFrameIndex = 0;
m_rotationType = CParticleProperty::ROTATION_TYPE_NONE;
m_fFrameTime = 0;
#ifdef ENABLE_BATCHED_PARTICLE_RENDERING
m_ParticleMesh[0].texCoord = D3DXVECTOR2(0.0f, 1.0f);
m_ParticleMesh[1].texCoord = D3DXVECTOR2(0.0f, 0.0f);
m_ParticleMesh[2].texCoord = D3DXVECTOR2(1.0f, 1.0f);
m_ParticleMesh[3].texCoord = D3DXVECTOR2(1.0f, 1.0f);
m_ParticleMesh[4].texCoord = D3DXVECTOR2(0.0f, 0.0f);
m_ParticleMesh[5].texCoord = D3DXVECTOR2(1.0f, 0.0f);
#else
m_ParticleMesh[0].texCoord = D3DXVECTOR2(0.0f, 1.0f);
m_ParticleMesh[1].texCoord = D3DXVECTOR2(0.0f, 0.0f);
m_ParticleMesh[2].texCoord = D3DXVECTOR2(1.0f, 1.0f);
m_ParticleMesh[3].texCoord = D3DXVECTOR2(1.0f, 0.0f);
#endif
}
CParticleInstance::CParticleInstance()
@@ -608,11 +510,7 @@ CParticleInstance::~CParticleInstance()
Destroy();
}
#ifdef ENABLE_BATCHED_PARTICLE_RENDERING
const std::array<TPDTVertex, 6>& CParticleInstance::GetParticleMeshPointer()
#else
const std::array<TPTVertex, 4>& CParticleInstance::GetParticleMeshPointer()
#endif
TPTVertex * CParticleInstance::GetParticleMeshPointer()
{
return m_ParticleMesh;
}

View File

@@ -1,11 +1,8 @@
#pragma once
#include "UserInterface/Locale_inc.h"
#include "Type.h"
#include "Eterlib/GrpBase.h"
#include "EterLib/Pool.h"
#include <array>
class CParticleProperty;
class CEmitterProperty;
@@ -41,7 +38,6 @@ class CParticleInstance
D3DXVECTOR2 m_v2Scale;
float m_fRotation;
D3DXCOLOR m_Color;
BYTE m_byTextureAnimationType;
@@ -68,11 +64,7 @@ class CParticleInstance
void Transform(const D3DXMATRIX * c_matLocal=NULL);
void Transform(const D3DXMATRIX * c_matLocal, const float c_fZRotation);
#ifdef ENABLE_BATCHED_PARTICLE_RENDERING
const std::array<TPDTVertex, 6>& GetParticleMeshPointer();
#else
const std::array<TPTVertex, 4>& GetParticleMeshPointer();
#endif
TPTVertex * GetParticleMeshPointer();
void DeleteThis();
@@ -80,12 +72,7 @@ class CParticleInstance
protected:
void __Initialize();
#ifdef ENABLE_BATCHED_PARTICLE_RENDERING
std::array<TPDTVertex, 6> m_ParticleMesh;
#else
std::array<TPTVertex, 4> m_ParticleMesh;
#endif
TPTVertex m_ParticleMesh[4];
public:
static CDynamicPool<CParticleInstance> ms_kPool;

View File

@@ -1,15 +1,11 @@
#include "StdAfx.h"
#include "ParticleProperty.h"
#include "../eterlib/ResourceManager.h"
#include "Eterlib/ResourceManager.h"
void CParticleProperty::InsertTexture(const char * c_szFileName)
{
CGraphicImage * pImage = (CGraphicImage *)CResourceManager::Instance().GetResourcePointer(c_szFileName);
m_ImageVector.push_back(pImage);
#ifdef WORLD_EDITOR
m_TextureNameVector.push_back(c_szFileName);
#endif
}
bool CParticleProperty::SetTexture(const char * c_szFileName)
@@ -20,9 +16,6 @@ bool CParticleProperty::SetTexture(const char * c_szFileName)
return false;
}
m_ImageVector.clear();
#ifdef WORLD_EDITOR
m_TextureNameVector.clear();
#endif
InsertTexture(c_szFileName);
return true;
}
@@ -56,15 +49,7 @@ void CParticleProperty::Clear()
m_TimeEventScaleX.clear();
m_TimeEventScaleY.clear();
//m_TimeEventScaleXY.clear();
#ifdef WORLD_EDITOR
m_TimeEventColorRed.clear();
m_TimeEventColorGreen.clear();
m_TimeEventColorBlue.clear();
m_TimeEventAlpha.clear();
m_TextureNameVector.clear();
#else
m_TimeEventColor.clear();
#endif
m_TimeEventRotation.clear();
m_ImageVector.clear();
@@ -103,16 +88,7 @@ CParticleProperty & CParticleProperty::operator = ( const CParticleProperty& c_P
m_TimeEventScaleX = c_ParticleProperty.m_TimeEventScaleX;
m_TimeEventScaleY = c_ParticleProperty.m_TimeEventScaleY;
#ifdef WORLD_EDITOR
m_TimeEventColorRed = c_ParticleProperty.m_TimeEventColorRed;
m_TimeEventColorGreen = c_ParticleProperty.m_TimeEventColorGreen;
m_TimeEventColorBlue = c_ParticleProperty.m_TimeEventColorBlue;
m_TimeEventAlpha = c_ParticleProperty.m_TimeEventAlpha;
m_TextureNameVector = c_ParticleProperty.m_TextureNameVector;
#else
m_TimeEventColor = c_ParticleProperty.m_TimeEventColor;
#endif
m_TimeEventRotation = c_ParticleProperty.m_TimeEventRotation;
m_ImageVector = c_ParticleProperty.m_ImageVector;

View File

@@ -1,7 +1,7 @@
#pragma once
#include <vector>
#include "../eterlib/GrpImageInstance.h"
#include "Eterlib/GrpImageInstance.h"
#include "Type.h"
@@ -75,16 +75,7 @@ class CParticleProperty
TTimeEventTableFloat m_TimeEventScaleX;
TTimeEventTableFloat m_TimeEventScaleY;
#ifdef WORLD_EDITOR
TTimeEventTableFloat m_TimeEventColorRed;
TTimeEventTableFloat m_TimeEventColorGreen;
TTimeEventTableFloat m_TimeEventColorBlue;
TTimeEventTableFloat m_TimeEventAlpha;
std::vector<std::string> m_TextureNameVector;
#else
TTimeEventTableColor m_TimeEventColor;
#endif
TTimeEventTableFloat m_TimeEventRotation;
std::vector<CGraphicImage*> m_ImageVector;

View File

@@ -210,17 +210,6 @@ BOOL CParticleSystemData::OnLoadScript(CTextFileLoader & rTextFileLoader)
if (!GetTokenTimeEventFloat(rTextFileLoader, "timeeventscaley", &m_ParticleProperty.m_TimeEventScaleY))
return FALSE;
#ifdef WORLD_EDITOR
if (!GetTokenTimeEventFloat(rTextFileLoader, "timeeventcolorred", &m_ParticleProperty.m_TimeEventColorRed))
return FALSE;
if (!GetTokenTimeEventFloat(rTextFileLoader, "timeeventcolorgreen", &m_ParticleProperty.m_TimeEventColorGreen))
return FALSE;
if (!GetTokenTimeEventFloat(rTextFileLoader, "timeeventcolorblue", &m_ParticleProperty.m_TimeEventColorBlue))
return FALSE;
if (!GetTokenTimeEventFloat(rTextFileLoader, "timeeventalpha", &m_ParticleProperty.m_TimeEventAlpha))
return FALSE;
#else
TTimeEventTableFloat TimeEventR;
TTimeEventTableFloat TimeEventB;
TTimeEventTableFloat TimeEventG;
@@ -257,16 +246,13 @@ BOOL CParticleSystemData::OnLoadScript(CTextFileLoader & rTextFileLoader)
fA = GetTimeEventBlendValue(fTime, TimeEventA);
TTimeEventTypeColor t;
t.m_fTime = fTime;
D3DXCOLOR c;
c.r = fR;
c.g = fG;
c.b = fB;
c.a = fA;
t.m_Value = c;
t.m_Value.r = fR;
t.m_Value.g = fG;
t.m_Value.b = fB;
t.m_Value.a = fA;
m_ParticleProperty.m_TimeEventColor.push_back(t);
}
}
#endif
if (!GetTokenTimeEventFloat(rTextFileLoader, "timeeventrotation", &m_ParticleProperty.m_TimeEventRotation))
return FALSE;

View File

@@ -1,6 +1,6 @@
#pragma once
#include "../eterLib/TextFileLoader.h"
#include "EterLib/TextFileLoader.h"
#include "EffectElementBase.h"
#include "EmitterProperty.h"

View File

@@ -1,12 +1,10 @@
#include "StdAfx.h"
#include "../eterBase/Random.h"
#include "../eterLib/StateManager.h"
#include "EterBase/Random.h"
#include "EterLib/StateManager.h"
#include "ParticleSystemData.h"
#include "ParticleSystemInstance.h"
#include "ParticleInstance.h"
std::unordered_map<LPDIRECT3DTEXTURE9, std::unordered_map<uint32_t, std::vector<TPDTVertex>>> g_particleVertexBatch;
CDynamicPool<CParticleSystemInstance> CParticleSystemInstance::ms_kPool;
void CParticleSystemInstance::DestroySystem()
@@ -250,14 +248,7 @@ void CParticleSystemInstance::CreateParticles(float fElapsedTime)
pInstance->m_v2Scale.x = m_pParticleProperty->m_TimeEventScaleX.front().m_Value;
pInstance->m_v2Scale.y= m_pParticleProperty->m_TimeEventScaleY.front().m_Value;
//pInstance->m_v2Scale = m_pParticleProperty->m_TimeEventScaleXY.front().m_Value;
#ifdef WORLD_EDITOR
pInstance->m_Color.r = m_pParticleProperty->m_TimeEventColorRed.front().m_Value;
pInstance->m_Color.g = m_pParticleProperty->m_TimeEventColorGreen.front().m_Value;
pInstance->m_Color.b = m_pParticleProperty->m_TimeEventColorBlue.front().m_Value;
pInstance->m_Color.a = m_pParticleProperty->m_TimeEventAlpha.front().m_Value;
#else
pInstance->m_Color = m_pParticleProperty->m_TimeEventColor.front().m_Value;
#endif
}
m_ParticleInstanceListVector[pInstance->m_byFrameIndex].push_back(pInstance);
@@ -345,189 +336,80 @@ namespace NParticleRenderer
struct TwoSideRenderer
{
const D3DXMATRIX * pmat;
uint32_t opKey;
TwoSideRenderer(uint32_t key, const D3DXMATRIX * pmat=NULL)
: opKey(key), pmat(pmat)
TwoSideRenderer(const D3DXMATRIX * pmat=NULL)
: pmat(pmat)
{
}
inline void operator () (CParticleInstance * pInstance, LPDIRECT3DTEXTURE9 pTexture)
inline void operator () (CParticleInstance * pInstance)
{
auto& vtxBatch = g_particleVertexBatch[pTexture][opKey];
const auto& particleMesh = pInstance->GetParticleMeshPointer();
pInstance->Transform(pmat,D3DXToRadian(-30.0f));
vtxBatch.insert(vtxBatch.end(), particleMesh.begin(), particleMesh.end());
STATEMANAGER.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pInstance->GetParticleMeshPointer(), sizeof(TPTVertex));
pInstance->Transform(pmat,D3DXToRadian(+30.0f));
vtxBatch.insert(vtxBatch.end(), particleMesh.begin(), particleMesh.end());
STATEMANAGER.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pInstance->GetParticleMeshPointer(), sizeof(TPTVertex));
}
};
struct ThreeSideRenderer
{
const D3DXMATRIX * pmat;
uint32_t opKey;
ThreeSideRenderer(uint32_t key, const D3DXMATRIX * pmat=NULL)
: opKey(key), pmat(pmat)
ThreeSideRenderer(const D3DXMATRIX * pmat=NULL)
: pmat(pmat)
{
}
inline void operator () (CParticleInstance* pInstance, LPDIRECT3DTEXTURE9 pTexture)
inline void operator () (CParticleInstance * pInstance)
{
auto& vtxBatch = g_particleVertexBatch[pTexture][opKey];
const auto& particleMesh = pInstance->GetParticleMeshPointer();
pInstance->Transform(pmat);
vtxBatch.insert(vtxBatch.end(), particleMesh.begin(), particleMesh.end());
STATEMANAGER.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pInstance->GetParticleMeshPointer(), sizeof(TPTVertex));
pInstance->Transform(pmat,D3DXToRadian(-60.0f));
vtxBatch.insert(vtxBatch.end(), particleMesh.begin(), particleMesh.end());
STATEMANAGER.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pInstance->GetParticleMeshPointer(), sizeof(TPTVertex));
pInstance->Transform(pmat,D3DXToRadian(+60.0f));
vtxBatch.insert(vtxBatch.end(), particleMesh.begin(), particleMesh.end());
STATEMANAGER.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pInstance->GetParticleMeshPointer(), sizeof(TPTVertex));
}
};
struct NormalRenderer
{
uint32_t opKey;
NormalRenderer(uint32_t key) : opKey(key) {}
inline void operator () (CParticleInstance* pInstance, LPDIRECT3DTEXTURE9 pTexture)
inline void operator () (CParticleInstance * pInstance)
{
auto& vtxBatch = g_particleVertexBatch[pTexture][opKey];
const auto& particleMesh = pInstance->GetParticleMeshPointer();
pInstance->Transform();
vtxBatch.insert(vtxBatch.end(), particleMesh.begin(), particleMesh.end());
STATEMANAGER.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pInstance->GetParticleMeshPointer(), sizeof(TPTVertex));
}
};
struct AttachRenderer
{
const D3DXMATRIX* pmat;
uint32_t opKey;
AttachRenderer(uint32_t key, const D3DXMATRIX * pmat)
: opKey(key), pmat(pmat)
AttachRenderer(const D3DXMATRIX * pmat)
: pmat(pmat)
{
}
inline void operator () (CParticleInstance* pInstance, LPDIRECT3DTEXTURE9 pTexture)
inline void operator () (CParticleInstance * pInstance)
{
auto& vtxBatch = g_particleVertexBatch[pTexture][opKey];
const auto& particleMesh = pInstance->GetParticleMeshPointer();
pInstance->Transform(pmat);
vtxBatch.insert(vtxBatch.end(), particleMesh.begin(), particleMesh.end());
STATEMANAGER.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pInstance->GetParticleMeshPointer(), sizeof(TPTVertex));
}
};
}
void CParticleSystemInstance::OnRender()
{
g_particleVertexBatch.clear();
CScreen::Identity();
uint32_t opKey;
{
uint8_t* pKeyPart = (uint8_t*)&opKey;
pKeyPart[0] = m_pParticleProperty->m_bySrcBlendType;
pKeyPart[1] = m_pParticleProperty->m_byDestBlendType;
pKeyPart[2] = m_pParticleProperty->m_byColorOperationType;
}
if (m_pParticleProperty->m_byBillboardType < BILLBOARD_TYPE_2FACE)
{
if (!m_pParticleProperty->m_bAttachFlag)
{
auto obj = NParticleRenderer::NormalRenderer(opKey);
ForEachParticleRendering(obj);
}
else
{
auto obj = NParticleRenderer::AttachRenderer(opKey, mc_pmatLocal);
ForEachParticleRendering(obj);
}
}
else if (m_pParticleProperty->m_byBillboardType == BILLBOARD_TYPE_2FACE)
{
if (!m_pParticleProperty->m_bAttachFlag)
{
auto obj = NParticleRenderer::TwoSideRenderer(opKey);
ForEachParticleRendering(obj);
}
else
{
auto obj = NParticleRenderer::TwoSideRenderer(opKey, mc_pmatLocal);
ForEachParticleRendering(obj);
}
}
else if (m_pParticleProperty->m_byBillboardType == BILLBOARD_TYPE_3FACE)
{
if (!m_pParticleProperty->m_bAttachFlag)
{
auto obj = NParticleRenderer::ThreeSideRenderer(opKey);
ForEachParticleRendering(obj);
}
else
{
auto obj = NParticleRenderer::ThreeSideRenderer(opKey, mc_pmatLocal);
ForEachParticleRendering(obj);
}
}
for (auto& [pTexture, keyMap] : g_particleVertexBatch) {
if (keyMap.empty())
continue;
STATEMANAGER.SetTexture(0, pTexture);
for (auto& [opKey, vtxBatch] : keyMap) {
if (vtxBatch.empty())
continue;
uint8_t* pKeyPart = (uint8_t*)&opKey;
STATEMANAGER.SetRenderState(D3DRS_SRCBLEND, pKeyPart[0]);
STATEMANAGER.SetRenderState(D3DRS_DESTBLEND, pKeyPart[1]);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, pKeyPart[2]);
STATEMANAGER.DrawPrimitiveUP(
D3DPT_TRIANGLELIST,
vtxBatch.size() / 3,
vtxBatch.data(),
sizeof(TPDTVertex));
}
}
}
void CParticleSystemInstance::BatchParticles()
{
CScreen::Identity();
STATEMANAGER.SetRenderState(D3DRS_SRCBLEND, m_pParticleProperty->m_bySrcBlendType);
STATEMANAGER.SetRenderState(D3DRS_DESTBLEND, m_pParticleProperty->m_byDestBlendType);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, m_pParticleProperty->m_byColorOperationType);
uint32_t opKey;
{
uint8_t* pKeyPart = (uint8_t*)&opKey;
pKeyPart[0] = m_pParticleProperty->m_bySrcBlendType;
pKeyPart[1] = m_pParticleProperty->m_byDestBlendType;
pKeyPart[2] = m_pParticleProperty->m_byColorOperationType;
}
STATEMANAGER.SetTextureStageState(0,D3DTSS_COLOROP,m_pParticleProperty->m_byColorOperationType);
if (m_pParticleProperty->m_byBillboardType < BILLBOARD_TYPE_2FACE)
{
if (!m_pParticleProperty->m_bAttachFlag)
{
auto obj = NParticleRenderer::NormalRenderer(opKey);
auto obj = NParticleRenderer::NormalRenderer();
ForEachParticleRendering(obj);
}
else
{
auto obj = NParticleRenderer::AttachRenderer(opKey, mc_pmatLocal);
auto obj = NParticleRenderer::AttachRenderer(mc_pmatLocal);
ForEachParticleRendering(obj);
}
}
@@ -535,12 +417,12 @@ void CParticleSystemInstance::BatchParticles()
{
if (!m_pParticleProperty->m_bAttachFlag)
{
auto obj = NParticleRenderer::TwoSideRenderer(opKey);
auto obj = NParticleRenderer::TwoSideRenderer();
ForEachParticleRendering(obj);
}
else
{
auto obj = NParticleRenderer::TwoSideRenderer(opKey, mc_pmatLocal);
auto obj = NParticleRenderer::TwoSideRenderer(mc_pmatLocal);
ForEachParticleRendering(obj);
}
}
@@ -548,12 +430,12 @@ void CParticleSystemInstance::BatchParticles()
{
if (!m_pParticleProperty->m_bAttachFlag)
{
auto obj = NParticleRenderer::ThreeSideRenderer(opKey);
auto obj = NParticleRenderer::ThreeSideRenderer();
ForEachParticleRendering(obj);
}
else
{
auto obj = NParticleRenderer::ThreeSideRenderer(opKey, mc_pmatLocal);
auto obj = NParticleRenderer::ThreeSideRenderer(mc_pmatLocal);
ForEachParticleRendering(obj);
}
}

View File

@@ -1,5 +1,4 @@
#pragma once
#include "UserInterface/Locale_inc.h"
#include "EffectElementBaseInstance.h"
#include "ParticleInstance.h"
#include "ParticleProperty.h"
@@ -26,12 +25,14 @@ class CParticleSystemInstance : public CEffectElementBaseInstance
DWORD dwFrameIndex;
for(dwFrameIndex=0; dwFrameIndex<m_kVct_pkImgInst.size(); dwFrameIndex++)
{
STATEMANAGER.SetTexture(0, m_kVct_pkImgInst[dwFrameIndex]->GetTextureReference().GetD3DTexture());
TParticleInstanceList::iterator itor = m_ParticleInstanceListVector[dwFrameIndex].begin();
for (; itor != m_ParticleInstanceListVector[dwFrameIndex].end(); ++itor)
{
if (!InFrustum(*itor))
return;
FunObj(*itor, m_kVct_pkImgInst[dwFrameIndex]->GetTextureReference().GetD3DTexture());
continue;
FunObj(*itor);
}
}
}
@@ -57,8 +58,6 @@ class CParticleSystemInstance : public CEffectElementBaseInstance
DWORD GetEmissionCount();
void BatchParticles();
protected:
void OnInitialize();
void OnDestroy();

View File

@@ -1,5 +1,5 @@
#include "Stdafx.h"
#include "../eterLib/GrpLightManager.h"
#include "EterLib/GrpLightManager.h"
#include "SimpleLightInstance.h"

View File

@@ -1,6 +1,6 @@
#pragma once
#include "../eterLib/GrpScreen.h"
#include "EterLib/GrpScreen.h"
#include "EffectElementBaseInstance.h"
#include "SimpleLightData.h"

View File

@@ -2,17 +2,19 @@
//#include <crtdbg.h>
#include "../eterBase/StdAfx.h"
#include "EterBase/StdAfx.h"
#include "EterBase/Utils.h"
#include "EterBase/Timer.h"
#include "EterBase/CRC32.h"
#include "EterBase/Debug.h"
#include "EterLib/StdAfx.h"
#include "EterLib/TextFileLoader.h"
#include "../eterBase/Utils.h"
#include "../eterBase/Timer.h"
#include "../eterBase/CRC32.h"
#include "../eterBase/Debug.h"
#include "AudioLib/StdAfx.h"
#include "../eterLib/StdAfx.h"
#include "../eterLib/TextFileLoader.h"
#include "../milesLib/StdAfx.h"
#include "UserInterface/Locale_inc.h"
/*
#include "FrameController.h"

View File

@@ -74,8 +74,8 @@ enum EBillBoardType
BILLBOARD_TYPE_LIE, // 바닥에 누은 형상
BILLBOARD_TYPE_2FACE, // / and \
BILLBOARD_TYPE_3FACE, // / and \ and -
BILLBOARD_TYPE_2FACE, // / and
BILLBOARD_TYPE_3FACE, // / and
//BILLBOARD_TYPE_RAY, // 잔상
@@ -123,68 +123,6 @@ typedef struct SEffectPosition : public CTimeEvent<D3DXVECTOR3>
D3DXVECTOR3 m_vecControlPoint;
} TEffectPosition;
#define AG_MASK 0xff00ff00
#define RB_MASK 0x00ff00ff
struct DWORDCOLOR
{
DWORD m_dwColor;
DWORDCOLOR()
{
}
DWORDCOLOR(const DWORDCOLOR& r)
: m_dwColor(r.m_dwColor)
{
}
DWORDCOLOR(DWORD dwColor)
: m_dwColor(dwColor)
{
}
DWORDCOLOR& operator = (const DWORDCOLOR& r)
{
m_dwColor = r.m_dwColor;
return *this;
}
DWORDCOLOR& operator *= (float f)
{
DWORD idx = DWORD(f * 256);
m_dwColor =
(((DWORD)(((m_dwColor & AG_MASK) >> 8) * idx)) & AG_MASK)
+ ((DWORD)(((m_dwColor & RB_MASK) * idx) >> 8) & RB_MASK);
return *this;
}
DWORDCOLOR& operator += (const DWORDCOLOR& r)
{
m_dwColor += r.m_dwColor;
return *this;
}
operator DWORD()
{
return m_dwColor;
}
};
#undef AG_MASK
#undef RB_MASK
inline DWORDCOLOR operator * (DWORDCOLOR dc, float f)
{
DWORDCOLOR tmp(dc);
tmp *= f;
return tmp;
}
inline DWORDCOLOR operator * (float f, DWORDCOLOR dc)
{
DWORDCOLOR tmp(dc);
tmp *= f;
return tmp;
}
typedef CTimeEvent<char> TTimeEventTypeCharacter;
typedef CTimeEvent<short> TTimeEventTypeShort;
typedef CTimeEvent<float> TTimeEventTypeFloat;
@@ -238,14 +176,6 @@ inline D3DXVECTOR3 BlendSingleValue(float time, const TEffectPosition& low, cons
return D3DXVECTOR3();
}
inline DWORDCOLOR BlendSingleValue(float time, const TTimeEventTypeColor& low, const TTimeEventTypeColor& high)
{
const float timeDiff = high.m_fTime - low.m_fTime;
const float perc = (time - low.m_fTime) / timeDiff;
return low.m_Value * (1.0f - perc) + high.m_Value * perc;
}
template <typename T>
auto GetTimeEventBlendValue(float time,
const std::vector<T>& vec) -> typename T::value_type

View File

@@ -5,6 +5,7 @@ add_library(EterBase STATIC ${FILE_SOURCES})
target_link_libraries(EterBase
lzo2
cryptopp-static
mio
)
GroupSourcesByFolder(EterBase)

View File

@@ -1,299 +0,0 @@
#include "StdAfx.h"
#include "CPostIt.h"
#include "../eterBase/utils.h"
class _CPostItMemoryBlock
{
public:
_CPostItMemoryBlock( void );
~_CPostItMemoryBlock( void );
BOOL Assign( HANDLE hBlock );
HANDLE CreateHandle( void );
BOOL DestroyHandle( void );
LPSTR Find( LPCSTR lpszKeyName );
BOOL Put( LPCSTR lpBuffer );
BOOL Put( LPCSTR lpszKeyName, LPCSTR lpBuffer );
BOOL Get( LPCSTR lpszKeyName, LPSTR lpBuffer, DWORD nSize );
protected:
typedef std::list<CHAR *> StrList;
typedef StrList::iterator StrListItr;
HANDLE m_hHandle;
StrList m_StrList;
};
CPostIt::CPostIt( LPCSTR szAppName ) : m_pMemoryBlock(NULL), m_bModified(FALSE)
{
Init( szAppName );
}
CPostIt::~CPostIt( void )
{
Destroy();
}
BOOL CPostIt::Init( LPCSTR szAppName )
{
if( szAppName == NULL || !*szAppName ) {
strcpy( m_szClipFormatName, "YMCF" );
} else {
strcpy( m_szClipFormatName, "YMCF_" );
strcat( m_szClipFormatName, szAppName );
}
return TRUE;
}
BOOL CPostIt::CopyTo( CPostIt *pPostIt, LPCSTR lpszKeyName )
{
if( m_pMemoryBlock == NULL )
return FALSE;
LPSTR szText = m_pMemoryBlock->Find( lpszKeyName );
if( szText == NULL )
return FALSE;
return pPostIt->Set( szText );
}
BOOL CPostIt::Flush( void )
{
if( m_bModified == FALSE )
return FALSE;
if( m_pMemoryBlock == NULL )
return FALSE;
UINT uDGPFormat;
uDGPFormat = ::RegisterClipboardFormatA( m_szClipFormatName );
if( ::OpenClipboard( NULL ) == FALSE )
return FALSE;
if( ::SetClipboardData( uDGPFormat, m_pMemoryBlock->CreateHandle() ) == NULL ) {
// DWORD dwLastError = ::GetLastError();
m_pMemoryBlock->DestroyHandle();
::CloseClipboard();
m_bModified = FALSE;
return FALSE;
}
::CloseClipboard();
m_bModified = FALSE;
return TRUE;
}
void CPostIt::Empty( void )
{
SAFE_DELETE( m_pMemoryBlock );
UINT uDGPFormat;
uDGPFormat = ::RegisterClipboardFormatA( m_szClipFormatName );
if( ::OpenClipboard( NULL ) == FALSE )
return;
HANDLE hClipboardMemory = ::GetClipboardData( uDGPFormat );
if( hClipboardMemory ) {
// ::GlobalFree( hClipboardMemory );
::SetClipboardData( uDGPFormat, NULL );
}
::CloseClipboard();
m_bModified = FALSE;
}
void CPostIt::Destroy( void )
{
Flush();
SAFE_DELETE( m_pMemoryBlock );
}
BOOL CPostIt::Set( LPCSTR lpszKeyName, LPCSTR lpBuffer )
{
if( m_pMemoryBlock == NULL )
m_pMemoryBlock = new _CPostItMemoryBlock;
m_pMemoryBlock->Put( lpszKeyName, lpBuffer );
m_bModified = TRUE;
return TRUE;
}
BOOL CPostIt::Set( LPCSTR lpszKeyName, DWORD dwValue )
{
CHAR szValue[12];
_snprintf( szValue, 12, "%d", dwValue );
return Set( lpszKeyName, szValue );
}
BOOL CPostIt::Set( LPCSTR lpBuffer )
{
if( lpBuffer == NULL )
return FALSE;
if( m_pMemoryBlock == NULL )
m_pMemoryBlock = new _CPostItMemoryBlock;
m_pMemoryBlock->Put( lpBuffer );
m_bModified = TRUE;
return TRUE;
}
BOOL CPostIt::Get( LPCSTR lpszKeyName, LPSTR lpBuffer, DWORD nSize )
{
if( m_pMemoryBlock == NULL ) {
UINT uDGPFormat;
uDGPFormat = ::RegisterClipboardFormatA( m_szClipFormatName );
if( ::OpenClipboard( NULL ) == FALSE )
return FALSE;
HANDLE hClipboardMemory = ::GetClipboardData( uDGPFormat );
if( hClipboardMemory == NULL ) {
::CloseClipboard();
return FALSE;
}
m_pMemoryBlock = new _CPostItMemoryBlock;
m_pMemoryBlock->Assign( hClipboardMemory );
::CloseClipboard();
}
return m_pMemoryBlock->Get( lpszKeyName, lpBuffer, nSize );
}
_CPostItMemoryBlock::_CPostItMemoryBlock( void ) : m_hHandle( NULL )
{
}
_CPostItMemoryBlock::~_CPostItMemoryBlock( void )
{
for( StrListItr itr = m_StrList.begin(); itr != m_StrList.end(); ) {
LPSTR lpszText = *itr;
SAFE_DELETE_ARRAY( lpszText );
itr = m_StrList.erase( itr );
}
}
BOOL _CPostItMemoryBlock::Assign( HANDLE hBlock )
{
if( hBlock == NULL || hBlock == INVALID_HANDLE_VALUE )
return FALSE;
LPBYTE lpBuffer = (LPBYTE) ::GlobalLock( hBlock );
if( lpBuffer == NULL )
return FALSE;
DWORD dwCount = *((LPDWORD) lpBuffer); lpBuffer += sizeof( DWORD );
for( DWORD dwI=0; dwI < dwCount; dwI++ ) {
WORD wLen = *((LPWORD) lpBuffer); lpBuffer += sizeof( WORD );
LPSTR lpszText = new CHAR[ wLen + 1 ];
::CopyMemory( lpszText, lpBuffer, wLen );
lpszText[ wLen ] = '\0';
lpBuffer += wLen;
Put( lpszText );
}
::GlobalUnlock( hBlock );
return TRUE;
}
HANDLE _CPostItMemoryBlock::CreateHandle( void )
{
if( m_StrList.size() == 0 )
return INVALID_HANDLE_VALUE;
DWORD dwBlockSize = sizeof( DWORD );
StrListItr itr;
// Calculation for Memory Block Size
for( itr = m_StrList.begin(); itr != m_StrList.end(); ++itr ) {
dwBlockSize += sizeof( WORD );
dwBlockSize += (DWORD) strlen( *itr );
}
HANDLE hBlock = ::GlobalAlloc( GMEM_ZEROINIT | GMEM_MOVEABLE, dwBlockSize );
if( hBlock == NULL )
return INVALID_HANDLE_VALUE;
LPBYTE lpBuffer = (LPBYTE) ::GlobalLock( hBlock );
if( lpBuffer == NULL ) {
::GlobalFree( hBlock );
return INVALID_HANDLE_VALUE;
}
*((LPDWORD) lpBuffer) = (DWORD) m_StrList.size(); lpBuffer += sizeof( DWORD );
for( itr = m_StrList.begin(); itr != m_StrList.end(); ++itr ) {
*((LPWORD) lpBuffer) = (WORD) strlen( *itr ); lpBuffer += sizeof( WORD );
::CopyMemory( lpBuffer, *itr, strlen( *itr ) ); lpBuffer += strlen( *itr );
}
::GlobalUnlock( hBlock );
m_hHandle = hBlock;
return hBlock;
}
BOOL _CPostItMemoryBlock::DestroyHandle( void )
{
::GlobalFree( m_hHandle );
m_hHandle = NULL;
return TRUE;
}
LPSTR _CPostItMemoryBlock::Find( LPCSTR lpszKeyName )
{
for( StrListItr itr = m_StrList.begin(); itr != m_StrList.end(); ++itr ) {
LPSTR lpszText = *itr;
if( _strnicmp( lpszText, lpszKeyName, strlen( lpszKeyName ) ) != 0 )
continue;
if( *(lpszText + strlen( lpszKeyName )) != '=' )
continue;
return lpszText;
}
return NULL;
}
BOOL _CPostItMemoryBlock::Put( LPCSTR lpszKeyName, LPCSTR lpBuffer )
{
LPSTR lpszText;
if( (lpszText = Find( lpszKeyName )) != NULL ) {
for( StrListItr itr = m_StrList.begin(); itr != m_StrList.end(); ++itr ) {
if( lpszText == *itr ) {
SAFE_DELETE_ARRAY( lpszText );
m_StrList.erase( itr );
break;
}
}
}
if( lpBuffer == NULL || !*lpBuffer )
return TRUE;
size_t nStrLen = strlen( lpszKeyName ) + 1 /* '=' */ + strlen( lpBuffer );
lpszText = new CHAR[ nStrLen + 1 ];
::CopyMemory( lpszText, lpszKeyName, strlen( lpszKeyName ) );
*(lpszText + strlen( lpszKeyName )) = '=';
::CopyMemory( lpszText + strlen( lpszKeyName ) + 1, lpBuffer, strlen( lpBuffer ) );
*(lpszText + nStrLen) = '\0';
m_StrList.push_back( lpszText );
return TRUE;
}
BOOL _CPostItMemoryBlock::Put( LPCSTR lpBuffer )
{
LPSTR lpszText;
if( lpBuffer == NULL || !*lpBuffer )
return TRUE;
size_t nStrLen = strlen( lpBuffer );
lpszText = new CHAR[ nStrLen + 1 ];
::CopyMemory( lpszText, lpBuffer, nStrLen );
*(lpszText + nStrLen) = '\0';
m_StrList.push_back( lpszText );
return TRUE;
}
BOOL _CPostItMemoryBlock::Get( LPCSTR lpszKeyName, LPSTR lpBuffer, DWORD nSize )
{
LPSTR lpszText = Find( lpszKeyName );
if( lpszText == NULL )
return FALSE;
lpszText += (strlen( lpszKeyName ) + 1);
::ZeroMemory( lpBuffer, nSize );
strncpy( lpBuffer, lpszText, (nSize < strlen( lpszText )) ? nSize : strlen( lpszText ) );
return TRUE;
}

View File

@@ -1,80 +0,0 @@
#ifndef _EL_CPOSTIT_H_
#define _EL_CPOSTIT_H_
// _CPostItMemoryBlock is defined in CPostIt.cpp
class _CPostItMemoryBlock;
/**
* @class CPostIt
* @brief 게임런처에서 게임 클라이언트로 정보를 전달 및 클라이언트에서 수신하기 위하여 사용되는 클래스
*/
class CPostIt
{
public:
/**
* @brief CPostIt constructor
* @param [in] szAppName : 게임의 이름이 들어간다.
*/
explicit CPostIt( LPCSTR szAppName );
/**
* @brief CPostIt destructor
*/
~CPostIt( void );
/**
* @brief CPostIt class에서 보유하고 있는 데이타를 클립보드에 저장한다.
*/
BOOL Flush( void );
/**
* @brief CPostIt class에서 보유하고 있는 데이타 및 클립보드에 있는 내용을 지운다.
*/
void Empty( void );
/**
* @brief 데이타를 읽어온다.
* @param [in] lpszKeyName : 불러올 데이타의 키. "KEY" 식의 내용을 넣는다.
* @param [in] lpszData : 불러올 데이타의 버퍼
* @param [in] nSize : lpszData 버퍼의 최대사이즈
*/
BOOL Get( LPCSTR lpszKeyName, LPSTR lpszData, DWORD nSize );
/**
* @brief 저장할 데이타를 넣는다.
* @param [in] lpBuffer : 저장할 데이타. "KEY=DATA" 식의 내용을 넣는다.
*/
BOOL Set( LPCSTR lpszData );
/**
* @brief 저장할 데이타를 넣는다.
* @param [in] lpszKeyName : 저장할 데이타의 키. "KEY" 식의 내용을 넣는다.
* @param [in] lpszData : 저장할 데이타. "DATA" 식의 내용을 넣는다.
*/
BOOL Set( LPCSTR lpszKeyName, LPCSTR lpszData );
/**
* @brief 저장할 데이타(DWORD)를 넣는다.
* @param [in] lpBuffer : 저장할 데이타. "KEY=DATA" 식의 데이타를 넣는다.
* @param [in] dwValue : 저장할 데이타. (DWORD)
*/
BOOL Set( LPCSTR lpszKeyName, DWORD dwValue );
/**
* @brief CPostIt class를 복사한다. (클래스 constructor에 이름 인자가 있기 때문에, 새 이름을 지정해야함)
* @param [in] pPostIt : Destination class
* @param [in] lpszKeyName : Destination class's new app-name
*/
BOOL CopyTo( CPostIt *pPostIt, LPCSTR lpszKeyName );
protected:
BOOL Init( LPCSTR szAppName );
void Destroy( void );
protected:
BOOL m_bModified;
CHAR m_szClipFormatName[_MAX_PATH];
_CPostItMemoryBlock* m_pMemoryBlock;
};
#endif /* _EL_CPOSTIT_H_ */

View File

@@ -1,6 +1,8 @@
#include "StdAfx.h"
#include "CRC32.h"
#include <utf8.h>
static unsigned long CRCTable[256] =
{
0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,
@@ -147,65 +149,55 @@ DWORD GetHFILECRC32(HANDLE hFile)
dataOffset + mapSize, // low
NULL); // name
if (hFM)
{
LPVOID lpMapData = MapViewOfFile(hFM,
FILE_MAP_READ,
0,
dwFileMapStart,
dwMapViewSize);
dwRetCRC32=GetCRC32((const char*)lpMapData, dwFileSize);
{
LPVOID lpMapData = MapViewOfFile(hFM, FILE_MAP_READ, 0, dwFileMapStart, dwMapViewSize);
if (lpMapData)
{
//tw1x1: If MapViewOfFile returns null, crash risk on mapping failure
dwRetCRC32 = GetCRC32((const char*)lpMapData, dwFileSize);
UnmapViewOfFile(lpMapData);
}
CloseHandle(hFM);
}
return dwRetCRC32;
}
DWORD GetFileCRC32(const char* c_szFileName)
DWORD GetFileCRC32(const wchar_t* c_szFileName)
{
HANDLE hFile = CreateFile(c_szFileName, // name of the file
GENERIC_READ, // desired access
FILE_SHARE_READ, // share mode
NULL, // security attributes
OPEN_EXISTING, // creation disposition
FILE_ATTRIBUTE_NORMAL, // flags and attr
NULL); // template file
if (INVALID_HANDLE_VALUE == hFile)
if (!c_szFileName || !*c_szFileName)
return 0;
DWORD dwRetCRC32=GetHFILECRC32(hFile);
CloseHandle(hFile);
HANDLE hFile = CreateFileW(c_szFileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile == INVALID_HANDLE_VALUE)
return 0;
DWORD dwRetCRC32 = GetHFILECRC32(hFile);
CloseHandle(hFile);
return dwRetCRC32;
}
DWORD GetFileCRC32(const char* fileUtf8)
{
if (!fileUtf8 || !*fileUtf8)
return 0;
std::wstring wFile = Utf8ToWide(fileUtf8);
return GetFileCRC32(wFile.c_str());
}
DWORD GetFileSize(const char* c_szFileName)
{
HANDLE hFile = CreateFile(c_szFileName, // name of the file
GENERIC_READ, // desired access
FILE_SHARE_READ, // share mode
NULL, // security attributes
OPEN_EXISTING, // creation disposition
FILE_ATTRIBUTE_NORMAL, // flags and attr
NULL); // template file
if (INVALID_HANDLE_VALUE == hFile)
if (!c_szFileName || !*c_szFileName)
return 0;
DWORD dwSize = GetFileSize(hFile, NULL);
std::wstring wFile = Utf8ToWide(std::string(c_szFileName));
HANDLE hFile = CreateFileW(wFile.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile == INVALID_HANDLE_VALUE)
return 0;
DWORD dwSize = ::GetFileSize(hFile, nullptr);
CloseHandle(hFile);
return dwSize;
}

View File

@@ -6,7 +6,8 @@
DWORD GetCRC32(const char* buffer, size_t count);
DWORD GetCaseCRC32(const char * buf, size_t len);
DWORD GetHFILECRC32(HANDLE hFile);
DWORD GetFileCRC32(const char* c_szFileName);
DWORD GetFileCRC32(const wchar_t* c_szFileName);
DWORD GetFileCRC32(const char* fileUtf8);
DWORD GetFileSize(const char* c_szFileName);
#endif

View File

@@ -2,237 +2,266 @@
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <string>
#include "Debug.h"
#include "Singleton.h"
#include "Timer.h"
#include <filesystem>
#include <utf8.h>
const DWORD DEBUG_STRING_MAX_LEN = 1024;
static int isLogFile = false;
HWND g_PopupHwnd = NULL;
// Convert UTF-8 char* -> wide and send to debugger (NO helper function, just a macro)
#ifdef _DEBUG
#define DBG_OUT_W_UTF8(psz) \
do { \
const char* __s = (psz) ? (psz) : ""; \
std::wstring __w = Utf8ToWide(__s); \
OutputDebugStringW(__w.c_str()); \
} while (0)
#else
#define DBG_OUT_W_UTF8(psz) do { (void)(psz); } while (0)
#endif
class CLogFile : public CSingleton<CLogFile>
{
public:
CLogFile() : m_fp(NULL)
{
}
public:
CLogFile() : m_fp(NULL) {}
virtual ~CLogFile()
{
if (m_fp)
fclose(m_fp);
virtual ~CLogFile()
{
if (m_fp)
fclose(m_fp);
m_fp = NULL;
}
m_fp = NULL;
}
void Initialize()
{
m_fp = fopen("log.txt", "w");
}
void Initialize()
{
m_fp = fopen("log/log.txt", "w");
}
void Write(const char * c_pszMsg)
{
if (!m_fp)
return;
void Write(const char* c_pszMsg)
{
if (!m_fp)
return;
time_t ct = time(0);
struct tm ctm = *localtime(&ct);
time_t ct = time(0);
struct tm ctm = *localtime(&ct);
fprintf(m_fp, "%02d%02d %02d:%02d:%05d :: %s",
ctm.tm_mon + 1,
ctm.tm_mday,
ctm.tm_hour,
ctm.tm_min,
ELTimer_GetMSec() % 60000,
c_pszMsg);
fprintf(m_fp, "%02d%02d %02d:%02d:%05d :: %s",
ctm.tm_mon + 1,
ctm.tm_mday,
ctm.tm_hour,
ctm.tm_min,
ELTimer_GetMSec() % 60000,
c_pszMsg);
fflush(m_fp);
}
fflush(m_fp);
}
protected:
FILE * m_fp;
protected:
FILE* m_fp;
};
static CLogFile gs_logfile;
static UINT gs_uLevel=0;
static UINT gs_uLevel = 0;
void SetLogLevel(UINT uLevel)
{
gs_uLevel=uLevel;
gs_uLevel = uLevel;
}
void Log(UINT uLevel, const char* c_szMsg)
{
if (uLevel>=gs_uLevel)
Trace(c_szMsg);
if (uLevel >= gs_uLevel)
Trace(c_szMsg);
}
void Logn(UINT uLevel, const char* c_szMsg)
{
if (uLevel>=gs_uLevel)
Tracen(c_szMsg);
if (uLevel >= gs_uLevel)
Tracen(c_szMsg);
}
void Logf(UINT uLevel, const char* c_szFormat, ...)
{
if (uLevel<gs_uLevel)
return;
char szBuf[DEBUG_STRING_MAX_LEN+1];
if (uLevel < gs_uLevel)
return;
char szBuf[DEBUG_STRING_MAX_LEN + 1];
va_list args;
va_start(args, c_szFormat);
_vsnprintf_s(szBuf, sizeof(szBuf), _TRUNCATE, c_szFormat, args);
va_end(args);
va_list args;
va_start(args, c_szFormat);
_vsnprintf(szBuf, sizeof(szBuf), c_szFormat, args);
va_end(args);
#ifdef _DEBUG
OutputDebugString(szBuf);
fputs(szBuf, stdout);
DBG_OUT_W_UTF8(szBuf);
fputs(szBuf, stdout);
#endif
if (isLogFile)
LogFile(szBuf);
if (isLogFile)
LogFile(szBuf);
}
void Lognf(UINT uLevel, const char* c_szFormat, ...)
{
if (uLevel<gs_uLevel)
return;
if (uLevel < gs_uLevel)
return;
va_list args;
va_start(args, c_szFormat);
char szBuf[DEBUG_STRING_MAX_LEN + 2];
char szBuf[DEBUG_STRING_MAX_LEN+2];
int len = _vsnprintf(szBuf, sizeof(szBuf)-1, c_szFormat, args);
va_list args;
va_start(args, c_szFormat);
_vsnprintf_s(szBuf, sizeof(szBuf), _TRUNCATE, c_szFormat, args);
va_end(args);
size_t cur = strnlen(szBuf, sizeof(szBuf));
if (cur + 1 < sizeof(szBuf)) {
szBuf[cur] = '\n';
szBuf[cur + 1] = '\0';
}
else {
szBuf[sizeof(szBuf) - 2] = '\n';
szBuf[sizeof(szBuf) - 1] = '\0';
}
if (len > 0)
{
szBuf[len] = '\n';
szBuf[len + 1] = '\0';
}
va_end(args);
#ifdef _DEBUG
OutputDebugString(szBuf);
puts(szBuf);
DBG_OUT_W_UTF8(szBuf);
fputs(szBuf, stdout);
#endif
if (isLogFile)
LogFile(szBuf);
if (isLogFile)
LogFile(szBuf);
}
void Trace(const char * c_szMsg)
void Trace(const char* c_szMsg)
{
#ifdef _DEBUG
OutputDebugString(c_szMsg);
printf("%s", c_szMsg);
DBG_OUT_W_UTF8(c_szMsg);
printf("%s", c_szMsg ? c_szMsg : "");
#endif
if (isLogFile)
LogFile(c_szMsg);
if (isLogFile)
LogFile(c_szMsg ? c_szMsg : "");
}
void Tracen(const char* c_szMsg)
{
#ifdef _DEBUG
char szBuf[DEBUG_STRING_MAX_LEN+1];
_snprintf(szBuf, sizeof(szBuf), "%s\n", c_szMsg);
OutputDebugString(szBuf);
puts(c_szMsg);
char szBuf[DEBUG_STRING_MAX_LEN + 2];
_snprintf_s(szBuf, sizeof(szBuf), _TRUNCATE, "%s\n", c_szMsg ? c_szMsg : "");
if (isLogFile)
LogFile(szBuf);
DBG_OUT_W_UTF8(szBuf);
puts(c_szMsg);
putc('\n', stdout);
fputs(szBuf, stdout);
if (isLogFile)
LogFile(szBuf);
#else
if (isLogFile)
{
LogFile(c_szMsg);
LogFile("\n");
}
if (isLogFile)
{
LogFile(c_szMsg ? c_szMsg : "");
LogFile("\n");
}
#endif
}
void Tracenf(const char* c_szFormat, ...)
{
va_list args;
va_start(args, c_szFormat);
char szBuf[DEBUG_STRING_MAX_LEN + 2];
char szBuf[DEBUG_STRING_MAX_LEN+2];
int len = _vsnprintf(szBuf, sizeof(szBuf)-1, c_szFormat, args);
va_list args;
va_start(args, c_szFormat);
_vsnprintf_s(szBuf, sizeof(szBuf), _TRUNCATE, c_szFormat, args);
va_end(args);
size_t cur = strnlen(szBuf, sizeof(szBuf));
if (cur + 1 < sizeof(szBuf)) {
szBuf[cur] = '\n';
szBuf[cur + 1] = '\0';
}
else {
szBuf[sizeof(szBuf) - 2] = '\n';
szBuf[sizeof(szBuf) - 1] = '\0';
}
if (len > 0)
{
szBuf[len] = '\n';
szBuf[len + 1] = '\0';
}
va_end(args);
#ifdef _DEBUG
OutputDebugString(szBuf);
printf("%s", szBuf);
DBG_OUT_W_UTF8(szBuf);
fputs(szBuf, stdout);
#endif
if (isLogFile)
LogFile(szBuf);
if (isLogFile)
LogFile(szBuf);
}
void Tracef(const char* c_szFormat, ...)
{
char szBuf[DEBUG_STRING_MAX_LEN+1];
char szBuf[DEBUG_STRING_MAX_LEN + 1];
va_list args;
va_start(args, c_szFormat);
_vsnprintf(szBuf, sizeof(szBuf), c_szFormat, args);
va_end(args);
va_list args;
va_start(args, c_szFormat);
_vsnprintf_s(szBuf, sizeof(szBuf), _TRUNCATE, c_szFormat, args);
va_end(args);
#ifdef _DEBUG
OutputDebugString(szBuf);
fputs(szBuf, stdout);
DBG_OUT_W_UTF8(szBuf);
fputs(szBuf, stdout);
#endif
if (isLogFile)
LogFile(szBuf);
if (isLogFile)
LogFile(szBuf);
}
void TraceError(const char* c_szFormat, ...)
{
#ifndef _DISTRIBUTE
char szBuf[DEBUG_STRING_MAX_LEN + 2];
char szBuf[DEBUG_STRING_MAX_LEN+2];
strncpy_s(szBuf, sizeof(szBuf), "SYSERR: ", _TRUNCATE);
int prefixLen = (int)strlen(szBuf);
strncpy(szBuf, "SYSERR: ", DEBUG_STRING_MAX_LEN);
int len = strlen(szBuf);
va_list args;
va_start(args, c_szFormat);
_vsnprintf_s(szBuf + prefixLen, sizeof(szBuf) - prefixLen, _TRUNCATE, c_szFormat, args);
va_end(args);
va_list args;
va_start(args, c_szFormat);
len = _vsnprintf(szBuf + len, sizeof(szBuf) - (len + 1), c_szFormat, args) + len;
va_end(args);
size_t cur = strnlen(szBuf, sizeof(szBuf));
if (cur + 1 < sizeof(szBuf)) {
szBuf[cur] = '\n';
szBuf[cur + 1] = '\0';
}
else {
szBuf[sizeof(szBuf) - 2] = '\n';
szBuf[sizeof(szBuf) - 1] = '\0';
}
szBuf[len] = '\n';
szBuf[len + 1] = '\0';
time_t ct = time(0);
struct tm ctm = *localtime(&ct);
time_t ct = time(0);
struct tm ctm = *localtime(&ct);
fprintf(stderr, "%02d%02d %02d:%02d:%05d :: %s",
ctm.tm_mon + 1,
ctm.tm_mday,
ctm.tm_hour,
ctm.tm_min,
ELTimer_GetMSec() % 60000,
szBuf + 8);
fflush(stderr);
fprintf(stderr, "%02d%02d %02d:%02d:%05d :: %s",
ctm.tm_mon + 1,
ctm.tm_mday,
ctm.tm_hour,
ctm.tm_min,
ELTimer_GetMSec() % 60000,
szBuf + 8);
fflush(stderr);
#ifdef _DEBUG
OutputDebugString(szBuf);
fputs(szBuf, stdout);
DBG_OUT_W_UTF8(szBuf);
fputs(szBuf, stdout);
#endif
if (isLogFile)
LogFile(szBuf);
if (isLogFile)
LogFile(szBuf);
#endif
}
@@ -240,87 +269,101 @@ void TraceErrorWithoutEnter(const char* c_szFormat, ...)
{
#ifndef _DISTRIBUTE
char szBuf[DEBUG_STRING_MAX_LEN];
char szBuf[DEBUG_STRING_MAX_LEN];
va_list args;
va_start(args, c_szFormat);
_vsnprintf(szBuf, sizeof(szBuf), c_szFormat, args);
va_end(args);
va_list args;
va_start(args, c_szFormat);
_vsnprintf_s(szBuf, sizeof(szBuf), _TRUNCATE, c_szFormat, args);
va_end(args);
time_t ct = time(0);
struct tm ctm = *localtime(&ct);
time_t ct = time(0);
struct tm ctm = *localtime(&ct);
fprintf(stderr, "%02d%02d %02d:%02d:%05d :: %s",
ctm.tm_mon + 1,
ctm.tm_mday,
ctm.tm_hour,
ctm.tm_min,
ELTimer_GetMSec() % 60000,
szBuf + 8);
fflush(stderr);
fprintf(stderr, "%02d%02d %02d:%02d:%05d :: %s",
ctm.tm_mon + 1,
ctm.tm_mday,
ctm.tm_hour,
ctm.tm_min,
ELTimer_GetMSec() % 60000,
szBuf + 8);
fflush(stderr);
#ifdef _DEBUG
OutputDebugString(szBuf);
fputs(szBuf, stdout);
DBG_OUT_W_UTF8(szBuf);
fputs(szBuf, stdout);
#endif
if (isLogFile)
LogFile(szBuf);
if (isLogFile)
LogFile(szBuf);
#endif
}
void LogBoxf(const char* c_szFormat, ...)
{
va_list args;
va_start(args, c_szFormat);
va_list args;
va_start(args, c_szFormat);
char szBuf[2048];
_vsnprintf(szBuf, sizeof(szBuf), c_szFormat, args);
char szBuf[2048];
_vsnprintf_s(szBuf, sizeof(szBuf), _TRUNCATE, c_szFormat, args);
LogBox(szBuf);
va_end(args);
LogBox(szBuf);
}
void LogBox(const char* c_szMsg, const char * c_szCaption, HWND hWnd)
void LogBox(const char* c_szMsg, const char* c_szCaption, HWND hWnd)
{
if (!hWnd)
hWnd = g_PopupHwnd;
if (!hWnd)
hWnd = g_PopupHwnd;
MessageBox(hWnd, c_szMsg, c_szCaption ? c_szCaption : "LOG", MB_OK);
Tracen(c_szMsg);
std::wstring wMsg = Utf8ToWide(c_szMsg ? c_szMsg : "");
std::wstring wCaption = Utf8ToWide(c_szCaption ? c_szCaption : "LOG");
MessageBoxW(hWnd, wMsg.c_str(), wCaption.c_str(), MB_OK);
// Logging stays UTF-8
Tracen(c_szMsg ? c_szMsg : "");
}
void LogFile(const char * c_szMsg)
void LogFile(const char* c_szMsg)
{
CLogFile::Instance().Write(c_szMsg);
CLogFile::Instance().Write(c_szMsg);
}
void LogFilef(const char * c_szMessage, ...)
void LogFilef(const char* c_szMessage, ...)
{
va_list args;
va_start(args, c_szMessage);
char szBuf[DEBUG_STRING_MAX_LEN+1];
_vsnprintf(szBuf, sizeof(szBuf), c_szMessage, args);
va_list args;
va_start(args, c_szMessage);
CLogFile::Instance().Write(szBuf);
char szBuf[DEBUG_STRING_MAX_LEN + 1];
_vsnprintf_s(szBuf, sizeof(szBuf), _TRUNCATE, c_szMessage, args);
va_end(args);
CLogFile::Instance().Write(szBuf);
}
void OpenLogFile(bool bUseLogFIle)
{
#ifndef _DISTRIBUTE
freopen("syserr.txt", "w", stderr);
if (!std::filesystem::exists("log")) {
std::filesystem::create_directory("log");
}
if (bUseLogFIle)
{
isLogFile = true;
CLogFile::Instance().Initialize();
}
#ifndef _DISTRIBUTE
_wfreopen(L"log/syserr.txt", L"w", stderr);
if (bUseLogFIle)
{
isLogFile = true;
CLogFile::Instance().Initialize();
}
#endif
}
void OpenConsoleWindow()
{
AllocConsole();
AllocConsole();
freopen("CONOUT$", "a", stdout);
freopen("CONIN$", "r", stdin);
_wfreopen(L"CONOUT$", L"a", stdout);
_wfreopen(L"CONIN$", L"r", stdin);
}

View File

@@ -38,3 +38,9 @@ extern HWND g_PopupHwnd;
} \
#endif
#if defined(_DEBUG)
#define MD_ASSERT(expr) ((expr) ? true : (TraceError("MD_ASSERT('%s') failed at (%s:%d)", #expr, __FILE__, __LINE__), throw "ffs", false))
#else
#define MD_ASSERT(expr) ((expr) ? true : (TraceError("MD_ASSERT('%s') failed at (%s:%d)", #expr, __FILE__, __LINE__), false))
#endif

View File

@@ -1,6 +1,8 @@
#include "StdAfx.h"
#include "FileBase.h"
#include <utf8.h>
CFileBase::CFileBase() : m_hFile(NULL), m_dwSize(0)
{
}
@@ -34,9 +36,12 @@ BOOL CFileBase::Create(const char* filename, EFileMode mode)
{
Destroy();
// Keep filename internally as UTF-8 (engine side)
strncpy(m_filename, filename, MAX_PATH);
m_filename[MAX_PATH - 1] = '\0';
DWORD dwMode, dwShareMode = FILE_SHARE_READ;
DWORD dwMode;
DWORD dwShareMode = FILE_SHARE_READ;
if (mode == FILEMODE_WRITE)
{
@@ -44,19 +49,26 @@ BOOL CFileBase::Create(const char* filename, EFileMode mode)
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
}
else
{
dwMode = GENERIC_READ;
}
m_hFile = CreateFile(filename, // name of the file
dwMode, // desired access
dwShareMode, // share mode
NULL, // security attributes
mode == FILEMODE_READ ? OPEN_EXISTING : OPEN_ALWAYS, // creation disposition
FILE_ATTRIBUTE_NORMAL, // flags and attr
NULL); // template file
// UTF-8 -> UTF-16 conversion for WinAPI
std::wstring wFilename = Utf8ToWide(filename);
m_hFile = CreateFileW(
wFilename.c_str(), // UTF-16 path
dwMode,
dwShareMode,
nullptr,
(mode == FILEMODE_READ) ? OPEN_EXISTING : OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
nullptr
);
if (m_hFile != INVALID_HANDLE_VALUE)
{
m_dwSize = GetFileSize(m_hFile, NULL);
m_dwSize = GetFileSize(m_hFile, nullptr);
m_mode = mode;
return true;
}
@@ -64,7 +76,7 @@ BOOL CFileBase::Create(const char* filename, EFileMode mode)
/* char buf[256];
GetCurrentDirectory(256, buf);
DWORD dwErr = GetLastError();*/
m_hFile = NULL;
m_hFile = nullptr;
return false;
}
@@ -95,7 +107,7 @@ BOOL CFileBase::Write(const void* src, int bytes)
{
DWORD dwUseless;
BOOL ret = WriteFile(m_hFile, src, bytes, &dwUseless, NULL);
if (!ret)
return false;

View File

@@ -1,6 +1,7 @@
#include "StdAfx.h"
#include "FileDir.h"
#include <string>
#include <utf8.h>
CDir::CDir()
{
@@ -20,43 +21,46 @@ void CDir::Destroy()
Initialize();
}
bool CDir::Create(const char * c_szFilter, const char* c_szPath, BOOL bCheckedExtension)
bool CDir::Create(const char* c_szFilter, const char* c_szPath, BOOL bCheckedExtension)
{
Destroy();
std::string stPath = c_szPath;
if (stPath.length())
std::string stPath = c_szPath ? c_szPath : "";
if (!stPath.empty())
{
char end = stPath[stPath.length() - 1];
char end = stPath.back();
if (end != '\\')
stPath+='\\';
stPath += '\\';
}
std::string stQuery;
stQuery += stPath;
stQuery += "*.*";
m_wfd.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
m_hFind = FindFirstFile(stQuery.c_str(), &m_wfd);
// Query: UTF-8 -> UTF-16 for WinAPI
std::string stQueryUtf8 = stPath + "*.*";
std::wstring stQueryW = Utf8ToWide(stQueryUtf8);
m_wfd.dwFileAttributes = 0;
m_wfd.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
m_hFind = FindFirstFileW(stQueryW.c_str(), &m_wfd);
if (m_hFind == INVALID_HANDLE_VALUE)
return true;
do
{
if (*m_wfd.cFileName == '.')
// Convert filename to UTF-8 for existing logic/callbacks
std::string fileNameUtf8 = WideToUtf8(m_wfd.cFileName);
if (!fileNameUtf8.empty() && fileNameUtf8[0] == '.')
continue;
if (IsFolder())
if (IsFolder())
{
if (!OnFolder(c_szFilter, stPath.c_str(), m_wfd.cFileName))
if (!OnFolder(c_szFilter, stPath.c_str(), fileNameUtf8.c_str()))
return false;
}
else
{
const char * c_szExtension = strchr(m_wfd.cFileName, '.');
const char* c_szExtension = strchr(fileNameUtf8.c_str(), '.');
if (!c_szExtension)
continue;
@@ -65,27 +69,29 @@ bool CDir::Create(const char * c_szFilter, const char* c_szPath, BOOL bCheckedEx
// 그전에 전 프로젝트의 CDir을 사용하는 곳에서 Extension을 "wav", "gr2" 이런식으로 넣게끔 한다. - [levites]
if (bCheckedExtension)
{
std::string strFilter = c_szFilter;
int iPos = strFilter.find_first_of(';', 0);
std::string strFilter = c_szFilter ? c_szFilter : "";
int iPos = (int)strFilter.find_first_of(';', 0);
if (iPos > 0)
{
std::string strFirstFilter = std::string(c_szFilter).substr(0, iPos);
std::string strSecondFilter = std::string(c_szFilter).substr(iPos+1, strlen(c_szFilter));
if (0 != strFirstFilter.compare(c_szExtension+1) && 0 != strSecondFilter.compare(c_szExtension+1))
std::string first = strFilter.substr(0, iPos);
std::string second = strFilter.substr(iPos + 1);
if (0 != first.compare(c_szExtension + 1) &&
0 != second.compare(c_szExtension + 1))
continue;
}
else
{
if (0 != stricmp(c_szExtension+1, c_szFilter))
if (0 != _stricmp(c_szExtension + 1, c_szFilter))
continue;
}
}
if (!OnFile(stPath.c_str(), m_wfd.cFileName))
if (!OnFile(stPath.c_str(), fileNameUtf8.c_str()))
return false;
}
}
while (FindNextFile(m_hFind, &m_wfd));
} while (FindNextFileW(m_hFind, &m_wfd));
return true;
}
@@ -94,12 +100,12 @@ bool CDir::IsFolder()
{
if (m_wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
return true;
return false;
}
}
void CDir::Initialize()
{
memset(&m_wfd, 0, sizeof(m_wfd));
m_hFind = NULL;
m_hFind = NULL;
}

View File

@@ -1,6 +1,7 @@
#include "StdAfx.h"
#include "FileLoader.h"
#include <assert.h>
#include <utf8.h>
CMemoryTextFileLoader::CMemoryTextFileLoader()
{
@@ -252,7 +253,9 @@ bool CDiskFileLoader::Open(const char* c_szFileName)
if (!c_szFileName[0])
return false;
m_fp = fopen(c_szFileName, "rb");
// UTF-8 → UTF-16 conversion for Unicode path support
std::wstring wFileName = Utf8ToWide(c_szFileName);
m_fp = _wfopen(wFileName.c_str(), L"rb");
if (!m_fp)
return false;

View File

@@ -1,259 +0,0 @@
#include "StdAfx.h"
#include "MappedFile.h"
#include "Debug.h"
CMappedFile::CMappedFile() :
m_hFM(NULL),
m_lpMapData(NULL),
m_dataOffset(0),
m_mapSize(0),
m_seekPosition(0),
m_pLZObj(NULL),
m_pbBufLinkData(NULL),
m_dwBufLinkSize(0),
m_pbAppendResultDataBlock(NULL),
m_dwAppendResultDataSize(0)
{
}
CMappedFile::~CMappedFile()
{
Destroy();
}
BOOL CMappedFile::Create(const char * filename)
{
Destroy();
return CFileBase::Create(filename, FILEMODE_READ);
}
BOOL CMappedFile::Create(const char * filename, const void** dest, int offset, int size)
{
if (!CMappedFile::Create(filename))
return NULL;
int ret = Map(dest, offset, size);
return (ret) > 0;
}
LPCVOID CMappedFile::Get()
{
return m_lpData;
}
void CMappedFile::Link(DWORD dwBufSize, const void* c_pvBufData)
{
m_dwBufLinkSize=dwBufSize;
m_pbBufLinkData=(BYTE*)c_pvBufData;
}
void CMappedFile::BindLZObject(CLZObject * pLZObj)
{
assert(m_pLZObj == NULL);
m_pLZObj = pLZObj;
Link(m_pLZObj->GetSize(), m_pLZObj->GetBuffer());
}
void CMappedFile::BindLZObjectWithBufferedSize(CLZObject * pLZObj)
{
assert(m_pLZObj == NULL);
m_pLZObj = pLZObj;
Link(m_pLZObj->GetBufferSize(), m_pLZObj->GetBuffer());
}
BYTE* CMappedFile::AppendDataBlock( const void* pBlock, DWORD dwBlockSize )
{
if( m_pbAppendResultDataBlock )
{
delete []m_pbAppendResultDataBlock;
}
//realloc
m_dwAppendResultDataSize = m_dwBufLinkSize+dwBlockSize;
m_pbAppendResultDataBlock = new BYTE[m_dwAppendResultDataSize];
memcpy(m_pbAppendResultDataBlock, m_pbBufLinkData, m_dwBufLinkSize );
memcpy(m_pbAppendResultDataBlock + m_dwBufLinkSize, pBlock, dwBlockSize );
//redirect
Link(m_dwAppendResultDataSize, m_pbAppendResultDataBlock);
return m_pbAppendResultDataBlock;
}
void CMappedFile::Destroy()
{
if (m_pLZObj) // 압축된 데이터가 이 포인터로 연결 된다
{
delete m_pLZObj;
m_pLZObj = NULL;
}
if (NULL != m_lpMapData)
{
Unmap(m_lpMapData);
m_lpMapData = NULL;
}
if (NULL != m_hFM)
{
CloseHandle(m_hFM);
m_hFM = NULL;
}
if( m_pbAppendResultDataBlock )
{
delete []m_pbAppendResultDataBlock;
m_pbAppendResultDataBlock = NULL;
}
m_dwAppendResultDataSize = 0;
m_pbBufLinkData = NULL;
m_dwBufLinkSize = 0;
m_seekPosition = 0;
m_dataOffset = 0;
m_mapSize = 0;
CFileBase::Destroy();
}
int CMappedFile::Seek(DWORD offset, int iSeekType)
{
switch (iSeekType)
{
case SEEK_TYPE_BEGIN:
if (offset > m_dwSize)
offset = m_dwSize;
m_seekPosition = offset;
break;
case SEEK_TYPE_CURRENT:
m_seekPosition = std::min(m_seekPosition + offset, Size());
break;
case SEEK_TYPE_END:
m_seekPosition = std::max(0ul, Size() - offset);
break;
}
return m_seekPosition;
}
// 2004.09.16.myevan.MemoryMappedFile 98/ME 개수 제한 문제 체크
//DWORD g_dwCount=0;
int CMappedFile::Map(const void **dest, int offset, int size)
{
m_dataOffset = offset;
if (size == 0)
m_mapSize = m_dwSize;
else
m_mapSize = size;
if (m_dataOffset + m_mapSize > m_dwSize)
return NULL;
SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
DWORD dwSysGran = SysInfo.dwAllocationGranularity;
DWORD dwFileMapStart = (m_dataOffset / dwSysGran) * dwSysGran;
DWORD dwMapViewSize = (m_dataOffset % dwSysGran) + m_mapSize;
INT iViewDelta = m_dataOffset - dwFileMapStart;
m_hFM = CreateFileMapping(m_hFile, // handle
NULL, // security
PAGE_READONLY, // flProtect
0, // high
m_dataOffset + m_mapSize, // low
NULL); // name
if (!m_hFM)
{
OutputDebugString("CMappedFile::Map !m_hFM\n");
return NULL;
}
m_lpMapData = MapViewOfFile(m_hFM,
FILE_MAP_READ,
0,
dwFileMapStart,
dwMapViewSize);
if (!m_lpMapData) // Success
{
TraceError("CMappedFile::Map !m_lpMapData %lu", GetLastError());
return 0;
}
// 2004.09.16.myevan.MemoryMappedFile 98/ME 개수 제한 문제 체크
//g_dwCount++;
//Tracenf("MAPFILE %d", g_dwCount);
m_lpData = (char*) m_lpMapData + iViewDelta;
*dest = (char*) m_lpData;
m_seekPosition = 0;
Link(m_mapSize, m_lpData);
return (m_mapSize);
}
BYTE * CMappedFile::GetCurrentSeekPoint()
{
return m_pbBufLinkData+m_seekPosition;
//return m_pLZObj ? m_pLZObj->GetBuffer() + m_seekPosition : (BYTE *) m_lpData + m_seekPosition;
}
DWORD CMappedFile::Size()
{
return m_dwBufLinkSize;
/*
if (m_pLZObj)
return m_pLZObj->GetSize();
return (m_mapSize);
*/
}
DWORD CMappedFile::GetPosition()
{
return m_dataOffset;
}
BOOL CMappedFile::Read(void * dest, int bytes)
{
if (m_seekPosition + bytes > Size())
return FALSE;
memcpy(dest, GetCurrentSeekPoint(), bytes);
m_seekPosition += bytes;
return TRUE;
}
DWORD CMappedFile::GetSeekPosition(void)
{
return m_seekPosition;
}
void CMappedFile::Unmap(LPCVOID data)
{
if (UnmapViewOfFile(data))
{
// 2004.09.16.myevan.MemoryMappedFile 98/ME 개수 제한 문제 체크
//g_dwCount--;
//Tracenf("UNMAPFILE %d", g_dwCount);
}
else
{
TraceError("CMappedFile::Unmap - Error");
}
m_lpData = NULL;
}

View File

@@ -1,59 +0,0 @@
#ifndef __INC_MAPPEDFILE_H__
#define __INC_MAPPEDFILE_H__
#include "lzo.h"
#include "FileBase.h"
class CMappedFile : public CFileBase
{
public:
enum ESeekType
{
SEEK_TYPE_BEGIN,
SEEK_TYPE_CURRENT,
SEEK_TYPE_END
};
public:
CMappedFile();
virtual ~CMappedFile();
void Link(DWORD dwBufSize, const void* c_pvBufData);
BOOL Create(const char* filename);
BOOL Create(const char* filename, const void** dest, int offset, int size);
LPCVOID Get();
void Destroy();
int Seek(DWORD offset, int iSeekType = SEEK_TYPE_BEGIN);
int Map(const void **dest, int offset=0, int size=0);
DWORD Size();
DWORD GetPosition();
BOOL Read(void* dest, int bytes);
DWORD GetSeekPosition();
void BindLZObject(CLZObject * pLZObj);
void BindLZObjectWithBufferedSize(CLZObject * pLZObj);
BYTE* AppendDataBlock( const void* pBlock, DWORD dwBlockSize );
BYTE * GetCurrentSeekPoint();
private:
void Unmap(LPCVOID data);
private:
BYTE* m_pbBufLinkData;
DWORD m_dwBufLinkSize;
BYTE* m_pbAppendResultDataBlock;
DWORD m_dwAppendResultDataSize;
DWORD m_seekPosition;
HANDLE m_hFM;
DWORD m_dataOffset;
DWORD m_mapSize;
LPVOID m_lpMapData;
LPVOID m_lpData;
CLZObject * m_pLZObj;
};
#endif

View File

@@ -1,6 +0,0 @@
#ifndef _EL_SERVICEDEFS_H_
#define _EL_SERVICEDEFS_H_
#define _IMPROVED_PACKET_ENCRYPTION_
#endif //_EL_SERVICEDEFS_H_

View File

@@ -1,10 +1,5 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#pragma warning(disable:4710) // not inlined
#pragma warning(disable:4786) // character 255 넘어가는거 끄기
#pragma warning(disable:4244) // type conversion possible lose of data
@@ -53,4 +48,5 @@
#include "vk.h"
#include "filename.h"
#include "ServiceDefs.h"
#include "../UserInterface/Locale_inc.h"

View File

@@ -2,11 +2,17 @@
#include "TempFile.h"
#include "Utils.h"
#include "Debug.h"
#include <utf8.h>
CTempFile::~CTempFile()
{
Destroy();
DeleteFile(m_szFileName);
if (m_szFileName[0])
{
std::wstring wPath = Utf8ToWide(m_szFileName);
DeleteFileW(wPath.c_str());
}
}
CTempFile::CTempFile(const char * c_pszPrefix)

View File

@@ -5,24 +5,43 @@
#include <io.h>
#include <assert.h>
#include <sys/stat.h>
#include <utf8.h>
#include "Utils.h"
#include "filedir.h"
char korean_tolower(const char c);
const char * CreateTempFileName(const char * c_pszPrefix)
const char* CreateTempFileName(const char* c_pszPrefix)
{
char szTempPath[MAX_PATH + 1];
static char szTempName[MAX_PATH + 1];
static std::string s_utf8TempName; // safe static storage
GetTempPath(MAX_PATH, szTempPath);
wchar_t wTempPath[MAX_PATH + 1]{};
wchar_t wTempName[MAX_PATH + 1]{};
GetTempFileName(szTempPath, // directory for temp files
c_pszPrefix ? c_pszPrefix : "etb", // temp file name prefix
c_pszPrefix ? true : false, // create unique name
szTempName); // buffer for name
// Get temp directory
if (!GetTempPathW(MAX_PATH, wTempPath))
return "";
return (szTempName);
// Prefix must be wide
wchar_t wPrefix[4] = L"etb";
if (c_pszPrefix && *c_pszPrefix)
{
std::wstring wp = Utf8ToWide(c_pszPrefix);
wcsncpy_s(wPrefix, wp.c_str(), 3);
}
// Create temp file name
if (!GetTempFileNameW(
wTempPath,
wPrefix,
0, // unique number generated by system
wTempName))
return "";
// Convert result to UTF-8 for engine
s_utf8TempName = WideToUtf8(wTempName);
return s_utf8TempName.c_str();
}
void GetFilePathNameExtension(const char * c_szFile, int len, std::string * pstPath, std::string * pstName, std::string * pstExt)
@@ -41,10 +60,10 @@ void GetFilePathNameExtension(const char * c_szFile, int len, std::string * pstP
if (ext == len && c == '.')
{
ext = pos;
ext = pos;
break;
}
if (c == '/' || c == '\\')
break;
}
@@ -83,7 +102,7 @@ void GetFileExtension(const char* c_szFile, int len, std::string* pstExt)
char c=c_szFile[pos];
if (ext==len && c=='.')
{
ext=pos;
ext=pos;
break;
}
@@ -91,7 +110,7 @@ void GetFileExtension(const char* c_szFile, int len, std::string* pstExt)
else if (c=='\\') break;
}
++ext;
++ext;
if (len>ext)
pstExt->append(c_szFile+ext, len-ext);
}
@@ -110,7 +129,7 @@ void GetFileNameParts(const char* c_szFile, int len, char* pszPath, char* pszNam
char c=c_szFile[pos];
if (ext==len && c=='.')
{
ext=pos;
ext=pos;
break;
}
@@ -127,7 +146,7 @@ void GetFileNameParts(const char* c_szFile, int len, char* pszPath, char* pszNam
else if (c=='\\') break;
}
if (pos)
if (pos)
{
++pos;
for (int i = 0; i < pos; ++i)
@@ -147,7 +166,7 @@ void GetFileNameParts(const char* c_szFile, int len, char* pszPath, char* pszNam
pszName[count] = '\0';
}
++ext;
++ext;
if (len > ext)
{
int count = 0;
@@ -163,10 +182,10 @@ void GetOldIndexingName(char * szName, int Index)
{
int dec, sign;
char Temp[512];
strcpy(Temp, _ecvt(Index, 256, &dec, &sign));
Temp[dec] = '\0';
strcat(szName, Temp);
}
@@ -423,38 +442,40 @@ bool IsGlobalFileName(const char * c_szFileName)
return strchr(c_szFileName, ':') != NULL;
}
void MyCreateDirectory(const char* path)
void MyCreateDirectory(const char* pathUtf8)
{
if (!path || !*path)
if (!pathUtf8 || !*pathUtf8)
return;
char * dir;
const char * p;
// Skip drive letter (C:\)
const char* path = pathUtf8;
if (strlen(path) >= 3 && path[1] == ':')
path += 3;
if (strlen(path) >= 3)
{
if (*(path + 1) == ':') // C:, D: 같은 경우를 체크
path += 3;
}
size_t len = strlen(pathUtf8) + 1;
char* dirUtf8 = new char[len];
p = path;
int len = strlen(path) + 1;
dir = new char[len];
const char* p = path;
while (*p)
{
if (*p == '/' || *p == '\\')
{
memset(dir, 0, len);
strncpy(dir, path, p - path);
CreateDirectory(dir, NULL);
}
memset(dirUtf8, 0, len);
strncpy(dirUtf8, pathUtf8, p - path + (path - pathUtf8));
// UTF-8 → UTF-16 for WinAPI
std::wstring wDir = Utf8ToWide(dirUtf8);
CreateDirectoryW(wDir.c_str(), nullptr);
}
++p;
}
delete [] dir;
// Create final directory too
std::wstring wFinal = Utf8ToWide(pathUtf8);
CreateDirectoryW(wFinal.c_str(), nullptr);
delete[] dirUtf8;
}
class CDirRemover : public CDir
@@ -484,22 +505,31 @@ class CDirRemover : public CDir
ms_strDirectoryDeque.push_back(strWorkingFolder);
return true;
}
bool OnFile(const char* c_szPathName, const char* c_szFileName)
{
std::string strFullPathName;
strFullPathName = c_szPathName;
strFullPathName += c_szFileName;
_chmod(strFullPathName.c_str(), _S_IWRITE);
DeleteFile(strFullPathName.c_str());
strFullPathName += c_szFileName;
std::wstring wFullPath = Utf8ToWide(strFullPathName);
// Make writable (use wide version)
_wchmod(wFullPath.c_str(), _S_IWRITE);
// Delete (use wide WinAPI)
DeleteFileW(wFullPath.c_str());
return true;
}
static void RemoveAllDirectory()
{
for (std::deque<std::string>::iterator itor = ms_strDirectoryDeque.begin(); itor != ms_strDirectoryDeque.end(); ++itor)
for (std::deque<std::string>::iterator itor = ms_strDirectoryDeque.begin();
itor != ms_strDirectoryDeque.end(); ++itor)
{
const std::string & c_rstrDirectory = *itor;
RemoveDirectory(c_rstrDirectory.c_str());
const std::string& dirUtf8 = *itor;
std::wstring wDir = Utf8ToWide(dirUtf8);
RemoveDirectoryW(wDir.c_str());
}
ms_strDirectoryDeque.clear();
@@ -511,14 +541,19 @@ class CDirRemover : public CDir
std::deque<std::string> CDirRemover::ms_strDirectoryDeque;
void RemoveAllDirectory(const char * c_szDirectoryName)
void RemoveAllDirectory(const char* c_szDirectoryName)
{
{
CDirRemover remover;
remover.Create("*.*", c_szDirectoryName);
CDirRemover::RemoveAllDirectory();
}
RemoveDirectory(c_szDirectoryName);
if (c_szDirectoryName && *c_szDirectoryName)
{
std::wstring wDir = Utf8ToWide(c_szDirectoryName);
RemoveDirectoryW(wDir.c_str());
}
}
void StringExceptCharacter(std::string * pstrString, const char * c_szCharacter)
@@ -573,14 +608,15 @@ bool SplitLine(const char * c_szLine, const char * c_szDelimeter, std::vector<st
return true;
}
void GetExcutedFileName(std::string & r_str)
void GetExcutedFileName(std::string& r_str)
{
char szPath[MAX_PATH+1];
wchar_t wPath[MAX_PATH + 1]{};
GetModuleFileName(NULL, szPath, MAX_PATH);
szPath[MAX_PATH] = '\0';
GetModuleFileNameW(nullptr, wPath, MAX_PATH);
wPath[MAX_PATH] = L'\0';
r_str = szPath;
// Convert UTF-16 → UTF-8 for engine use
r_str = WideToUtf8(wPath);
}
const char * _getf(const char* c_szFormat, ...)

View File

@@ -27,12 +27,6 @@
#define AssertLog(str) TraceError(str); assert(!str)
#ifndef MAKEFOURCC
#define MAKEFOURCC(ch0, ch1, ch2, ch3) \
((DWORD)(BYTE) (ch0 ) | ((DWORD)(BYTE) (ch1) << 8) | \
((DWORD)(BYTE) (ch2) << 16) | ((DWORD)(BYTE) (ch3) << 24))
#endif // defined(MAKEFOURCC)
#ifndef IS_SET
#define IS_SET(flag,bit) ((flag) & (bit))
#endif
@@ -215,4 +209,18 @@ void StringExceptCharacter(std::string * pstrString, const char * c_szCharacter)
extern void GetExcutedFileName(std::string & r_str);
template<typename T>
constexpr T LinearInterpolation(const T& tMin, const T& tMax, float fRatio)
{
return T(tMin * (1.0f - fRatio) + tMax * fRatio);
}
template<typename T>
constexpr T HermiteInterpolation(const T& tMin, const T& tMax, float fRatio)
{
fRatio = MINMAX(0.0f, fRatio, 1.0f);
fRatio = fRatio * fRatio * (3.0f - 2.0f * fRatio);
return LinearInterpolation(tMin, tMax, fRatio);
}
#endif

View File

@@ -4,6 +4,7 @@
#include <time.h>
#include <winsock.h>
#include <imagehlp.h>
#include <utf8.h>
FILE* fException;
@@ -44,18 +45,21 @@ LONG __stdcall EterExceptionFilter(_EXCEPTION_POINTERS* pExceptionInfo)
HANDLE hProcess = GetCurrentProcess();
HANDLE hThread = GetCurrentThread();
fException = fopen("ErrorLog.txt", "wt");
fException = fopen("log/ErrorLog.txt", "wt");
if (fException)
{
char module_name[256];
wchar_t wModuleName[MAX_PATH]{};
time_t module_time;
HMODULE hModule = GetModuleHandle(NULL);
HMODULE hModule = GetModuleHandleW(nullptr);
GetModuleFileName(hModule, module_name, sizeof(module_name));
GetModuleFileNameW(hModule, wModuleName, MAX_PATH);
module_time = (time_t)GetTimestampForLoadedLibrary(hModule);
fprintf(fException, "Module Name: %s\n", module_name);
// Convert once for logging
std::string moduleNameUtf8 = WideToUtf8(wModuleName);
fprintf(fException, "Module Name: %s\n", moduleNameUtf8.c_str());
fprintf(fException, "Time Stamp: 0x%08x - %s\n", (unsigned int)module_time, ctime(&module_time));
fprintf(fException, "\n");
fprintf(fException, "Exception Type: 0x%08x\n", pExceptionInfo->ExceptionRecord->ExceptionCode);

View File

@@ -216,22 +216,14 @@ public:
public:
DecryptBuffer(unsigned size)
{
static unsigned count = 0;
static unsigned sum = 0;
static unsigned maxSize = 0;
sum += size;
count++;
maxSize = std::max(size, maxSize);
if (size >= LOCAL_BUF_SIZE)
{
m_buf = new char[size];
dbg_printf("DecryptBuffer - AllocHeap %d max(%d) ave(%d)\n", size, maxSize/1024, sum/count);
dbg_printf("DecryptBuffer - AllocHeap %d\n", size);
}
else
{
dbg_printf("DecryptBuffer - AllocStack %d max(%d) ave(%d)\n", size, maxSize/1024, sum/count);
dbg_printf("DecryptBuffer - AllocStack %d\n", size);
m_buf = m_local_buf;
}
}
@@ -239,12 +231,12 @@ public:
{
if (m_local_buf != m_buf)
{
dbg_printf("DecruptBuffer - FreeHeap\n");
dbg_printf("DecryptBuffer - FreeHeap\n");
delete [] m_buf;
}
else
{
dbg_printf("DecruptBuffer - FreeStack\n");
dbg_printf("DecryptBuffer - FreeStack\n");
}
}
void* GetBufferPtr()

View File

@@ -3,7 +3,8 @@
add_library(EterGrnLib STATIC ${FILE_SOURCES})
target_link_libraries(EterGrnLib
lzo2
cryptopp-static
mio
)
GroupSourcesByFolder(EterGrnLib)

153
src/EterGrnLib/Deform.cpp Normal file
View File

@@ -0,0 +1,153 @@
#include "Deform.h"
#include <xmmintrin.h>
#include <emmintrin.h>
void DeformPWNT3432toGrannyPNGBT33332D(granny_int32x Count, void const* SourceInit, void* DestInit,
granny_matrix_4x4 const* Transforms,
granny_int32x CopySize, granny_int32x SourceStride, granny_int32x DestStride)
{
const float inv255 = 1.0f / 255.0f;
const granny_pwnt3432_vertex* src = (const granny_pwnt3432_vertex*)SourceInit;
granny_pnt332_vertex* dst = (granny_pnt332_vertex*)DestInit;
while (Count--) {
const __m128 srcPos = _mm_set_ps(1.0f, src->Position[2], src->Position[1], src->Position[0]);
const __m128 srcNrm = _mm_set_ps(0.0f, src->Normal[2], src->Normal[1], src->Normal[0]);
const __m128 px = _mm_shuffle_ps(srcPos, srcPos, _MM_SHUFFLE(0, 0, 0, 0));
const __m128 py = _mm_shuffle_ps(srcPos, srcPos, _MM_SHUFFLE(1, 1, 1, 1));
const __m128 pz = _mm_shuffle_ps(srcPos, srcPos, _MM_SHUFFLE(2, 2, 2, 2));
const __m128 pw = _mm_shuffle_ps(srcPos, srcPos, _MM_SHUFFLE(3, 3, 3, 3));
const __m128 nx = _mm_shuffle_ps(srcNrm, srcNrm, _MM_SHUFFLE(0, 0, 0, 0));
const __m128 ny = _mm_shuffle_ps(srcNrm, srcNrm, _MM_SHUFFLE(1, 1, 1, 1));
const __m128 nz = _mm_shuffle_ps(srcNrm, srcNrm, _MM_SHUFFLE(2, 2, 2, 2));
__m128 P = _mm_setzero_ps();
__m128 N = _mm_setzero_ps();
for (int i = 0; i < 4; ++i) {
const int bi = src->BoneIndices[i];
const float wS = (float)src->BoneWeights[i] * inv255;
if (wS <= 0.0f) continue;
const float* m = (const float*)(&Transforms[bi]);
const __m128 r0 = _mm_loadu_ps(m + 0);
const __m128 r1 = _mm_loadu_ps(m + 4);
const __m128 r2 = _mm_loadu_ps(m + 8);
const __m128 r3 = _mm_loadu_ps(m + 12);
__m128 p = _mm_add_ps(_mm_mul_ps(r0, px), _mm_mul_ps(r1, py));
p = _mm_add_ps(p, _mm_mul_ps(r2, pz));
p = _mm_add_ps(p, _mm_mul_ps(r3, pw));
const __m128 w = _mm_set1_ps(wS);
P = _mm_add_ps(P, _mm_mul_ps(p, w));
__m128 n = _mm_add_ps(_mm_mul_ps(r0, nx), _mm_mul_ps(r1, ny));
n = _mm_add_ps(n, _mm_mul_ps(r2, nz));
N = _mm_add_ps(N, _mm_mul_ps(n, w));
}
float pOut[4], nOut[4];
_mm_storeu_ps(pOut, P);
_mm_storeu_ps(nOut, N);
dst->Position[0] = pOut[0];
dst->Position[1] = pOut[1];
dst->Position[2] = pOut[2];
dst->Normal[0] = nOut[0];
dst->Normal[1] = nOut[1];
dst->Normal[2] = nOut[2];
dst->UV[0] = src->UV[0];
dst->UV[1] = src->UV[1];
src = (const granny_pwnt3432_vertex*)((const granny_uint8*)src + SourceStride);
dst = (granny_pnt332_vertex*)((granny_uint8*)dst + DestStride);
}
}
void DeformPWNT3432toGrannyPNGBT33332I(granny_int32x Count, void const* SourceInit, void* DestInit,
granny_int32x const* TransformTable, granny_matrix_4x4 const* Transforms,
granny_int32x CopySize, granny_int32x SourceStride, granny_int32x DestStride)
{
const float inv255 = 1.0f / 255.0f;
const granny_pwnt3432_vertex* src = (const granny_pwnt3432_vertex*)SourceInit;
granny_pnt332_vertex* dst = (granny_pnt332_vertex*)DestInit;
while (Count--) {
const __m128 srcPos = _mm_set_ps(1.0f, src->Position[2], src->Position[1], src->Position[0]);
const __m128 srcNrm = _mm_set_ps(0.0f, src->Normal[2], src->Normal[1], src->Normal[0]);
const __m128 px = _mm_shuffle_ps(srcPos, srcPos, _MM_SHUFFLE(0, 0, 0, 0));
const __m128 py = _mm_shuffle_ps(srcPos, srcPos, _MM_SHUFFLE(1, 1, 1, 1));
const __m128 pz = _mm_shuffle_ps(srcPos, srcPos, _MM_SHUFFLE(2, 2, 2, 2));
const __m128 pw = _mm_shuffle_ps(srcPos, srcPos, _MM_SHUFFLE(3, 3, 3, 3));
const __m128 nx = _mm_shuffle_ps(srcNrm, srcNrm, _MM_SHUFFLE(0, 0, 0, 0));
const __m128 ny = _mm_shuffle_ps(srcNrm, srcNrm, _MM_SHUFFLE(1, 1, 1, 1));
const __m128 nz = _mm_shuffle_ps(srcNrm, srcNrm, _MM_SHUFFLE(2, 2, 2, 2));
__m128 P = _mm_setzero_ps();
__m128 N = _mm_setzero_ps();
for (int i = 0; i < 4; ++i) {
const int bi = TransformTable[src->BoneIndices[i]];
const float wS = (float)src->BoneWeights[i] * inv255;
if (wS <= 0.0f) continue;
const float* m = (const float*)(&Transforms[bi]);
const __m128 r0 = _mm_loadu_ps(m + 0);
const __m128 r1 = _mm_loadu_ps(m + 4);
const __m128 r2 = _mm_loadu_ps(m + 8);
const __m128 r3 = _mm_loadu_ps(m + 12);
__m128 p = _mm_add_ps(_mm_mul_ps(r0, px), _mm_mul_ps(r1, py));
p = _mm_add_ps(p, _mm_mul_ps(r2, pz));
p = _mm_add_ps(p, _mm_mul_ps(r3, pw));
const __m128 w = _mm_set1_ps(wS);
P = _mm_add_ps(P, _mm_mul_ps(p, w));
__m128 n = _mm_add_ps(_mm_mul_ps(r0, nx), _mm_mul_ps(r1, ny));
n = _mm_add_ps(n, _mm_mul_ps(r2, nz));
N = _mm_add_ps(N, _mm_mul_ps(n, w));
}
float pOut[4], nOut[4];
_mm_storeu_ps(pOut, P);
_mm_storeu_ps(nOut, N);
dst->Position[0] = pOut[0];
dst->Position[1] = pOut[1];
dst->Position[2] = pOut[2];
dst->Normal[0] = nOut[0];
dst->Normal[1] = nOut[1];
dst->Normal[2] = nOut[2];
dst->UV[0] = src->UV[0];
dst->UV[1] = src->UV[1];
src = (const granny_pwnt3432_vertex*)((const granny_uint8*)src + SourceStride);
dst = (granny_pnt332_vertex*)((granny_uint8*)dst + DestStride);
}
}
void DeformPWNT3432toGrannyPNGBT33332(granny_int32x Count, void const* SourceInit, void* DestInit,
granny_int32x const* TransformTable, granny_matrix_4x4 const* Transforms,
granny_int32x CopySize, granny_int32x SourceStride, granny_int32x DestStride)
{
if (TransformTable) {
DeformPWNT3432toGrannyPNGBT33332I(Count, SourceInit, DestInit, TransformTable, Transforms, CopySize, SourceStride, DestStride);
}
else {
DeformPWNT3432toGrannyPNGBT33332D(Count, SourceInit, DestInit, Transforms, CopySize, SourceStride, DestStride);
}
}

6
src/EterGrnLib/Deform.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#include <granny.h>
void DeformPWNT3432toGrannyPNGBT33332(granny_int32x Count, void const* SourceInit, void* DestInit,
granny_int32x const* TransformTable, granny_matrix_4x4 const* Transforms,
granny_int32x CopySize, granny_int32x SourceStride, granny_int32x DestStride);

View File

@@ -58,10 +58,10 @@ static CGraphicVertexBuffer* __AllocDeformVertexBuffer(unsigned deformableVertex
CGraphicVertexBuffer* pkNewVB = new CGraphicVertexBuffer;
if (!pkNewVB->Create(
capacity,
D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1,
D3DUSAGE_WRITEONLY,
D3DPOOL_MANAGED))
capacity,
D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1,
D3DUSAGE_DYNAMIC,
D3DPOOL_DEFAULT))
{
TraceError("NEW_ERROR %8d: %d(%d)", time(NULL) - base, capacity, deformableVertexCount);
}
@@ -101,10 +101,10 @@ void __ReserveSharedVertexBuffers(unsigned index, unsigned count)
{
CGraphicVertexBuffer* pkNewVB = new CGraphicVertexBuffer;
pkNewVB->Create(
capacity,
D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1,
D3DUSAGE_WRITEONLY,
D3DPOOL_MANAGED);
capacity,
D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1,
D3DUSAGE_DYNAMIC,
D3DPOOL_DEFAULT);
gs_vbs[index].push_back(pkNewVB);
}
NANOEND

View File

@@ -4,9 +4,9 @@
#include <windows.h>
#include <d3d9.h>
#include "../eterlib/ReferenceObject.h"
#include "../eterlib/Ref.h"
#include "../eterlib/GrpImageInstance.h"
#include "Eterlib/ReferenceObject.h"
#include "Eterlib/Ref.h"
#include "Eterlib/GrpImageInstance.h"
#include "Util.h"
class CGrannyMaterial : public CReferenceObject

View File

@@ -2,6 +2,7 @@
#include "Mesh.h"
#include "Model.h"
#include "Material.h"
#include "Deform.h"
granny_data_type_definition GrannyPNT3322VertexType[5] =
{
@@ -42,30 +43,45 @@ void CGrannyMesh::NEW_LoadVertices(void * dstBaseVertices)
GrannyCopyMeshVertices(pgrnMesh, m_pgrnMeshType, dstVertices);
}
void CGrannyMesh::DeformPNTVertices(void * dstBaseVertices, D3DXMATRIX * boneMatrices, granny_mesh_binding* pgrnMeshBinding) const
void CGrannyMesh::DeformPNTVertices(void* dstBaseVertices, D3DXMATRIX* boneMatrices, granny_mesh_binding* pgrnMeshBinding) const
{
assert(dstBaseVertices != NULL);
assert(boneMatrices != NULL);
assert(m_pgrnMeshDeformer != NULL);
const granny_mesh * pgrnMesh = GetGrannyMeshPointer();
const granny_mesh* pgrnMesh = GetGrannyMeshPointer();
TPNTVertex* srcVertices = (TPNTVertex*)GrannyGetMeshVertices(pgrnMesh);
TPNTVertex* dstVertices = ((TPNTVertex*)dstBaseVertices) + m_vtxBasePos;
TPNTVertex * srcVertices = (TPNTVertex *) GrannyGetMeshVertices(pgrnMesh);
TPNTVertex * dstVertices = ((TPNTVertex *) dstBaseVertices) + m_vtxBasePos;
int vtxCount = GrannyGetMeshVertexCount(pgrnMesh);
// WORK
granny_int32x * boneIndices = (granny_int32x*)GrannyGetMeshBindingToBoneIndices(pgrnMeshBinding);
granny_int32x* boneIndices = (granny_int32x*)GrannyGetMeshBindingToBoneIndices(pgrnMeshBinding);
// END_OF_WORK
GrannyDeformVertices(
m_pgrnMeshDeformer,
boneIndices,
(float *)boneMatrices,
vtxCount,
srcVertices,
dstVertices);
extern bool CPU_HAS_SSE2;
if (CPU_HAS_SSE2) {
DeformPWNT3432toGrannyPNGBT33332(
vtxCount,
srcVertices,
dstVertices,
boneIndices,
(granny_matrix_4x4 const*)boneMatrices,
sizeof(granny_pwnt3432_vertex),
sizeof(granny_pwnt3432_vertex),
sizeof(granny_pnt332_vertex)
);
}
else {
GrannyDeformVertices(
m_pgrnMeshDeformer,
boneIndices,
(float*)boneMatrices,
vtxCount,
srcVertices,
dstVertices);
}
}
bool CGrannyMesh::CanDeformPNTVertices() const

View File

@@ -109,7 +109,7 @@ bool CGrannyModel::LoadPNTVertices()
assert(m_meshs != NULL);
if (!m_pntVtxBuf.Create(m_rigidVtxCount, m_dwFvF, D3DUSAGE_WRITEONLY, D3DPOOL_MANAGED))
if (!m_pntVtxBuf.Create(m_rigidVtxCount, m_dwFvF, D3DUSAGE_WRITEONLY, D3DPOOL_DEFAULT))
return false;
void* vertices;
@@ -257,7 +257,7 @@ BOOL CGrannyModel::CheckMeshIndex(int iIndex) const
{
if (iIndex < 0)
return FALSE;
if (iIndex >= m_meshNodeSize)
if (iIndex >= GetMeshCount())
return FALSE;
return TRUE;
@@ -361,7 +361,7 @@ bool CGrannyModel::__LoadVertices()
// assert((m_dwFvF & (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)) == m_dwFvF);
// if (!m_pntVtxBuf.Create(m_rigidVtxCount, D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1, D3DUSAGE_WRITEONLY, D3DPOOL_MANAGED))
if (!m_pntVtxBuf.Create(m_rigidVtxCount, m_dwFvF, D3DUSAGE_WRITEONLY, D3DPOOL_MANAGED))
if (!m_pntVtxBuf.Create(m_rigidVtxCount, m_dwFvF, D3DUSAGE_WRITEONLY, D3DPOOL_DEFAULT))
return false;
void* vertices;

View File

@@ -1,7 +1,7 @@
#pragma once
#include "../eterlib/GrpVertexBuffer.h"
#include "../eterlib/GrpIndexBuffer.h"
#include "Eterlib/GrpVertexBuffer.h"
#include "Eterlib/GrpIndexBuffer.h"
#include "Mesh.h"

View File

@@ -1,7 +1,7 @@
#include "StdAfx.h"
#include "ModelInstance.h"
#include "Model.h"
#include "../EterLib/ResourceManager.h"
#include "EterLib/ResourceManager.h"
CGrannyModel* CGrannyModelInstance::GetModel()

View File

@@ -1,8 +1,8 @@
#pragma once
//#define CACHE_DEFORMED_VERTEX
#include "../eterlib/GrpImage.h"
#include "../eterlib/GrpCollisionObject.h"
#include "Eterlib/GrpImage.h"
#include "Eterlib/GrpCollisionObject.h"
#include "Model.h"
#include "Motion.h"

View File

@@ -176,7 +176,7 @@ bool CGrannyModelInstance::Intersect(const D3DXMATRIX * c_pMatrix,
*/
}
#include "../EterBase/Timer.h"
#include "EterBase/Timer.h"
void CGrannyModelInstance::GetBoundBox(D3DXVECTOR3* vtMin, D3DXVECTOR3* vtMax)
{

View File

@@ -232,9 +232,7 @@ void CGrannyModelInstance::__CreateDynamicVertexBuffer()
{
if (!m_kLocalDeformableVertexBuffer.Create(vtxCount,
D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1,
//D3DUSAGE_DYNAMIC, D3DPOOL_SYSTEMMEM
D3DUSAGE_WRITEONLY, D3DPOOL_MANAGED
D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT
))
return;
}

View File

@@ -1,11 +1,11 @@
#include "StdAfx.h"
#include "../eterlib/StateManager.h"
#include "Eterlib/StateManager.h"
#include "ModelInstance.h"
#include "Model.h"
#ifdef _TEST
#include "../eterlib/GrpScreen.h"
#include "Eterlib/GrpScreen.h"
void Granny_RenderBoxBones(const granny_skeleton* pkGrnSkeleton, const granny_world_pose* pkGrnWorldPose, const D3DXMATRIX& matBase)
{

View File

@@ -1,5 +1,5 @@
#include "StdAfx.h"
#include "../eterbase/Debug.h"
#include "Eterbase/Debug.h"
#include "ModelInstance.h"
#include "Model.h"

View File

@@ -5,9 +5,9 @@
//#include <crtdbg.h>
#include <granny.h>
#include "../eterBase/Utils.h"
#include "../eterBase/Debug.h"
#include "../eterBase/Stl.h"
#include "EterBase/Utils.h"
#include "EterBase/Debug.h"
#include "EterBase/Stl.h"
#include "Util.h"

View File

@@ -1,5 +1,5 @@
#include "StdAfx.h"
#include "../eterbase/Debug.h"
#include "Eterbase/Debug.h"
#include "Thing.h"
#include "ThingInstance.h"

View File

@@ -1,7 +1,7 @@
#include "StdAfx.h"
#include "../eterbase/Debug.h"
#include "../eterlib/Camera.h"
#include "../eterBase/Timer.h"
#include "Eterbase/Debug.h"
#include "Eterlib/Camera.h"
#include "EterBase/Timer.h"
#include "ThingInstance.h"
#include "Thing.h"
#include "ModelInstance.h"
@@ -534,7 +534,7 @@ void CGraphicThingInstance::RegisterMotionThing(DWORD dwMotionKey, CGraphicThing
{
CGraphicThing::TRef * pMotionRef = new CGraphicThing::TRef;
pMotionRef->SetPointer(pMotionThing);
m_roMotionThingMap.insert(std::map<DWORD, CGraphicThing::TRef *>::value_type(dwMotionKey, pMotionRef));
m_roMotionThingMap.insert(std::make_pair(dwMotionKey, pMotionRef));
}
void CGraphicThingInstance::ResetLocalTime()

View File

@@ -1,8 +1,8 @@
#pragma once
#include "../eterbase/Stl.h"
#include "../eterlib/GrpObjectInstance.h"
#include "../eterlib/GrpShadowTexture.h"
#include "Eterbase/Stl.h"
#include "Eterlib/GrpObjectInstance.h"
#include "Eterlib/GrpShadowTexture.h"
#include "LODController.h"

View File

@@ -3,7 +3,8 @@
add_library(EterImageLib STATIC ${FILE_SOURCES})
target_link_libraries(EterImageLib
lzo2
cryptopp-static
mio
)
GroupSourcesByFolder(EterImageLib)

File diff suppressed because it is too large Load Diff

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