From 9506c2fa9c6a0ecd1e714f9f2ca78fcb4f46d64e Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Fri, 12 Jul 2024 15:26:57 +0200 Subject: [PATCH] re-structure --- audio/AudioSetting.h | 36 + auth/Auth.h | 104 ++ compression/CRC.h | 73 ++ compression/LZP.h | 104 ++ database/Database.h | 78 ++ database/DatabaseConnection.h | 29 + database/DatabaseType.h | 19 + font/font_characters.txt | 1 + gpuapi/direct3d/UtilsDirect3d.h | 300 ++++++ gpuapi/opengl/UtilsOpengl.h | 319 ++++++ image/Bitmap.h | 291 ++++++ image/Image.h | 32 + image/Tga.h | 113 +++ input/Input.h | 116 +++ math/Animation.h | 19 + math/PerlinNoise.h | 54 + math/matrix/MatrixFloat32.h | 294 ++++++ math/matrix/MatrixInt32.h | 15 + math/matrix/MatrixInt64.h | 220 +++++ math/matrix/VectorFloat32.h | 173 ++++ math/matrix/VectorFloat64.h | 16 + math/matrix/VectorInt32.h | 157 +++ math/matrix/VectorInt64.h | 157 +++ models/Attrib.h | 33 + models/Colors.h | 0 models/Obj.h | 17 + models/Sound.h | 17 + models/Texture.h | 57 ++ models/chat/Chat.h | 51 + models/chat/ChatLevel.h | 20 + models/chat/ChatStatus.h | 19 + models/chat/ChatType.h | 20 + models/item/Equipment.h | 19 + models/item/EquipmentType.h | 25 + models/item/Item.h | 18 + models/item/equipment_slots.h | 27 + models/item/equipment_types.h | 115 +++ models/map.h | 0 models/mob/Mob.cpp | 39 + models/mob/Mob.h | 34 + models/mob/MobAction.h | 73 ++ models/mob/MobCategory.h | 0 models/mob/MobState.h | 30 + models/mob/MobStats.h | 6 + models/mob/mob_category.h | 15 + models/mob/mob_list.h | 14 + models/mob/monster/Drop.h | 20 + models/mob/monster/LootTable.h | 104 ++ models/mob/monster/Monster.h | 63 ++ models/mob/monster/MonsterStats.h | 22 + models/mob/player/Backpack.h | 119 +++ models/mob/player/Guild.h | 35 + models/mob/player/Player.cpp | 34 + models/mob/player/Player.h | 145 +++ models/mob/player/PlayerStats.h | 349 +++++++ models/mob/player/Reputation.h | 53 + models/object/Block.cpp | 83 ++ models/object/Block.h | 94 ++ models/object/Chunk.h | 55 ++ models/object/Cube.h | 37 + models/object/Object.h | 23 + models/object/ObjectType.h | 24 + models/object/object_list.h | 279 ++++++ models/object/object_types.h | 27 + models/settings/Settings.h | 359 +++++++ models/settings/client_high.cfg | 0 models/settings/client_low.cfg | 0 models/settings/client_medium.cfg | 0 models/settings/client_vhigh.cfg | 0 models/settings/client_vlow.cfg | 22 + models/settings/setting_types.h | 77 ++ network/Client.h | 84 ++ network/Server.h | 8 + network/SocketConnection.h | 27 + network/packet/PacketHeader.h | 103 ++ network/packet/UDPPacket.h | 83 ++ network/packet/chat/ChatMessagePacket.h | 24 + network/packet/mob/MobInfoPacket.h | 39 + network/packet/mob/MobStatePacket.h | 52 + network/packet/mob/player/PlayerInfoPacket.h | 85 ++ network/packet/mob/player/PlayerState.h | 12 + network/packet/packet_types.h | 88 ++ platform/linux/UtilsLinux.h | 54 + platform/win32/UtilsWin32.h | 369 +++++++ platform/win32/UtilsWindows.h | 86 ++ platform/win32/audio/DirectSound.h | 202 ++++ platform/win32/audio/XAudio2.h | 196 ++++ platform/win32/input/RawInput.h | 188 ++++ platform/win32/input/XInput.h | 131 +++ render/liquid.cpp | 0 render/mob.cpp | 0 render/object.cpp | 0 render/sky.cpp | 0 render/text.cpp | 0 shaders/liquids/lava.hlsl | 0 shaders/liquids/water/cube_fragment.hlsl | 13 + shaders/liquids/water/cube_vertex.hlsl | 8 + shaders/liquids/water/helper.hlsli | 130 +++ shaders/liquids/water/sphere_fragment.hlsl | 12 + shaders/liquids/water/sphere_vertex.hlsl | 8 + .../liquids/water/water_above_fragment.hlsl | 28 + .../liquids/water/water_below_fragment.hlsl | 30 + .../water/water_caustics_fragment.hlsl | 32 + .../liquids/water/water_caustics_vertex.hlsl | 38 + shaders/liquids/water/water_vertex.hlsl | 9 + shaders/nature/cloud.hlsl | 0 shaders/nature/fire.hlsl | 0 shaders/nature/fog.hlsl | 0 shaders/nature/godray.hlsl | 0 shaders/nature/lightning.hlsl | 0 shaders/nature/rain.hlsl | 0 shaders/nature/smoke.hlsl | 0 shaders/nature/snow.hlsl | 0 shaders/shaders.hlsl | 20 + stdlib/Intrinsics.h | 68 ++ stdlib/Mathtypes.h | 214 ++++ stdlib/Types.h | 109 ++ stdlib/simd/SIMD_F32.h | 931 ++++++++++++++++++ stdlib/simd/SIMD_F64.h | 38 + stdlib/simd/SIMD_Helper.h | 97 ++ stdlib/simd/SIMD_I32.h | 867 ++++++++++++++++ stdlib/simd/SIMD_I64.h | 39 + thread/Thread.h | 210 ++++ thread/ThreadJob.h | 44 + thread/ThreadOSWrapper.h | 286 ++++++ thread/ThreadPool.h | 41 + utils/BitUtils.h | 43 + utils/Compiler.h | 31 + utils/EndianUtils.h | 94 ++ utils/MathUtils.h | 61 ++ utils/RingMemory.h | 86 ++ utils/StringUtils.h | 200 ++++ utils/TestUtils.h | 182 ++++ utils/Utils.h | 72 ++ 134 files changed, 11265 insertions(+) create mode 100644 audio/AudioSetting.h create mode 100644 auth/Auth.h create mode 100644 compression/CRC.h create mode 100644 compression/LZP.h create mode 100644 database/Database.h create mode 100644 database/DatabaseConnection.h create mode 100644 database/DatabaseType.h create mode 100644 font/font_characters.txt create mode 100644 gpuapi/direct3d/UtilsDirect3d.h create mode 100644 gpuapi/opengl/UtilsOpengl.h create mode 100644 image/Bitmap.h create mode 100644 image/Image.h create mode 100644 image/Tga.h create mode 100644 input/Input.h create mode 100644 math/Animation.h create mode 100644 math/PerlinNoise.h create mode 100644 math/matrix/MatrixFloat32.h create mode 100644 math/matrix/MatrixInt32.h create mode 100644 math/matrix/MatrixInt64.h create mode 100644 math/matrix/VectorFloat32.h create mode 100644 math/matrix/VectorFloat64.h create mode 100644 math/matrix/VectorInt32.h create mode 100644 math/matrix/VectorInt64.h create mode 100644 models/Attrib.h create mode 100644 models/Colors.h create mode 100644 models/Obj.h create mode 100644 models/Sound.h create mode 100644 models/Texture.h create mode 100644 models/chat/Chat.h create mode 100644 models/chat/ChatLevel.h create mode 100644 models/chat/ChatStatus.h create mode 100644 models/chat/ChatType.h create mode 100644 models/item/Equipment.h create mode 100644 models/item/EquipmentType.h create mode 100644 models/item/Item.h create mode 100644 models/item/equipment_slots.h create mode 100644 models/item/equipment_types.h create mode 100644 models/map.h create mode 100644 models/mob/Mob.cpp create mode 100644 models/mob/Mob.h create mode 100644 models/mob/MobAction.h create mode 100644 models/mob/MobCategory.h create mode 100644 models/mob/MobState.h create mode 100644 models/mob/MobStats.h create mode 100644 models/mob/mob_category.h create mode 100644 models/mob/mob_list.h create mode 100644 models/mob/monster/Drop.h create mode 100644 models/mob/monster/LootTable.h create mode 100644 models/mob/monster/Monster.h create mode 100644 models/mob/monster/MonsterStats.h create mode 100644 models/mob/player/Backpack.h create mode 100644 models/mob/player/Guild.h create mode 100644 models/mob/player/Player.cpp create mode 100644 models/mob/player/Player.h create mode 100644 models/mob/player/PlayerStats.h create mode 100644 models/mob/player/Reputation.h create mode 100644 models/object/Block.cpp create mode 100644 models/object/Block.h create mode 100644 models/object/Chunk.h create mode 100644 models/object/Cube.h create mode 100644 models/object/Object.h create mode 100644 models/object/ObjectType.h create mode 100644 models/object/object_list.h create mode 100644 models/object/object_types.h create mode 100644 models/settings/Settings.h create mode 100644 models/settings/client_high.cfg create mode 100644 models/settings/client_low.cfg create mode 100644 models/settings/client_medium.cfg create mode 100644 models/settings/client_vhigh.cfg create mode 100644 models/settings/client_vlow.cfg create mode 100644 models/settings/setting_types.h create mode 100644 network/Client.h create mode 100644 network/Server.h create mode 100644 network/SocketConnection.h create mode 100644 network/packet/PacketHeader.h create mode 100644 network/packet/UDPPacket.h create mode 100644 network/packet/chat/ChatMessagePacket.h create mode 100644 network/packet/mob/MobInfoPacket.h create mode 100644 network/packet/mob/MobStatePacket.h create mode 100644 network/packet/mob/player/PlayerInfoPacket.h create mode 100644 network/packet/mob/player/PlayerState.h create mode 100644 network/packet/packet_types.h create mode 100644 platform/linux/UtilsLinux.h create mode 100644 platform/win32/UtilsWin32.h create mode 100644 platform/win32/UtilsWindows.h create mode 100644 platform/win32/audio/DirectSound.h create mode 100644 platform/win32/audio/XAudio2.h create mode 100644 platform/win32/input/RawInput.h create mode 100644 platform/win32/input/XInput.h create mode 100644 render/liquid.cpp create mode 100644 render/mob.cpp create mode 100644 render/object.cpp create mode 100644 render/sky.cpp create mode 100644 render/text.cpp create mode 100644 shaders/liquids/lava.hlsl create mode 100644 shaders/liquids/water/cube_fragment.hlsl create mode 100644 shaders/liquids/water/cube_vertex.hlsl create mode 100644 shaders/liquids/water/helper.hlsli create mode 100644 shaders/liquids/water/sphere_fragment.hlsl create mode 100644 shaders/liquids/water/sphere_vertex.hlsl create mode 100644 shaders/liquids/water/water_above_fragment.hlsl create mode 100644 shaders/liquids/water/water_below_fragment.hlsl create mode 100644 shaders/liquids/water/water_caustics_fragment.hlsl create mode 100644 shaders/liquids/water/water_caustics_vertex.hlsl create mode 100644 shaders/liquids/water/water_vertex.hlsl create mode 100644 shaders/nature/cloud.hlsl create mode 100644 shaders/nature/fire.hlsl create mode 100644 shaders/nature/fog.hlsl create mode 100644 shaders/nature/godray.hlsl create mode 100644 shaders/nature/lightning.hlsl create mode 100644 shaders/nature/rain.hlsl create mode 100644 shaders/nature/smoke.hlsl create mode 100644 shaders/nature/snow.hlsl create mode 100644 shaders/shaders.hlsl create mode 100644 stdlib/Intrinsics.h create mode 100644 stdlib/Mathtypes.h create mode 100644 stdlib/Types.h create mode 100644 stdlib/simd/SIMD_F32.h create mode 100644 stdlib/simd/SIMD_F64.h create mode 100644 stdlib/simd/SIMD_Helper.h create mode 100644 stdlib/simd/SIMD_I32.h create mode 100644 stdlib/simd/SIMD_I64.h create mode 100644 thread/Thread.h create mode 100644 thread/ThreadJob.h create mode 100644 thread/ThreadOSWrapper.h create mode 100644 thread/ThreadPool.h create mode 100644 utils/BitUtils.h create mode 100644 utils/Compiler.h create mode 100644 utils/EndianUtils.h create mode 100644 utils/MathUtils.h create mode 100644 utils/RingMemory.h create mode 100644 utils/StringUtils.h create mode 100644 utils/TestUtils.h create mode 100644 utils/Utils.h diff --git a/audio/AudioSetting.h b/audio/AudioSetting.h new file mode 100644 index 0000000..50ce6f0 --- /dev/null +++ b/audio/AudioSetting.h @@ -0,0 +1,36 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_AUDIO_SETTING_H +#define TOS_AUDIO_SETTING_H + +#include "../stdlib/Types.h" + +#define SOUND_API_DIRECT_SOUND 0 +#define SOUND_API_XAUDIO2 1 + +struct AudioSetting { + uint32 sample_rate; + uint32 sample_size; + uint32 sample_index; + uint32 latency; + + int16 volume; + + uint32 buffer_size; + + // Actual samples inside the buffer + // The buffer could be larger than the data to output + uint32 sample_buffer_size; + int16* buffer; + + bool is_playing = false; + byte type = SOUND_API_DIRECT_SOUND; +}; + +#endif diff --git a/auth/Auth.h b/auth/Auth.h new file mode 100644 index 0000000..14e4969 --- /dev/null +++ b/auth/Auth.h @@ -0,0 +1,104 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_AUTH_H +#define TOS_AUTH_H + +#include +#include +#include + +#include "../lib/curl/include/curl/curl.h" +#include "../utils/MathUtils.h" + +#define MAX_AUTH_POST_LENGTH 1024 +#define MAX_AUTH_RESPONSE_LENGTH 1024 + +/** + * Parse response data + * + * @param char* data Response data + * @param size_t size Response size + * @param count count Response count + * @param void* arg Parsed data + * + * @return size_t Parsed data size + */ +size_t write_function(char* data, size_t size, size_t count, void* arg) +{ + char* dst = (char *)arg; + size_t length = strlen(dst); + + // Ensure we do not exceed the buffer length + size_t available_space = OMS_MIN(MAX_AUTH_RESPONSE_LENGTH, strlen(dst)); + if (available_space > 0) { + strncat(dst, data, available_space - 1); + } + + dst[available_space - 1] = '\0'; + + return length; +} + +/** + * Get access token from remote source + * + * @param const char* url Access url + * @param char* access_token Url response (hopefully access token) + * @param const char* username Username for authentication + * @param const char* identity_token Identity token (e.g. password) + * + * @return int 0 for failure, > 0 for success + */ +int get_access_token( + const char* url, + char* access_token, + const char* username, + const char* identity_token +) +{ + CURL *curl = curl_easy_init(); + if (!curl) { + return 0; + } + + char post[MAX_AUTH_POST_LENGTH] = {}; + char response[MAX_AUTH_RESPONSE_LENGTH] = {}; + uint32 http_code = 0; + + snprintf( + post, + MAX_AUTH_POST_LENGTH, + "username=%s&identity_token=%s", + username, + identity_token + ); + + #ifdef _WIN32 + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + #endif + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_function); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, response); + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post); + + CURLcode code = curl_easy_perform(curl); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + curl_easy_cleanup(curl); + + if (code == CURLE_OK && http_code == 200) { + strncpy(access_token, response, strlen(response)); + + return 1; + } + + return 0; +} + +#endif \ No newline at end of file diff --git a/compression/CRC.h b/compression/CRC.h new file mode 100644 index 0000000..726aa03 --- /dev/null +++ b/compression/CRC.h @@ -0,0 +1,73 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_COMPRESSION_CRC_H +#define TOS_COMPRESSION_CRC_H + +#include "../stdlib/Types.h" + +uint32 crc_table[256] = +{ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; + +uint32 calculate_crc32_checksum(uint8 *p, uint32 length) +{ + uint32 crc = 0xFFFFFFFF; + while (length-- != 0) { + crc = crc_table[((uint8) crc ^ *(p++))] ^ (crc >> 8); + } + + // return (~crc); also works + return (crc ^ 0xFFFFFFFF); +} + +void fill_crc32_table(uint32 *table){ + uint8 index = 0,z; + do { + table[index] = index; + for(z = 8; z; z--) { + table[index] = (table[index] & 1) + ? (table[index] >> 1) ^ 0xEDB88320 + : table[index] >> 1; + } + } while(++index); +} + +#endif \ No newline at end of file diff --git a/compression/LZP.h b/compression/LZP.h new file mode 100644 index 0000000..93aba69 --- /dev/null +++ b/compression/LZP.h @@ -0,0 +1,104 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_COMPRESSION_LZP_H +#define TOS_COMPRESSION_LZP_H + +#include + +#include "../stdlib/Types.h" + +uint32 encode_lzp(const byte* in, size_t length, byte* out) +{ + byte buf[9]; + byte table[1 << 16] = {0}; + + uint16 hash = 0; + int32 i, j; + byte mask, c; + uint32 in_pos = 0, out_pos = 0; + + while(true) { + j = 1; + mask = 0; + for (i = 0; i < 8; ++i) { + if (in_pos == length) { + break; + } + + c = in[in_pos++]; + if (c == table[hash]) { + mask |= 1 << i; + } else { + table[hash] = c; + buf[j++] = c; + } + + hash = (hash << 4) ^ c; + } + + if (i > 0) { + buf[0] = mask; + for (i = 0; i < j; ++i) { + out[out_pos++] = buf[i]; + } + } + + if (in_pos == length) { + break; + } + } + + return out_pos; +} + +uint32 decode_lzp(const byte* in, size_t length, byte* out) +{ + byte buf[8]; + byte table[1 << 16] = {0}; + + uint16 hash = 0; + int i, j; + byte mask, c; + uint32 in_pos = 0, out_pos = 0; + + while (true) { + j = 0; + if (in_pos == length) { + break; + } + + mask = in[in_pos++]; + for (i = 0; i < 8; ++i) { + if ((mask & (1 << i)) != 0) { + c = table[hash]; + } else { + if (in_pos == length) { + break; + } + + c = in[in_pos++]; + table[hash] = c; + } + + buf[j++] = c; + + hash = (hash << 4) ^ c; + } + + if (j > 0) { + for (i = 0; i < j; ++i) { + out[out_pos++] = buf[i]; + } + } + } + + return out_pos; +} + +#endif \ No newline at end of file diff --git a/database/Database.h b/database/Database.h new file mode 100644 index 0000000..3cf5e95 --- /dev/null +++ b/database/Database.h @@ -0,0 +1,78 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_DATABASE +#define TOS_DATABASE + +#include "../stdlib/Types.h" +#include "../lib/sqlite/src/sqlite3.h" + +#include "DatabaseType.h" +#include "DatabaseConnection.h" + +inline +int db_open_sqlite(DatabaseConnection* con) +{ + int rc; + rc = sqlite3_open(con->host, &con->db_sqlite); + + if (rc) { + return rc; + } + + return 0; +} + +inline +int db_open(DatabaseConnection* con) +{ + switch (con->type) { + case DB_TYPE_SQLITE: { + return db_open_sqlite(con); + } + case DB_TYPE_MARIA: { + return 0; + } + case DB_TYPE_PSQL: { + return 0; + } + case DB_TYPE_MSSQL: { + return 0; + } + } + + return 0; +} + +inline +void db_close_sqlite(DatabaseConnection* con) +{ + sqlite3_close(con->db_sqlite); +} + +inline +void db_close(DatabaseConnection* con) +{ + switch (con->type) { + case DB_TYPE_SQLITE: { + db_close_sqlite(con); + return; + } + case DB_TYPE_MARIA: { + return; + } + case DB_TYPE_PSQL: { + return; + } + case DB_TYPE_MSSQL: { + return; + } + } +} + +#endif \ No newline at end of file diff --git a/database/DatabaseConnection.h b/database/DatabaseConnection.h new file mode 100644 index 0000000..898cb6e --- /dev/null +++ b/database/DatabaseConnection.h @@ -0,0 +1,29 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_DATABASE_CONNECTION +#define TOS_DATABASE_CONNECTION + +#include "../stdlib/Types.h" +#include "../lib/sqlite/src/sqlite3.h" + +#include "DatabaseType.h" + +struct DatabaseConnection { + union { + sqlite3* db_sqlite; + sqlite3* db_pgsql; + }; + + DatabaseType type; + uint16 port; + char* host; + char* name; // databse name +}; + +#endif \ No newline at end of file diff --git a/database/DatabaseType.h b/database/DatabaseType.h new file mode 100644 index 0000000..bfea785 --- /dev/null +++ b/database/DatabaseType.h @@ -0,0 +1,19 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_DATABASE_TYPE +#define TOS_DATABASE_TYPE + +enum DatabaseType { + DB_TYPE_SQLITE, + DB_TYPE_MARIA, + DB_TYPE_PSQL, + DB_TYPE_MSSQL +}; + +#endif \ No newline at end of file diff --git a/font/font_characters.txt b/font/font_characters.txt new file mode 100644 index 0000000..cf6b177 --- /dev/null +++ b/font/font_characters.txt @@ -0,0 +1 @@ + ︎☺︎☻︎♥︎♦︎♣︎♠︎•︎◘︎○︎◙︎♂︎♀︎♪︎♫︎☼︎►︎◄︎↕︎‼︎¶︎§︎▬︎↨︎↑︎↓︎→︎←︎∟︎↔︎▲︎▼︎ ︎!︎"︎#︎$︎%︎&︎'︎(︎)︎*︎+︎,︎-︎.︎/︎0︎1︎2︎3︎4︎5︎6︎7︎8︎9︎:︎;︎<︎=︎>︎?︎@︎A︎B︎C︎D︎E︎F︎G︎H︎I︎J︎K︎L︎M︎N︎O︎P︎Q︎R︎S︎T︎U︎V︎W︎X︎Y︎Z︎[︎\︎]︎^︎_︎`︎a︎b︎c︎d︎e︎f︎g︎h︎i︎j︎k︎l︎m︎n︎o︎p︎q︎r︎s︎t︎u︎v︎w︎x︎y︎z︎{︎¦︎}︎~︎⌂︎Ç︎ü︎é︎â︎ä︎à︎å︎ç︎ê︎ë︎è︎ï︎î︎ì︎Ä︎Å︎É︎æ︎Æ︎ô︎ö︎ò︎û︎ù︎ÿ︎Ö︎Ü︎¢︎£︎¥︎₧︎ƒ︎á︎í︎ó︎ú︎ñ︎Ñ︎ª︎º︎¿︎⌐︎¬︎½︎¼︎¡︎«︎»︎░︎▒︎▓︎│︎┤︎╡︎╢︎╖︎╕︎╣︎║︎╗︎╝︎╜︎╛︎┐︎└︎┴︎┬︎├︎─︎┼︎╞︎╟︎╚︎╔︎╩︎╦︎╠︎═︎╬︎╧︎╨︎╤︎╥︎╙︎╘︎╒︎╓︎╫︎╪︎┘︎┌︎█︎▄︎▌︎▐︎▀︎α︎ß︎Γ︎π︎Σ︎σ︎µ︎τ︎Φ︎Θ︎Ω︎δ︎∞︎φ︎ε︎∩︎≡︎±︎≥︎≤︎⌠︎⌡︎÷︎≈︎°︎∙︎·︎√︎ⁿ︎²︎■︎□︎ \ No newline at end of file diff --git a/gpuapi/direct3d/UtilsDirect3d.h b/gpuapi/direct3d/UtilsDirect3d.h new file mode 100644 index 0000000..8ccecbb --- /dev/null +++ b/gpuapi/direct3d/UtilsDirect3d.h @@ -0,0 +1,300 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_GPUAPI_DIRECT3D_UTILS +#define TOS_GPUAPI_DIRECT3D_UTILS + +#include +#include + +#include +#include "../../lib/directx/d3d12.h" +#include "../../lib/directx/d3dx12.h" + +#include "../../stdlib/Types.h" + +#define FRAME_COUNT 2 + +struct Window { + bool is_fullscreen; + int32 width; + int32 height; + char name[32]; + + int32 x; + int32 y; + + HWND hwnd; + + // @todo move this out of here to a separate gpuapi struct (same with opengl) + Microsoft::WRL::ComPtr m_swapChain; + + Microsoft::WRL::ComPtr device; + Microsoft::WRL::ComPtr m_renderTargets[FRAME_COUNT]; + Microsoft::WRL::ComPtr m_commandAllocator; + Microsoft::WRL::ComPtr m_commandQueue; + Microsoft::WRL::ComPtr m_rtvHeap; + Microsoft::WRL::ComPtr m_pipelineState; + Microsoft::WRL::ComPtr m_commandList; + Microsoft::WRL::ComPtr m_fence; + + UINT m_rtvDescriptorSize; + + UINT m_frameIndex; + HANDLE m_fenceEvent; + UINT64 m_fenceValue; +}; + +void window_create(Window* window, void* proc) +{ + WNDPROC wndproc = (WNDPROC) proc; + WNDCLASSEX wc = {}; + HINSTANCE hinstance = GetModuleHandle(0); + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_OWNDC; + wc.lpfnWndProc = wndproc; + wc.hInstance = hinstance; + wc.lpszClassName = (LPCWSTR) window->name; + + RegisterClassEx(&wc); + + if (window->is_fullscreen) { + window->width = GetSystemMetrics(SM_CXSCREEN); + window->height = GetSystemMetrics(SM_CYSCREEN); + + DEVMODE screen_settings; + + memset(&screen_settings, 0, sizeof(screen_settings)); + screen_settings.dmSize = sizeof(screen_settings); + screen_settings.dmPelsWidth = (unsigned long) window->width; + screen_settings.dmPelsHeight = (unsigned long) window->height; + screen_settings.dmBitsPerPel = 32; + screen_settings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + + ChangeDisplaySettings(&screen_settings, CDS_FULLSCREEN); + + window->x = 0; + window->y = 0; + } + + window->hwnd = CreateWindowEx((DWORD) NULL, + wc.lpszClassName, NULL, + WS_OVERLAPPEDWINDOW, + window->x, window->y, + window->width, + window->height, + NULL, NULL, hinstance, window + ); + + //SetWindowLongA(window->hwnd, GWL_STYLE, 0); +} + +void window_open(const Window* window) +{ + ShowWindow(window->hwnd, SW_SHOW); + SetForegroundWindow(window->hwnd); + SetFocus(window->hwnd); + ShowCursor(false); + UpdateWindow(window->hwnd); +} + +void window_close(Window* window) +{ + CloseWindow(window->hwnd); +} + +bool is_directx_12_supported() +{ + Microsoft::WRL::ComPtr factory; + HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory)); + if (FAILED(hr)) { + return false; + } + + Microsoft::WRL::ComPtr adapter; + for (UINT adapterIndex = 0; + DXGI_ERROR_NOT_FOUND != factory->EnumAdapters1(adapterIndex, &adapter); + ++adapterIndex) + { + DXGI_ADAPTER_DESC1 desc; + adapter->GetDesc1(&desc); + + // Skip software adapters + if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) { + continue; + } + + try { + if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) { + return true; + } + } catch (...) { + return false; + } + } + + return false; +} + +void find_hardware_adapter( + IDXGIFactory1* factory, + IDXGIAdapter1** adapter1, + bool use_high_performance_adapter = true +) { + *adapter1 = nullptr; + + Microsoft::WRL::ComPtr adapter; + Microsoft::WRL::ComPtr factory6; + + if (SUCCEEDED(factory->QueryInterface(IID_PPV_ARGS(&factory6)))) { + for ( + UINT adapterIndex = 0; + SUCCEEDED(factory6->EnumAdapterByGpuPreference( + adapterIndex, + use_high_performance_adapter == true ? DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE : DXGI_GPU_PREFERENCE_UNSPECIFIED, + IID_PPV_ARGS(&adapter))); + ++adapterIndex) + { + DXGI_ADAPTER_DESC1 desc; + adapter->GetDesc1(&desc); + + if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) { + // Don't select the Basic Render Driver adapter. + continue; + } + + // Check to see whether the adapter supports Direct3D 12, but don't create the + // actual device yet. + if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) { + break; + } + } + } + + if(adapter.Get() == nullptr) { + for (UINT adapterIndex = 0; SUCCEEDED(factory->EnumAdapters1(adapterIndex, &adapter)); ++adapterIndex) { + DXGI_ADAPTER_DESC1 desc; + adapter->GetDesc1(&desc); + + if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) { + // Don't select the Basic Render Driver adapter. + continue; + } + + // Check to see whether the adapter supports Direct3D 12, but don't create the + // actual device yet. + if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) { + break; + } + } + } + + *adapter1 = adapter.Detach(); +} + +void load_pipeline(Window* window) +{ + uint32 factory_flags = 0; + + Microsoft::WRL::ComPtr factory; + CreateDXGIFactory2(factory_flags, IID_PPV_ARGS(&factory)); + + Microsoft::WRL::ComPtr hardware_adapter; + find_hardware_adapter(factory.Get(), &hardware_adapter); + + D3D12CreateDevice( + hardware_adapter.Get(), + D3D_FEATURE_LEVEL_11_0, + IID_PPV_ARGS(&window->device) + ); + + // Describe and create the command queue. + D3D12_COMMAND_QUEUE_DESC queueDesc = {}; + queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + + window->device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&window->m_commandQueue)); + + // Describe and create the swap chain. + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; + swapChainDesc.BufferCount = FRAME_COUNT; + swapChainDesc.Width = window->width; + swapChainDesc.Height = window->height; + swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + swapChainDesc.SampleDesc.Count = 1; + + Microsoft::WRL::ComPtr swapChain; + factory->CreateSwapChainForHwnd( + window->m_commandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it. + window->hwnd, + &swapChainDesc, + nullptr, + nullptr, + &swapChain + ); + + // This sample does not support fullscreen transitions. + factory->MakeWindowAssociation(window->hwnd, DXGI_MWA_NO_ALT_ENTER); + + swapChain.As(&window->m_swapChain); + window->m_frameIndex = window->m_swapChain->GetCurrentBackBufferIndex(); + + // Create descriptor heaps. + { + // Describe and create a render target view (RTV) descriptor heap. + D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; + rtvHeapDesc.NumDescriptors = FRAME_COUNT; + rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + window->device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&window->m_rtvHeap)); + + window->m_rtvDescriptorSize = window->device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + } + + // Create frame resources. + { + CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(window->m_rtvHeap->GetCPUDescriptorHandleForHeapStart()); + + // Create a RTV for each frame. + for (UINT n = 0; n < FRAME_COUNT; n++) + { + window->m_swapChain->GetBuffer(n, IID_PPV_ARGS(&window->m_renderTargets[n])); + window->device->CreateRenderTargetView(window->m_renderTargets[n].Get(), nullptr, rtvHandle); + rtvHandle.Offset(1, window->m_rtvDescriptorSize); + } + } + + window->device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&window->m_commandAllocator)); +} + +void load_assets(Window* window) +{ + // Create the command list. + window->device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, window->m_commandAllocator.Get(), nullptr, IID_PPV_ARGS(&window->m_commandList)); + + // Command lists are created in the recording state, but there is nothing + // to record yet. The main loop expects it to be closed, so close it now. + window->m_commandList->Close(); + + // Create synchronization objects. + { + window->device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&window->m_fence)); + window->m_fenceValue = 1; + + // Create an event handle to use for frame synchronization. + window->m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (window->m_fenceEvent == nullptr) { + HRESULT_FROM_WIN32(GetLastError()); + } + } +} + +#endif \ No newline at end of file diff --git a/gpuapi/opengl/UtilsOpengl.h b/gpuapi/opengl/UtilsOpengl.h new file mode 100644 index 0000000..2a25066 --- /dev/null +++ b/gpuapi/opengl/UtilsOpengl.h @@ -0,0 +1,319 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_GPUAPI_OPENGL_UTILS_H +#define TOS_GPUAPI_OPENGL_UTILS_H + +#include "../../stdlib/Types.h" +#include "../../utils/RingMemory.h" +#include "../../models/Attrib.h" +#include "../../models/Texture.h" + +#include "../../lib/opengl/glew/include/GL/glew.h" +#include "../../lib/opengl/glfw/include/glfw3.h" + +#if GLFW_EXPOSE_NATIVE_WIN32 + #include "../../lib/opengl/glfw/include/glfw3native.h" +#endif + +#ifdef _WIN32 + #include + #include "../../platform/win32/UtilsWin32.h" +#endif + +struct Window { + bool is_fullscreen; + int32 width; + int32 height; + char name[32]; + + int32 x; + int32 y; + + GLFWwindow* hwnd_lib; + + #ifdef _WIN32 + HWND hwnd; + #endif +}; + +inline +void window_create(Window* window, void*) +{ + //GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + window->hwnd_lib = glfwCreateWindow( + window->width, + window->height, + window->name, + NULL, + NULL + ); + + glfwSetInputMode(window->hwnd_lib, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + glfwMakeContextCurrent(window->hwnd_lib); + glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); + + #if GLFW_EXPOSE_NATIVE_WIN32 + window->hwnd = glfwGetWin32Window(window->hwnd_lib); + #endif +} + +inline +void window_open(Window* window) +{ + glfwMakeContextCurrent(window->hwnd_lib); + glViewport(window->x, window->y, window->width, window->height); + glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); +} + +inline +void window_close(Window* window) +{ + glfwWindowShouldClose(window->hwnd_lib); +} + +inline +uint32 get_texture_data_type(uint32 texture_data_type) +{ + switch (texture_data_type) { + case TEXTURE_DATA_TYPE_2D: { + return GL_TEXTURE_2D; + } + case TEXTURE_DATA_TYPE_1D: { + return GL_TEXTURE_1D; + } + case TEXTURE_DATA_TYPE_3D: { + return GL_TEXTURE_3D; + } + case TEXTURE_DATA_TYPE_1D_ARRAY: { + return GL_TEXTURE_1D_ARRAY; + } + case TEXTURE_DATA_TYPE_2D_ARRAY: { + return GL_TEXTURE_2D_ARRAY; + } + case TEXTURE_DATA_TYPE_2D_MULTISAMPLED: { + return GL_TEXTURE_2D_MULTISAMPLE; + } + case TEXTURE_DATA_TYPE_2D_MULTISAMPLED_ARRAY: { + return GL_TEXTURE_2D_MULTISAMPLE_ARRAY; + } + default: { + return GL_TEXTURE_2D; + } + } +} + +inline +void prepare_texture(TextureFile* texture, uint32 texture_unit) +{ + if (texture->id) { + return; + } + + uint32 texture_data_type = get_texture_data_type(texture->texture_data_type); + + glGenTextures(1, (GLuint *) &texture->id); + glActiveTexture(GL_TEXTURE0 + texture_unit); + glBindTexture(texture_data_type, (GLuint) texture->id); +} + +inline +void load_texture_to_gpu(const TextureFile* texture) +{ + uint32 texture_data_type = get_texture_data_type(texture->texture_data_type); + glTexImage2D( + texture_data_type, 0, GL_RGBA, + texture->image.width, texture->image.height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, + texture->image.pixels + ); +} + +GLuint make_shader(GLenum type, const char *source, RingMemory* ring) +{ + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &source, NULL); + glCompileShader(shader); + + GLint status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + + if (status == GL_FALSE) { + GLint length; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); + + GLchar *info = (GLchar *) ring_get_memory(ring, length * sizeof(GLchar)); + + glGetShaderInfoLog(shader, length, NULL, info); + + // @todo use global logger + fprintf(stderr, "glCompileShader failed:\n%s\n", info); + } + + return shader; +} + +GLuint load_shader(GLenum type, const char *path, RingMemory* ring) { + uint64 temp = ring->pos; + + // @bug potential bug for shaders > 4 mb + file_body file; + file.content = ring_get_memory(ring, MEGABYTE * 4); + + file_read(path, &file); + GLuint result = make_shader(type, (const char *) file.content, ring); + + // 4 mb of memory reservation is a lot and since we immediately can dispose of it + // we can also reset our ring memory position + ring->pos = temp; + + return result; +} + +GLuint make_program(GLuint shader1, GLuint shader2, RingMemory* ring) { + GLuint program = glCreateProgram(); + + glAttachShader(program, shader1); + glAttachShader(program, shader2); + glLinkProgram(program); + + GLint status; + glGetProgramiv(program, GL_LINK_STATUS, &status); + + if (status == GL_FALSE) { + GLint length; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); + + GLchar *info = (GLchar *) ring_get_memory(ring, length * sizeof(GLchar)); + + glGetProgramInfoLog(program, length, NULL, info); + + // @todo use global logger + fprintf(stderr, "glLinkProgram failed: %s\n", info); + } + + glDetachShader(program, shader1); + glDetachShader(program, shader2); + glDeleteShader(shader1); + glDeleteShader(shader2); + + return program; +} + +GLuint load_program(const char *path1, const char *path2, RingMemory* ring) { + GLuint shader1 = load_shader(GL_VERTEX_SHADER, path1, ring); + GLuint shader2 = load_shader(GL_FRAGMENT_SHADER, path2, ring); + GLuint program = make_program(shader1, shader2, ring); + + return program; +} + +inline +void activate_texture(TextureFile* texture, uint32 texture_unit) +{ +} + +void draw_triangles_3d(Attrib *attrib, GLuint buffer, int count) { + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glEnableVertexAttribArray(attrib->position); + glEnableVertexAttribArray(attrib->normal); + glEnableVertexAttribArray(attrib->uv); + glVertexAttribPointer(attrib->position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, 0); + glVertexAttribPointer(attrib->normal, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLvoid *)(sizeof(GLfloat) * 3)); + glVertexAttribPointer(attrib->uv, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLvoid *)(sizeof(GLfloat) * 6)); + glDrawArrays(GL_TRIANGLES, 0, count); + glDisableVertexAttribArray(attrib->position); + glDisableVertexAttribArray(attrib->normal); + glDisableVertexAttribArray(attrib->uv); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void draw_triangles_2d(Attrib *attrib, GLuint buffer, size_t count) { + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glEnableVertexAttribArray(attrib->position); + glEnableVertexAttribArray(attrib->uv); + glVertexAttribPointer(attrib->position, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, 0); + glVertexAttribPointer(attrib->uv, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, (GLvoid *)(sizeof(GLfloat) * 2)); + glDrawArrays(GL_TRIANGLES, 0, (GLsizei) count); + glDisableVertexAttribArray(attrib->position); + glDisableVertexAttribArray(attrib->uv); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +inline +void draw_text(Attrib *attrib, GLuint buffer, size_t length) +{ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + draw_triangles_2d(attrib, buffer, length * 6); + glDisable(GL_BLEND); +} + +GLuint gen_text_buffer(float x, float y, float n, const char *text) { + size_t length = strlen(text); + GLfloat *data = NULL; //malloc_faces(4, length); // sizeof(GLfloat) * 6 * 4 * length + + for (int i = 0; i < length; i++) { + make_character(data + i * 24, x, y, n / 2, n, text[i]); + x += n; + } + + return 0; //gen_faces(4, length, data); +} + +inline +void render_text(Attrib *attrib, int justify, float x, float y, float n, const char *text) +{ + float matrix[16]; + //set_matrix_2d(matrix, g->width, g->height); + + glUseProgram(attrib->program); + glUniformMatrix4fv(attrib->matrix, 1, GL_FALSE, matrix); + glUniform1i(attrib->sampler, 1); + glUniform1i(attrib->extra1, 0); + + size_t length = strlen(text); + x -= n * justify * (length - 1) / 2; + + GLuint buffer = gen_text_buffer(x, y, n, text); + draw_text(attrib, buffer, length); + + glDeleteBuffers(1, &buffer); +} + +inline +int calculate_face_size(int components, int faces) +{ + return sizeof(GLfloat) * 6 * components * faces; +} + +// generates faces +// data is no longer needed after this +inline +GLuint gpuapi_buffer_generate(int size, GLfloat *data) +{ + GLuint buffer; + + glGenBuffers(1, &buffer); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + return buffer; +} + +inline +void gpuapi_buffer_delete(GLuint buffer) +{ + glDeleteBuffers(1, &buffer); +} + + + +#endif \ No newline at end of file diff --git a/image/Bitmap.h b/image/Bitmap.h new file mode 100644 index 0000000..af0bb76 --- /dev/null +++ b/image/Bitmap.h @@ -0,0 +1,291 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_IMAGE_BITMAP_H +#define TOS_IMAGE_BITMAP_H + +#include +#include + +#include "../stdlib/Types.h" +#include "../utils/Utils.h" +#include "../utils/EndianUtils.h" +#include "../utils/MathUtils.h" +#include "Image.h" + +// See: https://en.wikipedia.org/wiki/BMP_file_format +// IMPORTANT: Remember that we are not using packing for the headers +// Because of that the struct size is different from the actual header size in the file +// This means we have to manually asign the data to the headers + +#define BITMAP_HEADER_SIZE 14 +struct BitmapHeader { + byte identifier[2]; // 2 bytes - bitmap identifier + uint32 size; // 4 bytes - size in bytes + byte app_data[4]; // 4 bytes - generated by the image software + uint32 offset; // 4 bytes - defines starting address for pixels +}; + +#define DIB_BITMAP_TYPE_BITMAPCOREHEADER 12 +struct DIB_BITMAPCOREHEADER { + uint32 size; + uint16 width; + uint16 height; + uint16 color_planes; + uint16 bits_per_pixel; +}; + +#define DIB_BITMAP_TYPE_OS21XBITMAPHEADER DIB_BITMAP_TYPE_BITMAPCOREHEADER +#define DIB_OS21XBITMAPHEADER DIB_BITMAPCOREHEADER + +#define DIB_BITMAP_TYPE_OS22XBITMAPHEADER 64 +struct DIB_OS22XBITMAPHEADER { + // @todo implement + // They don't use a size as first value? how do I know if this is the correct header? +}; + +#define DIB_BITMAP_TYPE_BITMAPINFOHEADER 40 +struct DIB_BITMAPINFOHEADER { + uint32 size; + int32 width; + int32 height; + uint16 color_planes; + uint16 bits_per_pixel; + uint32 compression_method; + uint32 raw_image_size; + //int32 horizontal_ppm; + //int32 vertical_ppm; + uint32 color_palette; + uint32 important_colors; +}; + +#define DIB_BITMAPINFOHEADER_COMPRESSION_BI_RGB 0x0000 +#define DIB_BITMAPINFOHEADER_COMPRESSION_BI_RLE8 0x0001 +#define DIB_BITMAPINFOHEADER_COMPRESSION_BI_RLE4 0x0002 +#define DIB_BITMAPINFOHEADER_COMPRESSION_BI_BITFIELDS 0x0003 +#define DIB_BITMAPINFOHEADER_COMPRESSION_BI_JPEG 0x0004 +#define DIB_BITMAPINFOHEADER_COMPRESSION_BI_PNG 0x0005 +#define DIB_BITMAPINFOHEADER_COMPRESSION_BI_ALPHABITFIELDS 0x0006 +#define DIB_BITMAPINFOHEADER_COMPRESSION_BI_CMYK 0x000B +#define DIB_BITMAPINFOHEADER_COMPRESSION_BI_CMYKRLE8 0x000C +#define DIB_BITMAPINFOHEADER_COMPRESSION_BI_CMYKRLE4 0x000D + +#define DIB_BITMAPINFOHEADER_HALFTONING_NONE 0 +#define DIB_BITMAPINFOHEADER_HALFTONING_ERROR_DIFFUSION 1 +#define DIB_BITMAPINFOHEADER_HALFTONING_PANDA 2 +#define DIB_BITMAPINFOHEADER_HALFTONING_SUPER_CIRCLE 3 + +#define DIB_BITMAP_TYPE_BITMAPV2INFOHEADER 52 +struct DIB_BITMAPV2INFOHEADER { + +}; + +#define DIB_BITMAP_TYPE_BITMAPV3INFOHEADER 56 +struct DIB_BITMAPV3INFOHEADER { + +}; + +struct CIEXYZ { + int32 ciexyzX; + int32 ciexyzY; + int32 ciexyzZ; +}; + +struct CIEXYZTRIPLE { + CIEXYZ ciexyzRed; + CIEXYZ ciexyzGreen; + CIEXYZ ciexyzBlue; +}; + +#define DIB_BITMAP_TYPE_BITMAPV4HEADER 108 +struct DIB_BITMAPV4HEADER { + int32 size; + int32 width; + int32 height; + uint16 color_planes; + uint16 bits_per_pixel; + int32 compression_method; + int32 raw_image_size; + //int32 horizontal_ppm; + //int32 vertical_ppm; + uint32 color_palette; + uint32 important_colors; + + int32 bV4RedMask; + int32 bV4GreenMask; + int32 bV4BlueMask; + int32 bV4AlphaMask; + int32 bV4CSType; + CIEXYZTRIPLE bV4Endpoints; + int32 bV4GammaRed; + int32 bV4GammaGreen; + int32 bV4GammaBlue; +}; + +#define DIB_BITMAP_TYPE_BITMAPV5HEADER 124 +struct DIB_BITMAPV5HEADER { + int32 size; + int32 width; + int32 height; + uint16 color_planes; + uint16 bits_per_pixel; + int32 compression_method; + int32 raw_image_size; + //int32 horizontal_ppm; + //int32 vertical_ppm; + uint32 color_palette; + uint32 important_colors; + + int32 bV5RedMask; + int32 bV5GreenMask; + int32 bV5BlueMask; + int32 bV5AlphaMask; + int32 bV5CSType; + CIEXYZTRIPLE bV5Endpoints; + int32 bV5GammaRed; + int32 bV5GammaGreen; + int32 bV5GammaBlue; + int32 bV5Intent; + int32 bV5ProfileData; + int32 bV5ProfileSize; + int32 bV5Reserved; +}; + +struct Bitmap { + BitmapHeader header; + byte dib_header_type; + DIB_BITMAPINFOHEADER dib_header; // Despite the different header types we use this one for simplicity + uint32* extra_bit_mask; // 3-4 = 12-16 bytes + byte color_table_size; + byte* color_table; + + // Structure: + // 1. pixels stored in rows + // 2. rows are padded in multiples of 4 bytes + // 3. rows start from the bottom (unless the height is negative) + // 4. pixel data is stored in ABGR (graphics libraries usually need BGRA or RGBA) + byte* pixels; + + uint32 size; + byte* data; +}; + +void generate_default_bitmap_references(const file_body* file, Bitmap* bitmap) +{ + bitmap->size = file->size; + bitmap->data = file->content; + + // Fill header + bitmap->header.identifier[0] = *(file->content + 0); + bitmap->header.identifier[1] = *(file->content + 1); + + bitmap->header.size = SWAP_ENDIAN_LITTLE(*((uint32 *) (file->content + 2))); + bitmap->header.app_data[0] = *(file->content + 6); + bitmap->header.app_data[1] = *(file->content + 7); + bitmap->header.app_data[2] = *(file->content + 8); + bitmap->header.app_data[3] = *(file->content + 9); + bitmap->header.offset = SWAP_ENDIAN_LITTLE(*((uint32 *) (file->content + 10))); + + byte* dib_header_offset = file->content + BITMAP_HEADER_SIZE; + bitmap->dib_header_type = SWAP_ENDIAN_LITTLE(*((uint32 *) dib_header_offset)); + + byte* color_table_offset = file->content + BITMAP_HEADER_SIZE + bitmap->dib_header_type; + + // Fill DIB header + switch (bitmap->dib_header_type) { + case DIB_BITMAP_TYPE_BITMAPCOREHEADER: { + bitmap->dib_header.size = SWAP_ENDIAN_LITTLE(*((uint32 *) (dib_header_offset))); + bitmap->dib_header.width = SWAP_ENDIAN_LITTLE(*((uint16 *) (dib_header_offset + 4))); + bitmap->dib_header.height = SWAP_ENDIAN_LITTLE(*((uint16 *) (dib_header_offset + 6))); + bitmap->dib_header.color_planes = SWAP_ENDIAN_LITTLE(*((uint16 *) (dib_header_offset + 8))); + bitmap->dib_header.bits_per_pixel = SWAP_ENDIAN_LITTLE(*((uint16 *) (dib_header_offset + 10))); + bitmap->dib_header.color_palette = 1U << bitmap->dib_header.bits_per_pixel; + } break; + case DIB_BITMAP_TYPE_BITMAPV5HEADER: + case DIB_BITMAP_TYPE_BITMAPV4HEADER: + case DIB_BITMAP_TYPE_BITMAPV3INFOHEADER: + case DIB_BITMAP_TYPE_BITMAPV2INFOHEADER: + case DIB_BITMAP_TYPE_BITMAPINFOHEADER: { + bitmap->dib_header.size = SWAP_ENDIAN_LITTLE(*((uint32 *) (dib_header_offset))); + bitmap->dib_header.width = SWAP_ENDIAN_LITTLE(*((int32 *) (dib_header_offset + 4))); + bitmap->dib_header.height = SWAP_ENDIAN_LITTLE(*((int32 *) (dib_header_offset + 8))); + bitmap->dib_header.color_planes = SWAP_ENDIAN_LITTLE(*((uint16 *) (dib_header_offset + 12))); + bitmap->dib_header.bits_per_pixel = SWAP_ENDIAN_LITTLE(*((uint16 *) (dib_header_offset + 14))); + bitmap->dib_header.compression_method = SWAP_ENDIAN_LITTLE(*((uint32 *) (dib_header_offset + 16))); + bitmap->dib_header.raw_image_size = SWAP_ENDIAN_LITTLE(*((uint32 *) (dib_header_offset + 20))); + bitmap->dib_header.color_palette = SWAP_ENDIAN_LITTLE(*((uint32 *) (dib_header_offset + 32))); + bitmap->dib_header.important_colors = SWAP_ENDIAN_LITTLE(*((uint32 *) (dib_header_offset + 36))); + + if (bitmap->dib_header.compression_method == DIB_BITMAPINFOHEADER_COMPRESSION_BI_BITFIELDS) { + // 12 bytes + bitmap->extra_bit_mask = (uint32 *) (dib_header_offset + DIB_BITMAP_TYPE_BITMAPINFOHEADER); + color_table_offset += 12; + } else if (bitmap->dib_header.compression_method == DIB_BITMAPINFOHEADER_COMPRESSION_BI_ALPHABITFIELDS) { + // 16 bytes + bitmap->extra_bit_mask = (uint32 *) (dib_header_offset + DIB_BITMAP_TYPE_BITMAPINFOHEADER); + color_table_offset += 16; + } + } break; + default: { + + } + } + + // Fill other + bitmap->color_table = color_table_offset; + bitmap->pixels = (byte *) (file->content + bitmap->header.offset); +} + +void generate_bmp_image(const file_body* src_data, Image* image) +{ + Bitmap src = {}; + generate_default_bitmap_references(src_data, &src); + + image->width = src.dib_header.width; + image->height = src.dib_header.height; + image->length = image->width * image->height; + + // rows are 4 bytes multiples in length + uint32 width = ROUND_TO_NEAREST(src.dib_header.width, 4); + + uint32 pixel_bytes = src.dib_header.bits_per_pixel / 8; + if (image->order_pixels = IMAGE_PIXEL_ORDER_BGRA) { + memcpy((void *) image->pixels, src.pixels, image->length * pixel_bytes); + + return; + } + + byte alpha_offset = pixel_bytes == 3 ? 0 : 1; + + uint32 row_pos1 = 0; + uint32 row_pos2 = 0; + + for (uint32 y = 0; y < src.dib_header.height; ++y) { + for (uint32 x = 0; x < width; ++x) { + if (x >= image->width) { + // we don't care about the padding + continue; + } + + row_pos1 = y * width * pixel_bytes; + row_pos2 = (src.dib_header.height - y - 1) * width * pixel_bytes; + + // Invert byte order + for (uint32 i = 0; i < pixel_bytes - alpha_offset; ++i) { + image->pixels[row_pos1 + x * pixel_bytes + i] = src.pixels[row_pos2 + x * pixel_bytes + pixel_bytes - alpha_offset - i]; + } + + // Add alpha channel at end + if (alpha_offset > 0) { + image->pixels[row_pos1 + x * pixel_bytes + 3] = src.pixels[row_pos2 + x * pixel_bytes + pixel_bytes + 3]; + } + } + } +} + +#endif \ No newline at end of file diff --git a/image/Image.h b/image/Image.h new file mode 100644 index 0000000..a6719c9 --- /dev/null +++ b/image/Image.h @@ -0,0 +1,32 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_IMAGE_H +#define TOS_IMAGE_H + +#include "../stdlib/Types.h" + +#define IMAGE_PIXEL_ORDER_RGBA 0 +#define IMAGE_PIXEL_ORDER_BGRA 1 + +#define IMAGE_ROW_ORDER_TOP_TO_BOTTOM 0 +#define IMAGE_ROW_ORDER_BOTTOM_TO_TOP 1 + +struct Image { + uint32 width; + uint32 height; + uint32 length; + + bool has_alpha; + byte order_pixels; // RGBA vs BGRA + byte order_rows; // top-to-bottom vs bottom-to-top + + uint32* pixels; +}; + +#endif \ No newline at end of file diff --git a/image/Tga.h b/image/Tga.h new file mode 100644 index 0000000..9f39def --- /dev/null +++ b/image/Tga.h @@ -0,0 +1,113 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_IMAGE_TGA_H +#define TOS_IMAGE_TGA_H + +#include +#include "../stdlib/Types.h" +#include "../utils/Utils.h" +#include "../utils/EndianUtils.h" +#include "Image.h" + +// See: https://en.wikipedia.org/wiki/Truevision_TGA +// IMPORTANT: Remember that we are not using packing for the headers +// Because of that the struct size is different from the actual header size in the file +// This means we have to manually asign the data to the headers + +// Packed header size +#define TGA_HEADER_SIZE 18 +struct TgaHeader { + byte id_length; + byte color_map_type; + byte image_type; + uint16 color_map_index; + uint16 color_map_length; + uint16 color_map_bits; + uint16 x_origin; + uint16 y_origin; + uint16 width; + uint16 height; + byte bits_per_pixel; + byte alpha_bits_per_pixel; + byte horizonal_ordering; + byte vertical_ordering; +}; + +struct Tga { + TgaHeader header; + + byte* pixels; + + uint32 size; + byte* data; +}; + +void generate_default_tga_references(const file_body* file, Tga* tga) +{ + tga->header.id_length = file->content[0]; + tga->header.color_map_type = file->content[1]; + tga->header.image_type = file->content[2]; + tga->header.color_map_index = SWAP_ENDIAN_LITTLE(*((uint16 *) (file->content + 3))); + tga->header.color_map_length = SWAP_ENDIAN_LITTLE(*((uint16 *) (file->content + 5))); + tga->header.color_map_bits = file->content[7]; + tga->header.width = SWAP_ENDIAN_LITTLE(*((uint16 *) (file->content + 12))); + tga->header.height = SWAP_ENDIAN_LITTLE(*((uint16 *) (file->content + 14))); + tga->header.bits_per_pixel = file->content[16]; + tga->header.alpha_bits_per_pixel = file->content[17] & 0x07; + tga->header.horizonal_ordering = file->content[17] & (1 << 4); // 0 = left-to-right + tga->header.vertical_ordering = (file->content[17] & (1 << 5)) == 0 ? 1 : 0; // 0 = top-to-bottom + + tga->pixels = file->content + TGA_HEADER_SIZE + + tga->header.id_length // can be 0 + + tga->header.color_map_length * (tga->header.color_map_bits / 8); // can be 0 +} + +void generate_tga_image(const file_body* src_data, Image* image) +{ + Tga src = {}; + generate_default_tga_references(src_data, &src); + + image->width = src.header.width; + image->height = src.header.height; + image->length = image->width * image->height; + + // @todo also handle bottom-top/top-bottom order here + uint32 pixel_bytes = src.header.bits_per_pixel / 8; + if (image->order_pixels == IMAGE_PIXEL_ORDER_BGRA) { + memcpy((void *) image->pixels, src.pixels, image->length * pixel_bytes); + + return; + } + + byte alpha_offset = pixel_bytes == 3 ? 0 : 1; + uint32 pixel_rgb_bytes = pixel_bytes - alpha_offset; + + uint32 row_pos1; + uint32 row_pos2; + + for (uint32 y = 0; y < src.header.height; ++y) { + for (uint32 x = 0; x < src.header.width; ++x) { + row_pos1 = y * image->width * pixel_bytes; + row_pos2 = src.header.vertical_ordering == 0 + ? y * image->width * pixel_bytes + : (image->height - y - 1) * image->width * pixel_bytes; + + for (uint32 i = 0; i < pixel_rgb_bytes; ++i) { + image->pixels[row_pos1 + x * pixel_bytes + i] = src.pixels[row_pos2 + x * pixel_bytes + pixel_rgb_bytes - i]; + } + + // Add alpha channel at end + if (alpha_offset > 0) { + image->pixels[row_pos1 + x * pixel_bytes + 3] = src.pixels[row_pos2 + x * pixel_bytes + pixel_bytes + 3]; + } + } + } +} + +#endif \ No newline at end of file diff --git a/input/Input.h b/input/Input.h new file mode 100644 index 0000000..26be4b5 --- /dev/null +++ b/input/Input.h @@ -0,0 +1,116 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_INPUT_H +#define TOS_INPUT_H + +#define MAX_KEY_PRESSES 4 +#define MIN_INPUT_DEVICES 2 + +#define INPUT_TYPE_MOUSE 0x01 +#define INPUT_TYPE_KEYBOARD 0x02 +#define INPUT_TYPE_OTHER 0x03 + +#define MIN_CONTROLLER_DEVICES 4 + +#include "../stdlib/Types.h" + +#ifdef _WIN32 + #include +#endif + +struct InputState { + // Device + bool is_connected = false; + char name[256]; + byte type = INPUT_TYPE_OTHER; + double time; + + #ifdef _WIN32 + // @todo maybe replace with id?! + // -> remove _WIN32 section + HANDLE handle_keyboard; + HANDLE handle_mouse; + #endif + + // Keyboard + bool key_down = false; + bool key_up = false; + uint16 key = 0; + + // After handling the keyboard state change the game loop should set this to false + bool state_change_keyboard = false; + + // We only consider up to 4 pressed keys + // Depending on the keyboard you may only be able to detect a limited amount of key presses anyway + uint16 keys_down[MAX_KEY_PRESSES]; + + // Mouse + // After handling the mouse state change the game loop should set this to false + bool state_change_mouse = false; + + uint32 x; + uint32 y; + + uint32 x_last; + uint32 y_last; + + bool mouse1_down = false; + bool mouse1_up = false; + + bool mouse2_down = false; + bool mouse2_up = false; + + bool mouse3_down = false; + bool mouse3_up = false; + + bool mouse4_down = false; + bool mouse4_up = false; + + bool mouse5_down = false; + bool mouse5_up = false; + + int16 wheel_delta = 0; + uint32 raw_button = 0; +}; + +struct ControllerState { + uint32 id = 0; + bool is_connected = false; + + // After handling the state change the game loop should set this to false + bool state_change = false; + + bool up = false; + bool down = false; + bool left = false; + bool right = false; + bool start = false; + bool back = false; + + bool shoulder_left = false; + bool shoulder_right = false; + + byte trigger_left = 0; + byte trigger_right = 0; + + bool button_a = false; + bool button_b = false; + bool button_x = false; + bool button_y = false; + + int16 stickl_x = 0; + int16 stickl_y = 0; + bool stickl_press = false; + + int16 stickr_x = 0; + int16 stickr_y = 0; + bool stickr_press = false; +}; + +#endif \ No newline at end of file diff --git a/math/Animation.h b/math/Animation.h new file mode 100644 index 0000000..6c04f25 --- /dev/null +++ b/math/Animation.h @@ -0,0 +1,19 @@ +/** + * Jingga + * + * @package Utils + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MATH_ANIMATION +#define TOS_MATH_ANIMATION + +inline +float lerp_approx(float a, float b, float t) +{ + return a + t * (b - a); +} + +#endif \ No newline at end of file diff --git a/math/PerlinNoise.h b/math/PerlinNoise.h new file mode 100644 index 0000000..4a32195 --- /dev/null +++ b/math/PerlinNoise.h @@ -0,0 +1,54 @@ +#include +#include +#include "../stdlib/Intrinsics.h" +#include "Animation.h" + +double fade(double t) { + return t * t * t * (t * (t * 6 - 15) + 10); +} + +double grad(int hash, double x, double y, double z) +{ + int h = hash & 15; + + double u = h < 8 ? x : y; + double v = h < 4 ? y : h == 12 || h == 14 ? x : z; + + return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); +} + +// permutation = 512 elements +double noise(int* permutation, double x, double y, double z) +{ + int X = (int) floor(x) & 255; + int Y = (int) floor(y) & 255; + int Z = (int) floor(z) & 255; + + x -= floor(x); + y -= floor(y); + z -= floor(z); + + double u = fade(x), v = fade(y), w = fade(z); + + int A = permutation[X] + Y; + int AA = permutation[A] + Z; + int AB = permutation[A + 1] + Z; + + int B = permutation[X + 1] + Y; + int BA = permutation[B] + Z; + int BB = permutation[B + 1] + Z; + + return lerp_approx( + w, + lerp_approx( + v, + lerp_approx(u, grad(permutation[AA], x, y, z), grad(permutation[BA], x - 1, y, z)), + lerp_approx(u, grad(permutation[AB], x, y - 1, z), grad(permutation[BB], x - 1, y - 1, z)) + ), + lerp_approx( + v, + lerp_approx(u, grad(permutation[AA+1], x, y, z - 1), grad(permutation[BA + 1], x - 1, y, z - 1)), + lerp_approx(u, grad(permutation[AB+1], x, y - 1, z - 1), grad(permutation[BB+1], x - 1, y - 1, z - 1)) + ) + ); +} diff --git a/math/matrix/MatrixFloat32.h b/math/matrix/MatrixFloat32.h new file mode 100644 index 0000000..74d1d51 --- /dev/null +++ b/math/matrix/MatrixFloat32.h @@ -0,0 +1,294 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MATH_MATRIX_FLOAT32_H +#define TOS_MATH_MATRIX_FLOAT32_H + +#include "../../stdlib/Intrinsics.h" +#include "../../utils/MathUtils.h" + +void mat3_identity_f32(float* matrix) +{ + matrix[0] = 1.0f; matrix[1] = 0.0f; matrix[2] = 0.0f; + matrix[3] = 0.0f; matrix[4] = 1.0f; matrix[5] = 0.0f; + matrix[6] = 0.0f; matrix[7] = 0.0f; matrix[8] = 1.0f; +} + +void mat3_identity_f32(__m128* matrix) +{ + matrix[0] = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f); + matrix[1] = _mm_set_ps(0.0f, 1.0f, 0.0f, 0.0f); + matrix[2] = _mm_set_ps(0.0f, 0.0f, 1.0f, 0.0f); +} + +void mat4_identity_f32(float* matrix) +{ + matrix[0] = 1.0f; matrix[1] = 0.0f; matrix[2] = 0.0f; matrix[3] = 0.0f; + matrix[4] = 0.0f; matrix[5] = 1.0f; matrix[6] = 0.0f; matrix[7] = 0.0f; + matrix[8] = 0.0f; matrix[9] = 0.0f; matrix[10] = 1.0f; matrix[11] = 0.0f; + matrix[12] = 0.0f; matrix[13] = 0.0f; matrix[14] = 0.0f; matrix[15] = 1.0f; +} + +void mat4_identity_f32(__m128* matrix) +{ + matrix[0] = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f); + matrix[1] = _mm_set_ps(0.0f, 1.0f, 0.0f, 0.0f); + matrix[2] = _mm_set_ps(0.0f, 0.0f, 1.0f, 0.0f); + matrix[3] = _mm_set_ps(0.0f, 0.0f, 0.0f, 1.0f); +} + +void mat_translate_f32(float* matrix, float dx, float dy, float dz) +{ + matrix[0] = 1; matrix[1] = 0; matrix[2] = 0; matrix[3] = 0; + matrix[4] = 0; matrix[5] = 1; matrix[6] = 0; matrix[7] = 0; + matrix[8] = 0; matrix[9] = 0; matrix[10] = 1; matrix[11] = 0; + matrix[12] = dx; matrix[13] = dy; matrix[14] = dz; matrix[15] = 1; +} + +// x, y, z need to be normalized +void mat3_rotate(float* matrix, float x, float y, float z, float angle) +{ + float s = sinf_approx(angle); + float c = cosf_approx(angle); + float m = 1 - c; + + float mx = m * x; + float my = m * y; + float mz = m * z; + + float zs = z * s; + float xs = x * s; + float ys = y * s; + + float mxy = mx * y; + float mzx = mz * x; + float myz = my * z; + + matrix[0] = mx * x + c; + matrix[1] = mxy - zs; + matrix[2] = mzx + ys; + matrix[3] = 0; + + matrix[4] = mxy + zs; + matrix[5] = my * y + c; + matrix[6] = myz - xs; + matrix[7] = 0; + + matrix[8] = mzx - ys; + matrix[9] = myz + xs; + matrix[10] = mz * z + c; + matrix[11] = 0; + + matrix[12] = 0; + matrix[13] = 0; + matrix[14] = 0; + matrix[15] = 1; +} + +void mat3vec3_mult(const float* matrix, const float* vector, float* result) +{ + result[0] = matrix[0] * vector[0] + matrix[1] * vector[1] + matrix[2] * vector[2]; + result[1] = matrix[3] * vector[0] + matrix[4] * vector[1] + matrix[5] * vector[2]; + result[2] = matrix[6] * vector[0] + matrix[7] * vector[1] + matrix[8] * vector[2]; + + /* + for (int i = 0; i < 3; ++i) { + result[i] = matrix[i * 3 + 0] * vector[0] + + matrix[i * 3 + 1] * vector[1] + + matrix[i * 3 + 2] * vector[2]; + } + */ +} + +void mat3vec3_mult_sse(const float* matrix, const float* vector, float* result) +{ + __m128 vec = _mm_loadu_ps(vector); + vec = _mm_insert_ps(vec, _mm_setzero_ps(), 0x30); // vec[3] = 0 + + for (int i = 0; i < 3; ++i) { + __m128 row = _mm_loadu_ps(&matrix[i * 3]); + row = _mm_insert_ps(row, _mm_setzero_ps(), 0x30); // row[3] = 0 + + __m128 dot = _mm_dp_ps(row, vec, 0xF1); + + result[i] = _mm_cvtss_f32(dot); + } +} + +void mat3vec3_mult_sse(const __m128* matrix, const __m128* vector, float* result) +{ + for (int i = 0; i < 3; ++i) { + __m128 dot = _mm_dp_ps(matrix[i], *vector, 0xF1); + + result[i] = _mm_cvtss_f32(dot); + } +} + +void mat3vec3_mult_sse(const __m128* matrix, const __m128* vector, __m128* result) +{ + for (int i = 0; i < 4; ++i) { + result[i] = _mm_dp_ps(matrix[i], *vector, 0xF1); + } +} + +void mat4vec4_mult(const float* matrix, const float* vector, float* result) +{ + result[0] = matrix[0] * vector[0] + matrix[1] * vector[1] + matrix[2] * vector[2] + matrix[3] * vector[3]; + result[1] = matrix[4] * vector[0] + matrix[5] * vector[1] + matrix[6] * vector[2] + matrix[7] * vector[3]; + result[2] = matrix[8] * vector[0] + matrix[9] * vector[1] + matrix[10] * vector[2] + matrix[11] * vector[3]; + result[3] = matrix[12] * vector[0] + matrix[13] * vector[1] + matrix[14] * vector[2] + matrix[15] * vector[3]; + + /* + for (int i = 0; i < 4; ++i) { + result[i] = matrix[i * 4 + 0] * vector[0] + + matrix[i * 4 + 1] * vector[1] + + matrix[i * 4 + 2] * vector[2] + + matrix[i * 4 + 3] * vector[3]; + } + */ +} + +void mat4vec4_mult_sse(const float* matrix, const float* vector, float* result) +{ + __m128 vec = _mm_loadu_ps(vector); + + for (int i = 0; i < 4; ++i) { + __m128 row = _mm_loadu_ps(&matrix[i * 4]); + __m128 dot = _mm_dp_ps(row, vec, 0xF1); + + result[i] = _mm_cvtss_f32(dot); + } +} + +void mat4vec4_mult_sse(const __m128* matrix, const __m128* vector, float* result) +{ + for (int i = 0; i < 4; ++i) { + __m128 dot = _mm_dp_ps(matrix[i], *vector, 0xF1); + + result[i] = _mm_cvtss_f32(dot); + } +} + +void mat4vec4_mult_sse(const __m128* matrix, const __m128* vector, __m128* result) +{ + for (int i = 0; i < 4; ++i) { + result[i] = _mm_dp_ps(matrix[i], *vector, 0xF1); + } +} + +// @question Consider to replace with 1d array +void frustum_planes(float planes[6][4], int radius, float *matrix) { + // @todo make this a setting + float znear = 0.125; + float zfar = radius * 32 + 64; + + float *m = matrix; + + planes[0][0] = m[3] + m[0]; + planes[0][1] = m[7] + m[4]; + planes[0][2] = m[11] + m[8]; + planes[0][3] = m[15] + m[12]; + + planes[1][0] = m[3] - m[0]; + planes[1][1] = m[7] - m[4]; + planes[1][2] = m[11] - m[8]; + planes[1][3] = m[15] - m[12]; + + planes[2][0] = m[3] + m[1]; + planes[2][1] = m[7] + m[5]; + planes[2][2] = m[11] + m[9]; + planes[2][3] = m[15] + m[13]; + + planes[3][0] = m[3] - m[1]; + planes[3][1] = m[7] - m[5]; + planes[3][2] = m[11] - m[9]; + planes[3][3] = m[15] - m[13]; + + planes[4][0] = znear * m[3] + m[2]; + planes[4][1] = znear * m[7] + m[6]; + planes[4][2] = znear * m[11] + m[10]; + planes[4][3] = znear * m[15] + m[14]; + + planes[5][0] = zfar * m[3] - m[2]; + planes[5][1] = zfar * m[7] - m[6]; + planes[5][2] = zfar * m[11] - m[10]; + planes[5][3] = zfar * m[15] - m[14]; +} + +void mat_frustum( + float *matrix, float left, float right, float bottom, + float top, float znear, float zfar) +{ + float temp, temp2, temp3, temp4; + temp = 2.0 * znear; + temp2 = right - left; + temp3 = top - bottom; + temp4 = zfar - znear; + + matrix[0] = temp / temp2; + matrix[1] = 0.0; + matrix[2] = 0.0; + matrix[3] = 0.0; + + matrix[4] = 0.0; + matrix[5] = temp / temp3; + matrix[6] = 0.0; + matrix[7] = 0.0; + + matrix[8] = (right + left) / temp2; + matrix[9] = (top + bottom) / temp3; + matrix[10] = (-zfar - znear) / temp4; + matrix[11] = -1.0; + + matrix[12] = 0.0; + matrix[13] = 0.0; + matrix[14] = (-temp * zfar) / temp4; + matrix[15] = 0.0; +} + +void mat_perspective( + float *matrix, float fov, float aspect, + float znear, float zfar) +{ + float ymax, xmax; + ymax = znear * tanf_approx(fov * OMS_PI / 360.0); + xmax = ymax * aspect; + + mat_frustum(matrix, -xmax, xmax, -ymax, ymax, znear, zfar); +} + +void mat_ortho( + float *matrix, + float left, float right, float bottom, float top, float near, float far) +{ + float rl_delta = right - left; + float tb_delta = top - bottom; + float fn_delta = far - near; + + matrix[0] = 2 / rl_delta; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + + matrix[4] = 0; + matrix[5] = 2 / tb_delta; + matrix[6] = 0; + matrix[7] = 0; + + matrix[8] = 0; + matrix[9] = 0; + matrix[10] = -2 / fn_delta; + matrix[11] = 0; + + matrix[12] = -(right + left) / rl_delta; + matrix[13] = -(top + bottom) / tb_delta; + matrix[14] = -(far + near) / fn_delta; + matrix[15] = 1; +} + +#endif \ No newline at end of file diff --git a/math/matrix/MatrixInt32.h b/math/matrix/MatrixInt32.h new file mode 100644 index 0000000..814d394 --- /dev/null +++ b/math/matrix/MatrixInt32.h @@ -0,0 +1,15 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MATH_MATRIX_INT32_H +#define TOS_MATH_MATRIX_INT32_H + +#include "../../stdlib/Intrinsics.h" +#include "../../utils/MathUtils.h" + +#endif \ No newline at end of file diff --git a/math/matrix/MatrixInt64.h b/math/matrix/MatrixInt64.h new file mode 100644 index 0000000..784535e --- /dev/null +++ b/math/matrix/MatrixInt64.h @@ -0,0 +1,220 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MATH_MATRIX_INT64_H +#define TOS_MATH_MATRIX_INT64_H + +#include "../../stdlib/Intrinsics.h" +#include "../../utils/MathUtils.h" + +#endif + +// Remarks: sizes for the second matrix/vector are often implied by the first parameter and the rules for matrix/vector +// multiplication. + +// First element is always a matrix of int64_t +///////////////////////////////// + +///////////////////////////////// +// Multiplication +///////////////////////////////// + +// Array matrix multiplication +///////////////////////////////// +// mult_mat_int32(int64_t **a, size_t ai, size_t aj, int32_t **b) +// mult_mat_int64(int64_t **a, size_t ai, size_t aj, int64_t **b) +// mult_mat_float(int64_t **a, size_t ai, size_t aj, float **b) + +// mult_vec_int32(int64_t **a, size_t ai, size_t aj, int32_t *b) +// mult_vec_int64(int64_t **a, size_t ai, size_t aj, int64_t *b) +// mult_vec_float(int64_t **a, size_t ai, size_t aj, float *b) + +// mult_scal_int32(int64_t **a, size_t ai, size_t aj, int32_t b) +// mult_scal_int64(int64_t **a, size_t ai, size_t aj, int64_t b) +// mult_scal_float(int64_t **a, size_t ai, size_t aj, float b) + +// Modifies the original matrix +// vector 2 matrix multiplication +///////////////////////////////// +// v2_mult_mat_int32(v2 *a, size_t a, int32_t **b) +// v2_mult_mat_int64(v2 *a, size_t a, int64_t **b) +// v2_mult_mat_float(v2 *a, size_t a, float **b) +// v2_mult_mat_v2(v2 *a, size_t a, v2 *b) + +// v2_mult_vec_int32(v2 *a, size_t a, int32_t *b) +// v2_mult_vec_int64(v2 *a, size_t a, int64_t *b) +// v2_mult_vec_float(v2 *a, size_t a, float *b) +// v2_mult_vec_v2(v2 *a, size_t a, v2 *b) + +// v2_mult_scal_int32(v2 *a, size_t a, int32_t b) +// v2_mult_scal_int64(v2 *a, size_t a, int64_t b) +// v2_mult_scal_float(v2 *a, size_t a, float b) + +// vector 3 matrix multiplication +///////////////////////////////// +// v3_mult_mat_int32(v3 *a, size_t a, int32_t **b) +// v3_mult_mat_int64(v3 *a, size_t a, int64_t **b) +// v3_mult_mat_float(v3 *a, size_t a, float **b) +// v3_mult_mat_v3(v3 *a, size_t a, v3 *b) + +// v3_mult_vec_int32(v3 *a, size_t a, int32_t *b) +// v3_mult_vec_int64(v3 *a, size_t a, int64_t *b) +// v3_mult_vec_float(v3 *a, size_t a, float *b) +// v3_mult_vec_v3(v3 *a, size_t a, v3 *b) + +// v3_mult_scal_int32(v3 *a, size_t a, int32_t b) +// v3_mult_scal_int64(v3 *a, size_t a, int64_t b) +// v3_mult_scal_float(v3 *a, size_t a, float b) + +// vector 4 matrix multiplication +///////////////////////////////// +// v4_mult_mat_int32(v4 *a, size_t a, int32_t **b) +// v4_mult_mat_int64(v4 *a, size_t a, int64_t **b) +// v4_mult_mat_float(v4 *a, size_t a, float **b) +// v4_mult_mat_v4(v4 *a, size_t a, v4 *b) + +// v4_mult_vec_int32(v4 *a, size_t a, int32_t *b) +// v4_mult_vec_int64(v4 *a, size_t a, int64_t *b) +// v4_mult_vec_float(v4 *a, size_t a, float *b) +// v4_mult_vec_v4(v4 *a, size_t a, v4 *b) + +// v4_mult_scal_int32(v4 *a, size_t a, int32_t b) +// v4_mult_scal_int64(v4 *a, size_t a, int64_t b) +// v4_mult_scal_float(v4 *a, size_t a, float b) + +///////////////////////////////// +// Addition +///////////////////////////////// + +// Array matrix addition +///////////////////////////////// +// add_mat_int32(int64_t **a, size_t ai, size_t aj, int32_t **b) +// add_mat_int64(int64_t **a, size_t ai, size_t aj, int64_t **b) +// add_mat_float(int64_t **a, size_t ai, size_t aj, float **b) + +// add_vec_int32(int64_t **a, size_t ai, size_t aj, int32_t *b) +// add_vec_int64(int64_t **a, size_t ai, size_t aj, int64_t *b) +// add_vec_float(int64_t **a, size_t ai, size_t aj, float *b) + +// add_scal_int32(int64_t **a, size_t ai, size_t aj, int32_t b) +// add_scal_int64(int64_t **a, size_t ai, size_t aj, int64_t b) +// add_scal_float(int64_t **a, size_t ai, size_t aj, float b) + +// vector 2 matrix addition +///////////////////////////////// +// v2_add_mat_int32(v2 *a, size_t a, int32_t **b) +// v2_add_mat_int64(v2 *a, size_t a, int64_t **b) +// v2_add_mat_float(v2 *a, size_t a, float **b) +// v2_add_mat_v2(v2 *a, size_t a, v2 *b) + +// v2_add_vec_int32(v2 *a, size_t a, int32_t *b) +// v2_add_vec_int64(v2 *a, size_t a, int64_t *b) +// v2_add_vec_float(v2 *a, size_t a, float *b) +// v2_add_vec_v2(v2 *a, size_t a, v2 *b) + +// v2_add_scal_int32(v2 *a, size_t a, int32_t b) +// v2_add_scal_int64(v2 *a, size_t a, int64_t b) +// v2_add_scal_float(v2 *a, size_t a, float b) + +// vector 3 matrix addition +///////////////////////////////// +// v3_add_mat_int32(v3 *a, size_t a, int32_t **b) +// v3_add_mat_int64(v3 *a, size_t a, int64_t **b) +// v3_add_mat_float(v3 *a, size_t a, float **b) +// v3_add_mat_v3(v3 *a, size_t a, v3 *b) + +// v3_add_vec_int32(v3 *a, size_t a, int32_t *b) +// v3_add_vec_int64(v3 *a, size_t a, int64_t *b) +// v3_add_vec_float(v3 *a, size_t a, float *b) +// v3_add_vec_v3(v3 *a, size_t a, v3 *b) + +// v3_add_scal_int32(v3 *a, size_t a, int32_t b) +// v3_add_scal_int64(v3 *a, size_t a, int64_t b) +// v3_add_scal_float(v3 *a, size_t a, float b) + +// vector 4 matrix addition +///////////////////////////////// +// v4_add_mat_int32(v4 *a, size_t a, int32_t **b) +// v4_add_mat_int64(v4 *a, size_t a, int64_t **b) +// v4_add_mat_float(v4 *a, size_t a, float **b) +// v4_add_mat_v4(v4 *a, size_t a, v4 *b) + +// v4_add_vec_int32(v4 *a, size_t a, int32_t *b) +// v4_add_vec_int64(v4 *a, size_t a, int64_t *b) +// v4_add_vec_float(v4 *a, size_t a, float *b) +// v4_add_vec_v4(v4 *a, size_t a, v4 *b) + +// v4_add_scal_int32(v4 *a, size_t a, int32_t b) +// v4_add_scal_int64(v4 *a, size_t a, int64_t b) +// v4_add_scal_float(v4 *a, size_t a, float b) + +///////////////////////////////// +// Subtraction +///////////////////////////////// + +// Array matrix subtraction +///////////////////////////////// +// sub_mat_int32(int64_t **a, size_t ai, size_t aj, int32_t **b) +// sub_mat_int64(int64_t **a, size_t ai, size_t aj, int64_t **b) +// sub_mat_float(int64_t **a, size_t ai, size_t aj, float **b) + +// sub_vec_int32(int64_t **a, size_t ai, size_t aj, int32_t *b) +// sub_vec_int64(int64_t **a, size_t ai, size_t aj, int64_t *b) +// sub_vec_float(int64_t **a, size_t ai, size_t aj, float *b) + +// sub_scal_int32(int64_t **a, size_t ai, size_t aj, int32_t b) +// sub_scal_int64(int64_t **a, size_t ai, size_t aj, int64_t b) +// sub_scal_float(int64_t **a, size_t ai, size_t aj, float b) + +// vector 2 matrix subtraction +///////////////////////////////// +// v2_sub_mat_int32(v2 *a, size_t a, int32_t **b) +// v2_sub_mat_int64(v2 *a, size_t a, int64_t **b) +// v2_sub_mat_float(v2 *a, size_t a, float **b) +// v2_sub_mat_v2(v2 *a, size_t a, v2 *b) + +// v2_sub_vec_int32(v2 *a, size_t a, int32_t *b) +// v2_sub_vec_int64(v2 *a, size_t a, int64_t *b) +// v2_sub_vec_float(v2 *a, size_t a, float *b) +// v2_sub_vec_v2(v2 *a, size_t a, v2 *b) + +// v2_sub_scal_int32(v2 *a, size_t a, int32_t b) +// v2_sub_scal_int64(v2 *a, size_t a, int64_t b) +// v2_sub_scal_float(v2 *a, size_t a, float b) + +// vector 3 matrix subtraction +///////////////////////////////// +// v3_sub_mat_int32(v3 *a, size_t a, int32_t **b) +// v3_sub_mat_int64(v3 *a, size_t a, int64_t **b) +// v3_sub_mat_float(v3 *a, size_t a, float **b) +// v3_sub_mat_v3(v3 *a, size_t a, v3 *b) + +// v3_sub_vec_int32(v3 *a, size_t a, int32_t *b) +// v3_sub_vec_int64(v3 *a, size_t a, int64_t *b) +// v3_sub_vec_float(v3 *a, size_t a, float *b) +// v3_sub_vec_v3(v3 *a, size_t a, v3 *b) + +// v3_sub_scal_int32(v3 *a, size_t a, int32_t b) +// v3_sub_scal_int64(v3 *a, size_t a, int64_t b) +// v3_sub_scal_float(v3 *a, size_t a, float b) + +// vector 4 matrix subtraction +///////////////////////////////// +// v4_sub_mat_int32(v4 *a, size_t a, int32_t **b) +// v4_sub_mat_int64(v4 *a, size_t a, int64_t **b) +// v4_sub_mat_float(v4 *a, size_t a, float **b) +// v4_sub_mat_v4(v4 *a, size_t a, v4 *b) + +// v4_sub_vec_int32(v4 *a, size_t a, int32_t *b) +// v4_sub_vec_int64(v4 *a, size_t a, int64_t *b) +// v4_sub_vec_float(v4 *a, size_t a, float *b) +// v4_sub_vec_v4(v4 *a, size_t a, v4 *b) + +// v4_sub_scal_int32(v4 *a, size_t a, int32_t b) +// v4_sub_scal_int64(v4 *a, size_t a, int64_t b) +// v4_sub_scal_float(v4 *a, size_t a, float b) diff --git a/math/matrix/VectorFloat32.h b/math/matrix/VectorFloat32.h new file mode 100644 index 0000000..a52b145 --- /dev/null +++ b/math/matrix/VectorFloat32.h @@ -0,0 +1,173 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MATH_MATRIX_VECTOR_FLOAT32_H +#define TOS_MATH_MATRIX_VECTOR_FLOAT32_H + +#include "../../stdlib/Intrinsics.h" +#include "../../utils/MathUtils.h" +#include "../../stdlib/simd/SIMD_F32.h" + +struct v3_f32_4 { + union { + struct { + union { + f32_4 x; + f32_4 r; + }; + union { + f32_4 y; + f32_4 g; + }; + union { + f32_4 z; + f32_4 b; + }; + }; + + f32_4 v[3]; + }; +}; + +struct v3_f32_8 { + union { + struct { + union { + f32_8 x; + f32_8 r; + }; + union { + f32_8 y; + f32_8 g; + }; + union { + f32_8 z; + f32_8 b; + }; + }; + + f32_8 v[3]; + }; +}; + +struct v3_f32_16 { + union { + struct { + union { + f32_16 x; + f32_16 r; + }; + union { + f32_16 y; + f32_16 g; + }; + union { + f32_16 z; + f32_16 b; + }; + }; + + f32_16 v[3]; + }; +}; + +struct v4_f32_4 { + union { + struct { + union { + f32_4 x; + f32_4 r; + }; + union { + f32_4 y; + f32_4 g; + }; + union { + f32_4 z; + f32_4 b; + }; + union { + f32_4 w; + f32_4 a; + }; + }; + + f32_4 v[4]; + }; +}; + +struct v4_f32_8 { + union { + struct { + union { + f32_8 x; + f32_8 r; + }; + union { + f32_8 y; + f32_8 g; + }; + union { + f32_8 z; + f32_8 b; + }; + union { + f32_8 w; + f32_8 a; + }; + }; + + f32_8 v[4]; + }; +}; + +struct v4_f32_16 { + union { + struct { + union { + f32_16 x; + f32_16 r; + }; + union { + f32_16 y; + f32_16 g; + }; + union { + f32_16 z; + f32_16 b; + }; + union { + f32_16 w; + f32_16 a; + }; + }; + + f32_16 v[4]; + }; +}; + +void vec3_normalize_f32(float* x, float* y, float* z) +{ + float d = sqrt((*x) * (*x) + (*y) * (*y) + (*z) * (*z)); + + *x /= d; + *y /= d; + *z /= d; +} + +void vec4_normalize_f32(float* x, float* y, float* z, float* w) +{ + float d = sqrt((*x) * (*x) + (*y) * (*y) + (*z) * (*z) + (*w) * (*w)); + + *x /= d; + *y /= d; + *z /= d; + *w /= d; +} + +#endif diff --git a/math/matrix/VectorFloat64.h b/math/matrix/VectorFloat64.h new file mode 100644 index 0000000..7130ece --- /dev/null +++ b/math/matrix/VectorFloat64.h @@ -0,0 +1,16 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MATH_MATRIX_VECTOR_FLOAT64_H +#define TOS_MATH_MATRIX_VECTOR_FLOAT64_H + +#include "../../stdlib/Intrinsics.h" +#include "../../utils/MathUtils.h" +#include "../../stdlib/simd/SIMD_F64.h" + +#endif \ No newline at end of file diff --git a/math/matrix/VectorInt32.h b/math/matrix/VectorInt32.h new file mode 100644 index 0000000..90045b0 --- /dev/null +++ b/math/matrix/VectorInt32.h @@ -0,0 +1,157 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MATH_MATRIX_VECTOR_INT32_H +#define TOS_MATH_MATRIX_VECTOR_INT32_H + +#include +#include + +#include "../../stdlib/Intrinsics.h" +#include "../../utils/MathUtils.h" +#include "../../stdlib/simd/SIMD_I32.h" + +struct v3_int32_4 { + union { + struct { + union { + int32_4 x; + int32_4 r; + }; + union { + int32_4 y; + int32_4 g; + }; + union { + int32_4 z; + int32_4 b; + }; + }; + + int32_4 v[3]; + }; +}; + +struct v3_int32_8 { + union { + struct { + union { + int32_8 x; + int32_8 r; + }; + union { + int32_8 y; + int32_8 g; + }; + union { + int32_8 z; + int32_8 b; + }; + }; + + int32_8 v[3]; + }; +}; + +struct v3_int32_16 { + union { + struct { + union { + int32_16 x; + int32_16 r; + }; + union { + int32_16 y; + int32_16 g; + }; + union { + int32_16 z; + int32_16 b; + }; + }; + + int32_16 v[3]; + }; +}; + +struct v4_int32_4 { + union { + struct { + union { + int32_4 x; + int32_4 r; + }; + union { + int32_4 y; + int32_4 g; + }; + union { + int32_4 z; + int32_4 b; + }; + union { + int32_4 w; + int32_4 a; + }; + }; + + int32_4 v[4]; + }; +}; + +struct v4_int32_8 { + union { + struct { + union { + int32_8 x; + int32_8 r; + }; + union { + int32_8 y; + int32_8 g; + }; + union { + int32_8 z; + int32_8 b; + }; + union { + int32_8 w; + int32_8 a; + }; + }; + + int32_8 v[4]; + }; +}; + +struct v4_int32_16 { + union { + struct { + union { + int32_16 x; + int32_16 r; + }; + union { + int32_16 y; + int32_16 g; + }; + union { + int32_16 z; + int32_16 b; + }; + union { + int32_16 w; + int32_16 a; + }; + }; + + int32_16 v[4]; + }; +}; + +#endif diff --git a/math/matrix/VectorInt64.h b/math/matrix/VectorInt64.h new file mode 100644 index 0000000..e12c06d --- /dev/null +++ b/math/matrix/VectorInt64.h @@ -0,0 +1,157 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MATH_MATRIX_VECTOR_INT64_H +#define TOS_MATH_MATRIX_VECTOR_INT64_H + +#include +#include + +#include "../../stdlib/Intrinsics.h" +#include "../../utils/MathUtils.h" +#include "../../stdlib/simd/SIMD_I64.h" + +struct v3_int64_2 { + union { + struct { + union { + int64_2 x; + int64_2 r; + }; + union { + int64_2 y; + int64_2 g; + }; + union { + int64_2 z; + int64_2 b; + }; + }; + + int64_2 v[3]; + }; +}; + +struct v3_int64_4 { + union { + struct { + union { + int64_4 x; + int64_4 r; + }; + union { + int64_4 y; + int64_4 g; + }; + union { + int64_4 z; + int64_4 b; + }; + }; + + int64_4 v[3]; + }; +}; + +struct v3_int64_8 { + union { + struct { + union { + int64_8 x; + int64_8 r; + }; + union { + int64_8 y; + int64_8 g; + }; + union { + int64_8 z; + int64_8 b; + }; + }; + + int64_8 v[3]; + }; +}; + +struct v4_int64_2 { + union { + struct { + union { + int64_2 x; + int64_2 r; + }; + union { + int64_2 y; + int64_2 g; + }; + union { + int64_2 z; + int64_2 b; + }; + union { + int64_2 w; + int64_2 a; + }; + }; + + int64_2 v[4]; + }; +}; + +struct v4_int64_4 { + union { + struct { + union { + int64_4 x; + int64_4 r; + }; + union { + int64_4 y; + int64_4 g; + }; + union { + int64_4 z; + int64_4 b; + }; + union { + int64_4 w; + int64_4 a; + }; + }; + + int64_4 v[4]; + }; +}; + +struct v4_int64_8 { + union { + struct { + union { + int64_8 x; + int64_8 r; + }; + union { + int64_8 y; + int64_8 g; + }; + union { + int64_8 z; + int64_8 b; + }; + union { + int64_8 w; + int64_8 a; + }; + }; + + int64_8 v[4]; + }; +}; + +#endif diff --git a/models/Attrib.h b/models/Attrib.h new file mode 100644 index 0000000..ffca9ab --- /dev/null +++ b/models/Attrib.h @@ -0,0 +1,33 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_ATTRIB_H +#define TOS_ATTRIB_H + +#if OPENGL + #include "../lib/opengl/glew/include/GL/glew.h" + + struct Attrib { + GLuint program; + GLuint position; + GLuint normal; + GLuint uv; + GLuint matrix; + GLuint sampler; + GLuint camera; + GLuint timer; + GLuint extra1; + GLuint extra2; + GLuint extra3; + GLuint extra4; + }; +#else + struct Attrib {}; +#endif + +#endif \ No newline at end of file diff --git a/models/Colors.h b/models/Colors.h new file mode 100644 index 0000000..e69de29 diff --git a/models/Obj.h b/models/Obj.h new file mode 100644 index 0000000..4e0b627 --- /dev/null +++ b/models/Obj.h @@ -0,0 +1,17 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_OBJ_H +#define TOS_MODELS_OBJ_H + +#include "../stdlib/Types.h" + +struct ObjFile { +}; + +#endif \ No newline at end of file diff --git a/models/Sound.h b/models/Sound.h new file mode 100644 index 0000000..0d12b6d --- /dev/null +++ b/models/Sound.h @@ -0,0 +1,17 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_SOUND_H +#define TOS_MODELS_SOUND_H + +#include "../stdlib/Types.h" + +struct SoundFile { +}; + +#endif \ No newline at end of file diff --git a/models/Texture.h b/models/Texture.h new file mode 100644 index 0000000..cb1c75e --- /dev/null +++ b/models/Texture.h @@ -0,0 +1,57 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_TEXTURE_H +#define TOS_MODELS_TEXTURE_H + +#define TEXTURE_DATA_TYPE_2D 0 +#define TEXTURE_DATA_TYPE_1D 1 +#define TEXTURE_DATA_TYPE_3D 2 +#define TEXTURE_DATA_TYPE_1D_ARRAY 3 +#define TEXTURE_DATA_TYPE_2D_ARRAY 4 +#define TEXTURE_DATA_TYPE_2D_MULTISAMPLED 5 +#define TEXTURE_DATA_TYPE_2D_MULTISAMPLED_ARRAY 6 + +#define TEXTURE_WRAP_TYPE_NONE 0 +#define TEXTURE_WRAP_TYPE_CLAMP_TO_EDGE 1 +#define TEXTURE_WRAP_TYPE_CLAMP_TO_BORDER 2 +#define TEXTURE_WRAP_TYPE_REPEAT 3 +#define TEXTURE_WRAP_TYPE_MIRRORED_REPEAT 4 +#define TEXTURE_WRAP_TYPE_MIRRORED_CLAMP_TO_EDGE 5 + +#define TEXTURE_MINIFICATION_NONE 0 +#define TEXTURE_MINIFICATION_NEAREST 1 +#define TEXTURE_MINIFICATION_LINEAR 2 +#define TEXTURE_MINIFICATION_NEAREST_MIPMAP_NEAREST 3 +#define TEXTURE_MINIFICATION_LINEAR_MIPMAP_NEAREST 4 +#define TEXTURE_MINIFICATION_NEAREST_MIPMAP_LINEAR 5 +#define TEXTURE_MINIFICATION_LINEAR_MIPMAP_LINEAR 6 + +#include "../stdlib/Types.h" +#include "../image/Image.h" +#include "Attrib.h" + +struct TextureFile { + uint64 id; + + byte texture_data_type; + + byte texture_wrap_type_s; + byte texture_wrap_type_t; + byte texture_wrap_type_r; + + byte texture_minification; + + Image image; + + #if OPENGL + Attrib attrib; + #endif +}; + +#endif \ No newline at end of file diff --git a/models/chat/Chat.h b/models/chat/Chat.h new file mode 100644 index 0000000..195cd76 --- /dev/null +++ b/models/chat/Chat.h @@ -0,0 +1,51 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_CHAT_H +#define TOS_MODELS_CHAT_H + +#include "../../stdlib/Types.h" +#include "ChatLevel.h" +#include "ChatType.h" + +#ifndef MAX_CHAR_NAME_LENGTH + #define MAX_CHAR_NAME_LENGTH 32 +#endif + +#ifndef MAX_MESSAGE_LENGTH + #define MAX_MESSAGE_LENGTH 512 +#endif + +#ifndef MAX_MESSAGE_HISTORY + #define MAX_MESSAGE_HISTORY 64 +#endif + +struct ChatMessage { + uint64 id; + + unsigned int sender_id; + unsigned int receiver_id; + char sender_name[MAX_CHAR_NAME_LENGTH]; + + time_t dt; + + char message[MAX_MESSAGE_LENGTH]; + ChatLevel level; + ChatType type; +}; + +// Messages are stored in a ring +// -> latest = the newest message +// -> previous message = latest - 1 +// -> This makes iterating messages easy since we also know where the chat history memory block starts +struct ChatHistory { + ChatMessage messages[MAX_MESSAGE_HISTORY]; + int latest; +}; + +#endif \ No newline at end of file diff --git a/models/chat/ChatLevel.h b/models/chat/ChatLevel.h new file mode 100644 index 0000000..43f6468 --- /dev/null +++ b/models/chat/ChatLevel.h @@ -0,0 +1,20 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_CHAT_LEVEL_H +#define TOS_MODELS_CHAT_LEVEL_H + +enum ChatLevel { + CHAT_LEVEL_NORMAL, + CHAT_LEVEL_INFO, + CHAT_LEVEL_IMPORTANT, + CHAT_LEVEL_CRITICAL, + CHAT_LEVEL_DELETED +}; + +#endif \ No newline at end of file diff --git a/models/chat/ChatStatus.h b/models/chat/ChatStatus.h new file mode 100644 index 0000000..e43d1cb --- /dev/null +++ b/models/chat/ChatStatus.h @@ -0,0 +1,19 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_CHAT_STATUS_H +#define TOS_MODELS_CHAT_STATUS_H + +enum ChatStatus { + CHAT_STATUS_OFFLINE, + CHAT_STATUS_ONLINE, + CHAT_STATUS_HIDDEN, + CHAT_STATUS_DND +}; + +#endif \ No newline at end of file diff --git a/models/chat/ChatType.h b/models/chat/ChatType.h new file mode 100644 index 0000000..5ecdfb2 --- /dev/null +++ b/models/chat/ChatType.h @@ -0,0 +1,20 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_CHAT_TYPE_H +#define TOS_MODELS_CHAT_TYPE_H + +enum ChatType { + CHAT_TYPE_LOCAL, + CHAT_TYPE_GLOBAL, + CHAT_TYPE_PLAYER, + CHAT_TYPE_GROUP, + CHAT_TYPE_GUILD +}; + +#endif \ No newline at end of file diff --git a/models/item/Equipment.h b/models/item/Equipment.h new file mode 100644 index 0000000..23af979 --- /dev/null +++ b/models/item/Equipment.h @@ -0,0 +1,19 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_EQUIPMENT_H +#define TOS_MODELS_EQUIPMENT_H + +#include "../../stdlib/Types.h" + +struct Equipment { + byte type; + char* name; +}; + +#endif \ No newline at end of file diff --git a/models/item/EquipmentType.h b/models/item/EquipmentType.h new file mode 100644 index 0000000..1635392 --- /dev/null +++ b/models/item/EquipmentType.h @@ -0,0 +1,25 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_EQUIPMENT_TYPE_H +#define TOS_MODELS_EQUIPMENT_TYPE_H + +#include "../../stdlib/Types.h" + +struct EquipmentType { + byte id; + byte slot; + bool dual; + bool throwing; + bool projectile; + bool damage; + bool armor; + bool supporting; +}; + +#endif \ No newline at end of file diff --git a/models/item/Item.h b/models/item/Item.h new file mode 100644 index 0000000..c53b906 --- /dev/null +++ b/models/item/Item.h @@ -0,0 +1,18 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_ITEM_H +#define TOS_MODELS_ITEM_H + +#include "../../stdlib/Types.h" + +struct Item { + uint64 id; +}; + +#endif \ No newline at end of file diff --git a/models/item/equipment_slots.h b/models/item/equipment_slots.h new file mode 100644 index 0000000..4ddf072 --- /dev/null +++ b/models/item/equipment_slots.h @@ -0,0 +1,27 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_ITEM_EQUIPMENT_SLOTS_H +#define TOS_MODELS_ITEM_EQUIPMENT_SLOTS_H + +#define EQUIPMENT_SLOT_HEAD 0x01 +#define EQUIPMENT_SLOT_NECK 0x02 +#define EQUIPMENT_SLOT_BODY 0x03 +#define EQUIPMENT_SLOT_BELT 0x04 +#define EQUIPMENT_SLOT_PANTS 0x05 +#define EQUIPMENT_SLOT_BOOTS 0x06 +#define EQUIPMENT_SLOT_RING 0x07 +#define EQUIPMENT_SLOT_MAIN_HAND 0x08 +#define EQUIPMENT_SLOT_OFF_HAND 0x09 +#define EQUIPMENT_SLOT_ARMS 0x0A +#define EQUIPMENT_SLOT_BELT_ATTACHMENT 0x0B +#define EQUIPMENT_SLOT_SHOULDER 0x0C +#define EQUIPMENT_SLOT_BACK 0x0D +#define EQUIPMENT_SLOT_HANDS 0x0E + +#endif \ No newline at end of file diff --git a/models/item/equipment_types.h b/models/item/equipment_types.h new file mode 100644 index 0000000..2528080 --- /dev/null +++ b/models/item/equipment_types.h @@ -0,0 +1,115 @@ +#ifndef TOS_MODELS_ITEM_EQUIPMENT_TYPES_H +#define TOS_MODELS_ITEM_EQUIPMENT_TYPES_H + +#include "equipment_slots.h" +#include "EquipmentType.h" + +#define EQUIPMENT_TYPE_ONE_HANDED_SWORD 0x01 +#define EQUIPMENT_TYPE_TWO_HANDED_SWORD 0x02 +#define EQUIPMENT_TYPE_HELMET 0x03 +#define EQUIPMENT_TYPE_EARING 0x04 +#define EQUIPMENT_TYPE_NECKLACE 0x05 +#define EQUIPMENT_TYPE_BOOTS 0x06 +#define EQUIPMENT_TYPE_STAFF 0x07 +#define EQUIPMENT_TYPE_WAND 0x08 +#define EQUIPMENT_TYPE_DOLL 0x09 +#define EQUIPMENT_TYPE_POLEAXE 0x0A +#define EQUIPMENT_TYPE_SABRE 0x0B +#define EQUIPMENT_TYPE_DAGGER 0x0C +#define EQUIPMENT_TYPE_JAVELIN 0x0D +#define EQUIPMENT_TYPE_QUARTERSTAFF 0x0E +#define EQUIPMENT_TYPE_SPEAR 0x0F +#define EQUIPMENT_TYPE_CLAYMORE 0x10 +#define EQUIPMENT_TYPE_DAO 0x11 +#define EQUIPMENT_TYPE_CLEAVER 0x12 +#define EQUIPMENT_TYPE_BROADSWORD 0x13 +#define EQUIPMENT_TYPE_LONGSWORD 0x14 +#define EQUIPMENT_TYPE_SCIMITAR 0x15 +#define EQUIPMENT_TYPE_RAPIER 0x16 +#define EQUIPMENT_TYPE_SICKLE 0x17 +#define EQUIPMENT_TYPE_SCYTHE 0x18 +#define EQUIPMENT_TYPE_PUNCHING_DAGGER 0x19 +#define EQUIPMENT_TYPE_LIGHT_WARHAMMER 0x1A +#define EQUIPMENT_TYPE_LIGHT_MACE 0x1B +#define EQUIPMENT_TYPE_HEAVY_MACE 0x1C +#define EQUIPMENT_TYPE_HEAVY_WARHAMMER 0x1D +#define EQUIPMENT_TYPE_LIGHT_FLAIL 0x1E +#define EQUIPMENT_TYPE_HEAVY_FLAIL 0x1F +#define EQUIPMENT_TYPE_SHURIKAN 0x20 +#define EQUIPMENT_TYPE_GLAIVE 0x21 +#define EQUIPMENT_TYPE_HALBERD 0x22 +#define EQUIPMENT_TYPE_PARTIZAN 0x23 +#define EQUIPMENT_TYPE_LONGBOW 0x24 +#define EQUIPMENT_TYPE_DOUBLE_BOW 0x25 +#define EQUIPMENT_TYPE_BOW 0x27 +#define EQUIPMENT_TYPE_RECURVE_BOW 0x28 +#define EQUIPMENT_TYPE_CROSSBOW 0x29 +#define EQUIPMENT_TYPE_HEAVY_CROSSBOW 0x2A +#define EQUIPMENT_TYPE_WHIP 0x2B +#define EQUIPMENT_TYPE_THROWING_AXE 0x2C +#define EQUIPMENT_TYPE_BLOWGUN 0x2D +#define EQUIPMENT_TYPE_CLUB 0x2E +#define EQUIPMENT_TYPE_GREATCLUB 0x2F +#define EQUIPMENT_TYPE_SLING 0x30 +#define EQUIPMENT_TYPE_CHAKRAM 0x31 +#define EQUIPMENT_TYPE_TRIDENT 0x32 +#define EQUIPMENT_TYPE_THROWING_SPEAR 0x33 +#define EQUIPMENT_TYPE_THROWING_KNIVES 0x34 +#define EQUIPMENT_TYPE_GRANADE 0x35 +#define EQUIPMENT_TYPE_SCRIPTURE 0x36 +#define EQUIPMENT_TYPE_BONES 0x37 +#define EQUIPMENT_TYPE_MAGIC_CRYSTAL 0x38 +#define EQUIPMENT_TYPE_SHIELD 0x39 +#define EQUIPMENT_TYPE_QUIVER 0x3D +#define EQUIPMENT_TYPE_PISTOL 0x3E +#define EQUIPMENT_TYPE_SHOTGUN 0x3F +#define EQUIPMENT_TYPE_RIFLE 0x40 +#define EQUIPMENT_TYPE_FLASK 0x41 +#define EQUIPMENT_TYPE_LIGHT_AXE 0x42 +#define EQUIPMENT_TYPE_QUILL 0x43 +#define EQUIPMENT_TYPE_PANTS 0x44 +#define EQUIPMENT_TYPE_BELT 0x45 +#define EQUIPMENT_TYPE_RING 0x46 +#define EQUIPMENT_TYPE_ARMS 0x47 +#define EQUIPMENT_TYPE_BELT_ATTACHMENT 0x48 +#define EQUIPMENT_TYPE_BODY 0x49 +#define EQUIPMENT_TYPE_CIRCLET 0x4A +#define EQUIPMENT_TYPE_BRACELET 0x4B +#define EQUIPMENT_TYPE_GADGET 0x4C +#define EQUIPMENT_TYPE_LANTERN 0x4D +#define EQUIPMENT_TYPE_GLASSES 0x4E +#define EQUIPMENT_TYPE_CAPE 0x4F +#define EQUIPMENT_TYPE_POLEARM 0x50 +#define EQUIPMENT_TYPE_HEAVY_AXE 0x51 +#define EQUIPMENT_TYPE_SCALES 0x52 +#define EQUIPMENT_TYPE_PRAYING_BEADS 0x53 +#define EQUIPMENT_TYPE_TONFA 0x54 +#define EQUIPMENT_TYPE_TETSUBO 0x55 +#define EQUIPMENT_TYPE_KAMA 0x56 +#define EQUIPMENT_TYPE_SAMURAI_SWORD 0x57 +#define EQUIPMENT_TYPE_BOOMERANG 0x58 +#define EQUIPMENT_TYPE_SLINGSHOT 0x59 +#define EQUIPMENT_TYPE_HARPOON 0x5A +#define EQUIPMENT_TYPE_ORB 0x5B +#define EQUIPMENT_TYPE_RUNESTONE 0x5C +#define EQUIPMENT_TYPE_TALISMAN 0x5D +#define EQUIPMENT_TYPE_GRIMOIRE 0x5E +#define EQUIPMENT_TYPE_SHURIKEN 0x5F +#define EQUIPMENT_TYPE_THROWING_DARTS 0x60 +#define EQUIPMENT_TYPE_COCKTAIL 0x61 +#define EQUIPMENT_TYPE_FLUTE 0x62 +#define EQUIPMENT_TYPE_FAN 0x63 +#define EQUIPMENT_TYPE_SCEPTER 0x64 +#define EQUIPMENT_TYPE_TAMBOURINE 0x65 +#define EQUIPMENT_TYPE_BAGPIPE 0x66 +#define EQUIPMENT_TYPE_HARP 0x67 +#define EQUIPMENT_TYPE_TROMPET 0x68 +#define EQUIPMENT_TYPE_LUTE 0x69 +#define EQUIPMENT_TYPE_HORN 0x6A +#define EQUIPMENT_TYPE_BELL 0x6B +#define EQUIPMENT_TYPE_VIOLIN 0x6C +#define EQUIPMENT_TYPE_VIOLIN 0x6D + +#define SIZE_EQUIPMENT_TYPE 0x69 + +#endif \ No newline at end of file diff --git a/models/map.h b/models/map.h new file mode 100644 index 0000000..e69de29 diff --git a/models/mob/Mob.cpp b/models/mob/Mob.cpp new file mode 100644 index 0000000..324aa73 --- /dev/null +++ b/models/mob/Mob.cpp @@ -0,0 +1,39 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_MOB_C +#define TOS_MODELS_MOB_C + +#include "../../utils/MathUtils.h" +#include "Mob.h" +#include "MobState.h" + +void mob_interpolate(Mob* mob, f32 time) +{ + MobState *s1 = &mob->state1; + MobState *s2 = &mob->state2; + + float t1 = s2->t - s1->t; + float t2 = time - s2->t; + + t1 = OMS_MIN(t1, 1.0f); + t1 = OMS_MAX(t1, 0.1f); + + float p = OMS_MIN(t2 / t1, 1.0f); + + mob->state.location.x = s1->location.x + (s2->location.x - s1->location.x) * p; + mob->state.location.y = s1->location.y + (s2->location.y - s1->location.y) * p; + mob->state.location.z = s1->location.z + (s2->location.z - s1->location.z) * p; + + mob->state.orientation.x = s1->orientation.x + (s2->orientation.x - s1->orientation.x) * p; + mob->state.orientation.y = s1->orientation.y + (s2->orientation.y - s1->orientation.y) * p; + mob->state.orientation.z = s1->orientation.z + (s2->orientation.z - s1->orientation.z) * p; + mob->state.orientation.w = s1->orientation.w + (s2->orientation.w - s1->orientation.w) * p; +} + +#endif \ No newline at end of file diff --git a/models/mob/Mob.h b/models/mob/Mob.h new file mode 100644 index 0000000..3f9956e --- /dev/null +++ b/models/mob/Mob.h @@ -0,0 +1,34 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_MOB_H +#define TOS_MODELS_MOB_H + +#include "../../stdlib/Types.h" + +#include "../settings/Settings.h" +#include "../item/Equipment.h" + +#include "MobState.h" + +struct Mob { + byte category; + byte mclass; + + byte level; + byte rank; + + unsigned int id; + unsigned int guild_id; + + MobState state; + MobState state1; + MobState state2; +}; + +#endif \ No newline at end of file diff --git a/models/mob/MobAction.h b/models/mob/MobAction.h new file mode 100644 index 0000000..818d1d0 --- /dev/null +++ b/models/mob/MobAction.h @@ -0,0 +1,73 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_MOB_ACTION_H +#define TOS_MODELS_MOB_ACTION_H + +// @todo Consider to create better ranges +// This would allow easier checks during the game (e.g. can be healed if > X and < Y) +// Checks to consider are: +// - Can be healed +// - Can be attacked +// - Can attack +// - Can escape/teleport/... (-> out of fight) +// - Can cast +// - Can call mount (e.g. not during falling or during fight) +// - ... + +// Don't render, ready for garbage collection and re-use +#define MOB_ACTION_INACTIVE 0x00 + +#define MOB_ACTION_LAG 0x01 + +#define MOB_ACTION_AAAA 0x02 + +#define MOB_ACTION_WALK 0x03 +#define MOB_ACTION_RUN 0x04 +#define MOB_ACTION_SNEAK 0x05 +#define MOB_ACTION_CRAWL 0x06 +#define MOB_ACTION_CLIMB 0x07 +#define MOB_ACTION_SLIDE 0x08 +#define MOB_ACTION_JUMP 0x09 +#define MOB_ACTION_DUCK 0x0A +#define MOB_ACTION_FALL 0x0B + +#define MOB_ACTION_TALK 0x0C +#define MOB_ACTION_ATTACK 0x0D +#define MOB_ACTION_DEFEND 0x0E +#define MOB_ACTION_BLOCK 0x0F +#define MOB_ACTION_DODGE 0x10 +#define MOB_ACTION_DIE 0x11 +#define MOB_ACTION_DEAD 0x12 + +#define MOB_ACTION_SWIM 0x13 +#define MOB_ACTION_SWIM_HOVER 0x14 + +#define MOB_ACTION_DIVE 0x15 +#define MOB_ACTION_DIVE_HOVER 0x16 + +#define MOB_ACTION_FLY 0x17 +#define MOB_ACTION_FLY_HOVER 0x18 + +#define MOB_ACTION_STAND 0x19 +#define MOB_ACTION_SIT 0x1A +#define MOB_ACTION_LIE 0x1B + +#define MOB_ACTION_SPAWN 0x1C +#define MOB_ACTION_TELEPORT 0x1D +#define MOB_ACTION_LOAD 0x1E + +#define MOB_ACTION_MINE 0x1F +#define MOB_ACTION_CRAFT 0x20 +#define MOB_ACTION_GATHER 0x21 +#define MOB_ACTION_FISH 0x22 +#define MOB_ACTION_SHOP 0x23 + +#define MOB_ACTION_EMOTE 0xFF + +#endif \ No newline at end of file diff --git a/models/mob/MobCategory.h b/models/mob/MobCategory.h new file mode 100644 index 0000000..e69de29 diff --git a/models/mob/MobState.h b/models/mob/MobState.h new file mode 100644 index 0000000..7bb6f93 --- /dev/null +++ b/models/mob/MobState.h @@ -0,0 +1,30 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_MOB_STATE_H +#define TOS_MODELS_MOB_STATE_H + +#include "../../stdlib/Types.h" +#include "../../stdlib/Mathtypes.h" +#include "MobAction.h" + +struct MobState { + v3_f32 location; + v4_f32 orientation; + + float t; + + // Action performed + // first byte = action category + // last 3 bytes = animation to use + uint32 action = (MOB_ACTION_INACTIVE << 24); + + int chunk_id; +}; + +#endif \ No newline at end of file diff --git a/models/mob/MobStats.h b/models/mob/MobStats.h new file mode 100644 index 0000000..5183eed --- /dev/null +++ b/models/mob/MobStats.h @@ -0,0 +1,6 @@ +#ifndef TOS_MODELS_MOB_STATS_H +#define TOS_MODELS_MOB_STATS_H + +#include "../../../stdlib/Types.h" + +#endif \ No newline at end of file diff --git a/models/mob/mob_category.h b/models/mob/mob_category.h new file mode 100644 index 0000000..5db643d --- /dev/null +++ b/models/mob/mob_category.h @@ -0,0 +1,15 @@ +#ifndef TOS_MODELS_MOB_CATEGORY_H +#define TOS_MODELS_MOB_CATEGORY_H + +#define MOB_CATEGORY_REGULAR 0x01 +#define MOB_CATEGORY_CHAMPION 0x02 +#define MOB_CATEGORY_BOSS 0x03 +#define MOB_CATEGORY_WORLD_BOSS 0x04 +#define MOB_CATEGORY_SINGULARITY 0x05 +#define MOB_CATEGORY_ANIMAL 0x06 +#define MOB_CATEGORY_NPC 0x07 +#define MOB_CATEGORY_PLAYER 0x08 + +#define SIZE_MOB_CATEGORY 0x08 + +#endif \ No newline at end of file diff --git a/models/mob/mob_list.h b/models/mob/mob_list.h new file mode 100644 index 0000000..99b10a0 --- /dev/null +++ b/models/mob/mob_list.h @@ -0,0 +1,14 @@ +#ifndef TOS_MODELS_MOB_LIST_H +#define TOS_MODELS_MOB_LIST_H + +#define MOB_LIST_COW 0x01 +#define MOB_LIST_CHICKEN 0x02 +#define MOB_LIST_PIG 0x03 +#define MOB_LIST_DOG 0x04 +#define MOB_LIST_CAT 0x05 +#define MOB_LIST_HORSE 0x06 +#define MOB_LIST_CROW 0x07 + +#define SIZE_MOB_LIST 0x07 + +#endif \ No newline at end of file diff --git a/models/mob/monster/Drop.h b/models/mob/monster/Drop.h new file mode 100644 index 0000000..34bdab3 --- /dev/null +++ b/models/mob/monster/Drop.h @@ -0,0 +1,20 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_MOB_DROP_H +#define TOS_MODELS_MOB_DROP_H + +#include "../../../stdlib/Types.h" + +struct Drop { + uint64 item; + uint32 quantity; + // @todo Add item specifications (e.g. affixes) +}; + +#endif \ No newline at end of file diff --git a/models/mob/monster/LootTable.h b/models/mob/monster/LootTable.h new file mode 100644 index 0000000..0b5f5d8 --- /dev/null +++ b/models/mob/monster/LootTable.h @@ -0,0 +1,104 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_MOB_LOOT_TABLE_H +#define TOS_MODELS_MOB_LOOT_TABLE_H + +#include "../../../stdlib/Types.h" +#include "../../../utils/Utils.h" +#include "../../../utils/MathUtils.h" +#include "Drop.h" + +struct LootTable { + // Chance this table becomes effective at all + // Useful to define multiple loot tables for a mob e.g. normal drop + 1 rare guarantueed + float table_chance; + + uint64* items; + int table_size; + + // If drop chance = -1 -> use default rarity drop chance + float* item_drop_chances; + + // How many stacks of that item should be dropped + // Usually only used for consumables + int* item_min_drop_count; + int* item_max_drop_count; + bool item_unique; + + // How many "different" items should be dropped + uint32 item_min_count; + uint32 item_max_count; + + // How much gold should be dropped + uint32 gold_min_count; + uint32 gold_max_count; +}; + +// 1. check if table comes into effect +// 2. check if max item drop count is exceeded +void loot_table_drop(const LootTable* table, Drop* drop, uint32 counter = 0) +{ + f32 rand = fast_rand_percentage(); + if (counter >= table->item_max_count + || rand > table->table_chance + ) { + drop = NULL; + return; + } + + f32 range_value = 0; + int i = 0; + for (i = 0; i < table->table_size; ++i) { + range_value += table->item_drop_chances[i]; + + if (range_value < rand) { + drop->item = table->items[i]; + break; + } + } + + if (i >= table->table_size) { + drop = NULL; + return; + } + + drop->quantity = 1; + if (table->item_max_drop_count[i] > 1) { + rand = fast_rand_percentage(); + drop->quantity = OMS_MAX(table->item_min_drop_count[i], (int) ((float) table->item_max_count * rand)); + } +} + +uint64 loot_table_drop_gold(const LootTable* table) +{ + if (table->gold_max_count == 0) { + return 0; + } + + f32 rand = fast_rand_percentage(); + if (rand > table->table_chance) { + return 0; + } + + return OMS_MAX(table->gold_min_count, (uint64) ((f32) table->gold_max_count * rand)); + + // WARNING: This is mathematically WRONG! + // The expected value of the version above is higher than what you would actually expect + // The correct version would be the one below (although slower) + /* + uint32 r = rand(); + if (r > table->table_chance * RAND_MAX) { + return 0; + } + + return (r % (table->gold_max_count - table->gold_min_count + 1)) + table->gold_min_count; + */ +} + +#endif \ No newline at end of file diff --git a/models/mob/monster/Monster.h b/models/mob/monster/Monster.h new file mode 100644 index 0000000..1a5155d --- /dev/null +++ b/models/mob/monster/Monster.h @@ -0,0 +1,63 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_MOB_MONSTER_H +#define TOS_MODELS_MOB_MONSTER_H + +#include "../../../stdlib/Types.h" + +#include "../Mob.h" +#include "LootTable.h" +#include "MonsterStats.h" + +#if SERVER + struct SMonster { + Mob mob; + SMonsterStats monster_stats; + + LootTable loot; + + // Data layout + // 12223444 + // 1: scale sign + // 2: scale factor (8) + // 3: weight sign + // 4: weight factor (8) + byte custom_size; + + // Data layout + // 122222?? + // 1: body type (2) + // 2: skin color (32) + byte custom_body; + }; +#endif + +struct CMonster { + Mob mob; + CMonsterStats monster_stats; + + char name[MAX_CHAR_NAME_LENGTH]; + char title[MAX_CHAR_TITLE_LENGTH]; + + // Data layout + // 12223444 + // 1: scale sign + // 2: scale factor (8) + // 3: weight sign + // 4: weight factor (8) + byte custom_size; + + // Data layout + // 1122222? + // 1: body type (4) + // 2: skin color (32) + byte custom_body; +}; + +#endif \ No newline at end of file diff --git a/models/mob/monster/MonsterStats.h b/models/mob/monster/MonsterStats.h new file mode 100644 index 0000000..ecbd29e --- /dev/null +++ b/models/mob/monster/MonsterStats.h @@ -0,0 +1,22 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_MOB_MONSTER_STATS_H +#define TOS_MODELS_MOB_MONSTER_STATS_H + +#include "../../../stdlib/Types.h" + +#if SERVER + struct SMonsterStats { + }; +#endif + +struct CMonsterStats { +}; + +#endif \ No newline at end of file diff --git a/models/mob/player/Backpack.h b/models/mob/player/Backpack.h new file mode 100644 index 0000000..168c6cf --- /dev/null +++ b/models/mob/player/Backpack.h @@ -0,0 +1,119 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_BACKPACK_H +#define TOS_MODELS_BACKPACK_H + +#include "../../../stdlib/Types.h" +#include "../../item/Item.h" + +#define MAX_BACKPACK_ITEM_STACK 1024 + +struct Backpack { + uint32 size; + Item* items; + uint32* quantities; +}; + +bool backpack_split_items(Backpack* backpack, uint32 index, uint32 quantity) +{ + if (quantity > backpack->quantities[index] && quantity > 0) { + return false; + } + + // Find empty slot + int32 empty_slot = -1; + for (uint32 i = 0; i < backpack->size; ++i) { + if (backpack->quantities[i] == 0) { + empty_slot = i; + } + } + + if (empty_slot < 0) { + return false; + } + + memcpy(backpack->items + empty_slot, backpack->items + index, sizeof(Item)); + backpack->quantities[empty_slot] = quantity; + + return true; +} + +void backpack_move_item(Backpack* backpack, uint32 from, uint32 to) +{ + if (backpack->quantities[from] == 0) { + return; + } + + // Handle item stacking + // @todo only allow stacking for consumables or items that have a stackable flag defined?! + if (backpack->items[to].id == backpack->items[from].id) { + // Only change stack up to MAX_BACKPACK_ITEM_STACK + uint32 stack_change = OMS_MIN(MAX_BACKPACK_ITEM_STACK - backpack->quantities[to], backpack->quantities[from]); + backpack->quantities[to] += stack_change; + backpack->quantities[from] -= stack_change; + + return; + } + + Item temp_item = {}; + memcpy(&temp_item, backpack->items + to, sizeof(Item)); + int32 temp_quantity = backpack->quantities[to]; + + memcpy(backpack->items + to, backpack->items + from, sizeof(Item)); + + if (temp_quantity == 0) { + backpack->quantities[from] = 0; + + return; + } + + memcpy(backpack->items + from, &temp_item, sizeof(Item)); + backpack->quantities[from] = temp_quantity; +} + +inline +int32 backpack_find_empty(const Backpack* backpack) +{ + for (uint32 i = 0; i < backpack->size; ++i) { + if (backpack->quantities[i] == 0) { + return i; + } + } + + return -1; +} + +int32 backpack_add_item(Backpack* backpack, const Item* item, int32 quantities) +{ + for (uint32 i = 0; i < backpack->size; ++i) { + if (backpack->quantities[i] == 0) { + // @performance Do We have to memcpy? + // It could be MUCH better to just store pointers in the backpack and have a second unordered backpack + // This would make changing orders much more efficient. + // At the same time how often are we really changing the order?! + memcpy(backpack->items + i, item, sizeof(Item)); + backpack->quantities[i] = quantities; + + return i; + } + } + + return -1; +} + +void backpack_remove_item(Backpack* backpack, uint32 index) +{ + if (backpack->quantities[index] == 0) { + return; + } + + backpack->quantities[index] = 0; +} + +#endif \ No newline at end of file diff --git a/models/mob/player/Guild.h b/models/mob/player/Guild.h new file mode 100644 index 0000000..095cb2d --- /dev/null +++ b/models/mob/player/Guild.h @@ -0,0 +1,35 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_GUILD_H +#define TOS_MODELS_GUILD_H + +#include "../../../stdlib/Types.h" + +#ifndef MAX_CHAR_NAME_LENGTH + #define MAX_CHAR_NAME_LENGTH 32 +#endif + +#if SERVER +struct SGuild { + int id = 0; + char name[MAX_CHAR_NAME_LENGTH]; + + byte rank = 0x00; +}; +#endif + +// @performance The client should cache the guild names -> avoid sending guild names through network +struct CGuild { + int id = 0; + char name[MAX_CHAR_NAME_LENGTH]; + + byte rank = 0x00; +}; + +#endif \ No newline at end of file diff --git a/models/mob/player/Player.cpp b/models/mob/player/Player.cpp new file mode 100644 index 0000000..ffdcf51 --- /dev/null +++ b/models/mob/player/Player.cpp @@ -0,0 +1,34 @@ +void make_player( + float *data, + float x, float y, float z, float rx, float ry) +{ + float ao[6][4] = {0}; + float light[6][4] = { + {0.8, 0.8, 0.8, 0.8}, + {0.8, 0.8, 0.8, 0.8}, + {0.8, 0.8, 0.8, 0.8}, + {0.8, 0.8, 0.8, 0.8}, + {0.8, 0.8, 0.8, 0.8}, + {0.8, 0.8, 0.8, 0.8} + }; + + make_cube_faces( + data, ao, light, + 1, 1, 1, 1, 1, 1, + 226, 224, 241, 209, 225, 227, + 0, 0, 0, 0.4 + ); + + float ma[16]; + float mb[16]; + + mat_identity(ma); + mat_rotate(mb, 0, 1, 0, rx); + mat_multiply(ma, mb, ma); + mat_rotate(mb, cosf(rx), 0, sinf(rx), -ry); + mat_multiply(ma, mb, ma); + mat_apply(data, ma, 36, 3, 10); + mat_translate(mb, x, y, z); + mat_multiply(ma, mb, ma); + mat_apply(data, ma, 36, 0, 10); +} \ No newline at end of file diff --git a/models/mob/player/Player.h b/models/mob/player/Player.h new file mode 100644 index 0000000..1ab4dd8 --- /dev/null +++ b/models/mob/player/Player.h @@ -0,0 +1,145 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_MOB_PLAYER_H +#define TOS_MODELS_MOB_PLAYER_H + +#include "../../../stdlib/Types.h" + +#include "../../item/Equipment.h" +#include "../Mob.h" +#include "../MobState.h" +#include "../monster/LootTable.h" +#include "Backpack.h" +#include "PlayerStats.h" + +#ifndef MAX_CHAR_NAME_LENGTH + #define MAX_CHAR_NAME_LENGTH 32 +#endif + +#ifndef MAX_CHAR_TITLE_LENGTH + #define MAX_CHAR_TITLE_LENGTH 16 +#endif + +#if SERVER + struct SPlayer { + Mob mob; + SPlayerStats player_stats; + + char name[MAX_CHAR_NAME_LENGTH]; + char title[MAX_CHAR_TITLE_LENGTH]; + + Equipment equipment[14]; + PSettings settings; + + Backpack* packpack; + + // Data layout + // 12223444 + // 1: scale sign + // 2: scale factor (8) + // 3: weight sign + // 4: weight factor (8) + byte scale; + byte weight; + + // Data layout + // 1122222? + // 1: body type (4) + // 2: skin color (32) + byte body_type; + byte body_color; + + // Data layout + // 1-4 race (16) + // + // 5-9 face type (32) + // + // 10-15 hair style (64) + // 16-20 hair color (32) + // + // 21-26 beard style (32) + // + // 27-30 eye style (32) + // 31-35 eye color (32) + // + // 36-40 face scar (32) + // 41-45 body scar (32) + // + // 46-51 tattoo (64) + // 52-56 tattoo color (32) + byte race; + byte face_type; + byte hair_style; + byte hair_color; + byte beard_style; + byte eye_style; + byte eye_color; + byte face_scar; + byte body_scar; + byte tattoo; + byte tattoo_color; + }; +#endif + +struct CPlayer { + Mob mob; + CPlayerStats player_stats; + + char name[MAX_CHAR_NAME_LENGTH]; + char title[MAX_CHAR_TITLE_LENGTH]; + + // Equipment id used for rendering (this could be also the transmog item id) + uint32 equipment[14]; + + // Equipment transmog data + // 11111222223333344444444455555??? + // 1: primary color (32) + // 2: secondary color (32) + // 3: tertiary color (32) + // 4: effect (512) + // 5: effect color (32) + // ?: FREE + uint32 equipmentTransmog[14]; + + // Data layout + // 12223444 + // 1: scale sign + // 2: scale factor (8) + // 3: weight sign + // 4: weight factor (8) + byte custom_size; + + // Data layout + // 122222?? + // 1: body type (2) + // 2: skin color (32) + byte custom_body; + + // Data layout + // 1-4 race (16) + // + // 5-9 face type (32) + // + // 10-15 hair style (64) + // 16-20 hair color (32) + // + // 21-26 beard style (32) + // + // 27-30 eye style (32) + // 31-35 eye color (32) + // + // 36-40 face scar (32) + // 41-45 body scar (32) + // + // 46-51 tattoo (64) + // 52-56 tattoo color (32) + int64 customization; +}; + +#endif \ No newline at end of file diff --git a/models/mob/player/PlayerStats.h b/models/mob/player/PlayerStats.h new file mode 100644 index 0000000..fca23ea --- /dev/null +++ b/models/mob/player/PlayerStats.h @@ -0,0 +1,349 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_MOB_PLAYER_STATS_H +#define TOS_MODELS_MOB_PLAYER_STATS_H + +#include "../../../stdlib/Types.h" + +#if SERVER + struct SPlayerStats { + byte stat_str; // strength : effects health + base damage + byte stat_int; // inteligence : effects resource + base demage + byte stat_acc; // accuracy : effects critical chance + base damage + miss chance + byte stat_agi; // agility : effects resource + base damage + dodge change + byte stat_def; // defense : effects resource + base defense + dodge change + byte stat_sta; // stamina : effects health regen + resource regen + + // Naming conventions + // : total + // _base : character stats (see stat_ above) + // _equip : character equipment + // _item : other item effects (consumables, e.g. potions) + // _effect : external aoe/skill effect + // _skill : own skill + + // Damage types + unsigned int dmg; + unsigned int dmg_base; + unsigned int dmg_equip; + unsigned int dmg_item; + unsigned int dmg_effect; + unsigned int dmg_skill; + + unsigned int dmg_pircing; + unsigned int dmg_pircing_base; + unsigned int dmg_pircing_equip; + unsigned int dmg_pircing_item; + unsigned int dmg_pircing_effect; + unsigned int dmg_pircing_skill; + + unsigned int dmg_slashing; + unsigned int dmg_slashing_base; + unsigned int dmg_slashing_equip; + unsigned int dmg_slashing_item; + unsigned int dmg_slashing_effect; + unsigned int dmg_slashing_skill; + + unsigned int dmg_bludgeoning; + unsigned int dmg_bludgeoning_base; + unsigned int dmg_bludgeoning_equip; + unsigned int dmg_bludgeoning_item; + unsigned int dmg_bludgeoning_effect; + unsigned int dmg_bludgeoning_skill; + + unsigned int dmg_fire; + unsigned int dmg_fire_base; + unsigned int dmg_fire_equip; + unsigned int dmg_fire_item; + unsigned int dmg_fire_effect; + unsigned int dmg_fire_skill; + + unsigned int dmg_water; + unsigned int dmg_water_base; + unsigned int dmg_water_equip; + unsigned int dmg_water_item; + unsigned int dmg_water_effect; + unsigned int dmg_water_skill; + + unsigned int dmg_ice; + unsigned int dmg_ice_base; + unsigned int dmg_ice_equip; + unsigned int dmg_ice_item; + unsigned int dmg_ice_effect; + unsigned int dmg_ice_skill; + + unsigned int dmg_earth; + unsigned int dmg_earth_base; + unsigned int dmg_earth_equip; + unsigned int dmg_earth_item; + unsigned int dmg_earth_effect; + unsigned int dmg_earth_skill; + + unsigned int dmg_wind; + unsigned int dmg_wind_base; + unsigned int dmg_wind_equip; + unsigned int dmg_wind_item; + unsigned int dmg_wind_effect; + unsigned int dmg_wind_skill; + + unsigned int dmg_poison; + unsigned int dmg_poison_base; + unsigned int dmg_poison_equip; + unsigned int dmg_poison_item; + unsigned int dmg_poison_effect; + unsigned int dmg_poison_skill; + + unsigned int dmg_lightning; + unsigned int dmg_lightning_base; + unsigned int dmg_lightning_equip; + unsigned int dmg_lightning_item; + unsigned int dmg_lightning_effect; + unsigned int dmg_lightning_skill; + + unsigned int dmg_holy; + unsigned int dmg_holy_base; + unsigned int dmg_holy_equip; + unsigned int dmg_holy_item; + unsigned int dmg_holy_effect; + unsigned int dmg_holy_skill; + + unsigned int dmg_arcane; + unsigned int dmg_arcane_base; + unsigned int dmg_arcane_equip; + unsigned int dmg_arcane_item; + unsigned int dmg_arcane_effect; + unsigned int dmg_arcane_skill; + + unsigned int dmg_corrupted; + unsigned int dmg_corrupted_base; + unsigned int dmg_corrupted_equip; + unsigned int dmg_corrupted_item; + unsigned int dmg_corrupted_effect; + unsigned int dmg_corrupted_skill; + + unsigned int dmg_crit; + unsigned int dmg_crit_base; + unsigned int dmg_crit_equip; + unsigned int dmg_crit_item; + unsigned int dmg_crit_effect; + unsigned int dmg_crit_skill; + + float dmg_crit_chance; + float dmg_crit_chance_base; + float dmg_crit_chance_equip; + float dmg_crit_chance_item; + float dmg_crit_chance_effect; + float dmg_crit_chance_skill; + + // Health & Resource + unsigned int health; + unsigned int health_base; + unsigned int health_equip; + unsigned int health_item; + unsigned int health_effect; + unsigned int health_skill; + + unsigned int health_regen; + unsigned int health_regen_base; + unsigned int health_regen_equip; + unsigned int health_regen_item; + unsigned int health_regen_effect; + unsigned int health_regen_skill; + + unsigned int resource; + unsigned int resource_base; + unsigned int resource_equip; + unsigned int resource_item; + unsigned int resource_effect; + unsigned int resource_skill; + + unsigned int resource_regen; + unsigned int resource_regen_base; + unsigned int resource_regen_equip; + unsigned int resource_regen_item; + unsigned int resource_regen_effect; + unsigned int resource_regen_skill; + + // Defense types + // think about it as armor and/or resistence if it helps + unsigned int defense; + unsigned int defense_base; + unsigned int defense_equip; + unsigned int defense_item; + unsigned int defense_effect; + unsigned int defense_skill; + + unsigned int defense_pircing; + unsigned int defense_pircing_base; + unsigned int defense_pircing_equip; + unsigned int defense_pircing_item; + unsigned int defense_pircing_effect; + unsigned int defense_pircing_skill; + + unsigned int defense_slashing; + unsigned int defense_slashing_base; + unsigned int defense_slashing_equip; + unsigned int defense_slashing_item; + unsigned int defense_slashing_effect; + unsigned int defense_slashing_skill; + + unsigned int defense_bludgeoning; + unsigned int defense_bludgeoning_base; + unsigned int defense_bludgeoning_equip; + unsigned int defense_bludgeoning_item; + unsigned int defense_bludgeoning_effect; + unsigned int defense_bludgeoning_skill; + + unsigned int defense_fire; + unsigned int defense_fire_base; + unsigned int defense_fire_equip; + unsigned int defense_fire_item; + unsigned int defense_fire_effect; + unsigned int defense_fire_skill; + + unsigned int defense_water; + unsigned int defense_water_base; + unsigned int defense_water_equip; + unsigned int defense_water_item; + unsigned int defense_water_effect; + unsigned int defense_water_skill; + + unsigned int defense_ice; + unsigned int defense_ice_base; + unsigned int defense_ice_equip; + unsigned int defense_ice_item; + unsigned int defense_ice_effect; + unsigned int defense_ice_skill; + + unsigned int defense_earth; + unsigned int defense_earth_base; + unsigned int defense_earth_equip; + unsigned int defense_earth_item; + unsigned int defense_earth_effect; + unsigned int defense_earth_skill; + + unsigned int defense_wind; + unsigned int defense_wind_base; + unsigned int defense_wind_equip; + unsigned int defense_wind_item; + unsigned int defense_wind_effect; + unsigned int defense_wind_skill; + + unsigned int defense_poison; + unsigned int defense_poison_base; + unsigned int defense_poison_equip; + unsigned int defense_poison_item; + unsigned int defense_poison_effect; + unsigned int defense_poison_skill; + + unsigned int defense_lightning; + unsigned int defense_lightning_base; + unsigned int defense_lightning_equip; + unsigned int defense_lightning_item; + unsigned int defense_lightning_effect; + unsigned int defense_lightning_skill; + + unsigned int defense_holy; + unsigned int defense_holy_base; + unsigned int defense_holy_equip; + unsigned int defense_holy_item; + unsigned int defense_holy_effect; + unsigned int defense_holy_skill; + + unsigned int defense_arcane; + unsigned int defense_arcane_base; + unsigned int defense_arcane_equip; + unsigned int defense_arcane_item; + unsigned int defense_arcane_effect; + unsigned int defense_arcane_skill; + + unsigned int defense_corrupted; + unsigned int defense_corrupted_base; + unsigned int defense_corrupted_equip; + unsigned int defense_corrupted_item; + unsigned int defense_corrupted_effect; + unsigned int defense_corrupted_skill; + + // Accuracy + float dodge_chance; + float dodge_chance_base; + float dodge_chance_equip; + float dodge_chance_item; + float dodge_chance_effect; + float dodge_chance_skill; + + float root_protection; + float root_protection_base; + float root_protection_equip; + float root_protection_item; + float root_protection_effect; + float root_protection_skill; + + float miss_chance; + float miss_chance_base; + float miss_chance_equip; + float miss_chance_item; + float miss_chance_effect; + float miss_chance_skill; + + // Movement + // Additional speeds may be defined for players + float speed_walk1; // normal/fast + float speed_walk1_base; + float speed_walk1_equip; + float speed_walk1_item; + float speed_walk1_effect; + float speed_walk1_skill; + + float speed_walk2; // casual/slow + + float speed_swim1; // normal/fast + float speed_swim1_base; + float speed_swim1_equip; + float speed_swim1_item; + float speed_swim1_effect; + float speed_swim1_skill; + + float speed_swim2; // casual/slow + + float speed_fly1; // normal/fast + float speed_fly1_base; + float speed_fly1_equip; + float speed_fly1_item; + float speed_fly1_effect; + float speed_fly1_skill; + + float speed_fly2; // casual/slow + + float speed_jump; + float speed_dodge; + float speed_turn; + + // Fighting speed + float speed_cast; + float speed_cast_base; + float speed_cast_equip; + float speed_cast_item; + float speed_cast_effect; + float speed_cast_skill; + + float speed_attack; + float speed_attack_base; + float speed_attack_equip; + float speed_attack_item; + float speed_attack_effect; + float speed_attack_skill; + }; +#endif + +struct CPlayerStats { + +}; + +#endif \ No newline at end of file diff --git a/models/mob/player/Reputation.h b/models/mob/player/Reputation.h new file mode 100644 index 0000000..1bfaeda --- /dev/null +++ b/models/mob/player/Reputation.h @@ -0,0 +1,53 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_MOB_PLAYER_REPUTATION_H +#define TOS_MODELS_MOB_PLAYER_REPUTATION_H + +#include "../../../stdlib/Types.h" + +struct Reputation { + // Character trait + int8 bravery; + int8 skill; + int8 wisdom; + int8 goodness; + int8 loyalty; + int8 gratefulness; + int8 persistence; + int8 love; + int8 creativity; + int8 patience; + int8 ambition; + int8 honesty; + int8 empathy; + int8 discretion; + int8 fairness; + int8 kindness; + int8 selflessness; + int8 confidence; + int8 curiousity; + int8 discipline; + int8 flexibility; + int8 humility; + int8 openness; + int8 reliability; + int8 lawfulness; + + // Character activity + int8 thief_threat_level; + int8 brawler; + int8 murderer; + int8 trader; + int8 ripoff; + int8 dungeoneer; + int8 raider; + int8 pvpler; +}; + +#endif \ No newline at end of file diff --git a/models/object/Block.cpp b/models/object/Block.cpp new file mode 100644 index 0000000..5c9fbeb --- /dev/null +++ b/models/object/Block.cpp @@ -0,0 +1,83 @@ +void make_cube_faces( + float *data, float ao[6][4], float light[6][4], + int left, int right, int top, int bottom, int front, int back, + int wleft, int wright, int wtop, int wbottom, int wfront, int wback, + float x, float y, float z, float n) +{ + static const float positions[6][4][3] = { + {{-1, -1, -1}, {-1, -1, +1}, {-1, +1, -1}, {-1, +1, +1}}, + {{+1, -1, -1}, {+1, -1, +1}, {+1, +1, -1}, {+1, +1, +1}}, + {{-1, +1, -1}, {-1, +1, +1}, {+1, +1, -1}, {+1, +1, +1}}, + {{-1, -1, -1}, {-1, -1, +1}, {+1, -1, -1}, {+1, -1, +1}}, + {{-1, -1, -1}, {-1, +1, -1}, {+1, -1, -1}, {+1, +1, -1}}, + {{-1, -1, +1}, {-1, +1, +1}, {+1, -1, +1}, {+1, +1, +1}} + }; + + static const float normals[6][3] = { + {-1, 0, 0}, + {+1, 0, 0}, + {0, +1, 0}, + {0, -1, 0}, + {0, 0, -1}, + {0, 0, +1} + }; + + static const float uvs[6][4][2] = { + {{0, 0}, {1, 0}, {0, 1}, {1, 1}}, + {{1, 0}, {0, 0}, {1, 1}, {0, 1}}, + {{0, 1}, {0, 0}, {1, 1}, {1, 0}}, + {{0, 0}, {0, 1}, {1, 0}, {1, 1}}, + {{0, 0}, {0, 1}, {1, 0}, {1, 1}}, + {{1, 0}, {1, 1}, {0, 0}, {0, 1}} + }; + + static const float indices[6][6] = { + {0, 3, 2, 0, 1, 3}, + {0, 3, 1, 0, 2, 3}, + {0, 3, 2, 0, 1, 3}, + {0, 3, 1, 0, 2, 3}, + {0, 3, 2, 0, 1, 3}, + {0, 3, 1, 0, 2, 3} + }; + + static const float flipped[6][6] = { + {0, 1, 2, 1, 3, 2}, + {0, 2, 1, 2, 3, 1}, + {0, 1, 2, 1, 3, 2}, + {0, 2, 1, 2, 3, 1}, + {0, 1, 2, 1, 3, 2}, + {0, 2, 1, 2, 3, 1} + }; + + float *d = data; + float s = 0.0625; + float a = 0 + 1 / 2048.0; + float b = s - 1 / 2048.0; + + int faces[6] = {left, right, top, bottom, front, back}; + int tiles[6] = {wleft, wright, wtop, wbottom, wfront, wback}; + + for (int i = 0; i < 6; i++) { + if (faces[i] == 0) { + continue; + } + float du = (tiles[i] % 16) * s; + float dv = (tiles[i] / 16) * s; + + int flip = ao[i][0] + ao[i][3] > ao[i][1] + ao[i][2]; + + for (int v = 0; v < 6; v++) { + int j = flip ? flipped[i][v] : indices[i][v]; + *(d++) = x + n * positions[i][j][0]; + *(d++) = y + n * positions[i][j][1]; + *(d++) = z + n * positions[i][j][2]; + *(d++) = normals[i][0]; + *(d++) = normals[i][1]; + *(d++) = normals[i][2]; + *(d++) = du + (uvs[i][j][0] ? b : a); + *(d++) = dv + (uvs[i][j][1] ? b : a); + *(d++) = ao[i][j]; + *(d++) = light[i][j]; + } + } +} \ No newline at end of file diff --git a/models/object/Block.h b/models/object/Block.h new file mode 100644 index 0000000..f6a66bc --- /dev/null +++ b/models/object/Block.h @@ -0,0 +1,94 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_BLOCK_H +#define TOS_MODELS_BLOCK_H + +#include "../../stdlib/Types.h" +#include "../../stdlib/SIMD/SIMD_I32.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Block +// +// Blocks are landscape blocks that just get rendered as is +// Blocks are very simple -> fast to render +// WARNING: No other block can be placed at its position! +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Block coordinates are relative to the chunk coordinates +// Block coordinates can also be only grid-based +// Therefore the x,y,z coordinates can be byte datatypes +struct Block { + // 0 - x + // 1 - y + // 2 - z + // 3 - rot1 + // 4 - rot2 + // 5 - type + int32 v[6]; +}; + +struct BlockDB { + int32 x; + int32 y; + int32 z; + + int32 rot1; + int32 rot2; + + int32 type; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// BlockObject +// +// BlockObjectss are any object that fits on the grid. +// BlocksObjects are very simple -> faster to render than other objects. +// WARNING: No other block can be placed at its position! +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Block coordinates are relative to the chunk coordinates +// Block coordinates can also be only grid-based +// Therefore the x,y,z coordinates can be byte datatypes +struct BlockObject { + // 0 - x + // 1 - y + // 2 - z + // 3 - type + // 4 - rotx + // 5 - roty + Stdlib::SIMD::int32_8_simd v; +}; + +struct BlockObjectDB { + byte x; + byte y; + byte z; + + uint32 type; + + // first 4 bits = rotation + // 4 possible x rotations + // 4 possible y rotations + // -> 16 possible combinations + // -> 2^4 -> 4 bits + // + // last 4 bits = scale + // -> first bit defines positive or negative scale factor + // -> last 3 bits define scale factor + // -> 2^3 = 8 scale factors + // -> A block can be maximum 9 times its original size or 1/9th of it + // -> note that 0 is the original scale -> 1+8 + byte rotation_scale; +}; + +#endif \ No newline at end of file diff --git a/models/object/Chunk.h b/models/object/Chunk.h new file mode 100644 index 0000000..6b385a6 --- /dev/null +++ b/models/object/Chunk.h @@ -0,0 +1,55 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_OBJECT_CHUNK_H +#define TOS_MODELS_OBJECT_CHUNK_H + +#include "../../stdlib/SIMD/SIMD_I32.h" +#include "../../../stdlib/Types.h" +#include "Block.h" +#include "Object.h" + +struct Chunk { + // 0 - x + // 1 - y + // 2 - z + // 3 - size + Stdlib::SIMD::int32_4_simd v; +}; + +struct ChunkDB { + int x; + int y; + int z; + + int size; +}; + +struct BlockChunk { + Chunk chunk; + + // Max size depends on CHUNK_SIZE (= CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE) + Block *entities; +}; + +struct BlockObjectChunk { + Chunk chunk; + + // Max size depends on CHUNK_SIZE (= CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE) + BlockObject *entities; +}; + +struct ObjectChunk { + Chunk chunk; + + // Max size is "unlimited" since multiple objects can be placed at any position + Object *enteties; +}; + + +#endif \ No newline at end of file diff --git a/models/object/Cube.h b/models/object/Cube.h new file mode 100644 index 0000000..f2c95d6 --- /dev/null +++ b/models/object/Cube.h @@ -0,0 +1,37 @@ +// 6 faces, 4 vertexes, 3 coordinates +positions = { + -1, -1, -1, -1, -1, +1, -1, +1, -1, -1, +1, +1, + +1, -1, -1, +1, -1, +1, +1, +1, -1, +1, +1, +1, + -1, +1, -1, -1, +1, +1, +1, +1, -1, +1, +1, +1, + -1, -1, -1, -1, -1, +1, +1, -1, -1, +1, -1, +1, + -1, -1, -1, -1, +1, -1, +1, -1, -1, +1, +1, -1, + -1, -1, +1, -1, +1, +1, +1, -1, +1, +1, +1, +1 +}; + +// 6 faces 3 coordinates +normals = { + -1, 0, 0, + +1, 0, 0, + 0, +1, 0, + 0, -1, 0, + 0, 0, -1, + 0, 0, +1 +}; + +indices = { + 0, 3, 2, 0, 1, 3, + 0, 3, 1, 0, 2, 3, + 0, 3, 2, 0, 1, 3, + 0, 3, 1, 0, 2, 3, + 0, 3, 2, 0, 1, 3, + 0, 3, 1, 0, 2, 3 +}; + +flipped = { + 0, 1, 2, 1, 3, 2, + 0, 2, 1, 2, 3, 1, + 0, 1, 2, 1, 3, 2, + 0, 2, 1, 2, 3, 1, + 0, 1, 2, 1, 3, 2, + 0, 2, 1, 2, 3, 1 +}; \ No newline at end of file diff --git a/models/object/Object.h b/models/object/Object.h new file mode 100644 index 0000000..9e1b230 --- /dev/null +++ b/models/object/Object.h @@ -0,0 +1,23 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_OBJECT_H +#define TOS_MODELS_OBJECT_H + +#include "../../../stdlib/Types.h" + +// Object coordinates are relative to the chunk coordinates +struct Object { + float x; + float y; + float z; + + uint32 type; // defined in object_list +}; + +#endif \ No newline at end of file diff --git a/models/object/ObjectType.h b/models/object/ObjectType.h new file mode 100644 index 0000000..97ac977 --- /dev/null +++ b/models/object/ObjectType.h @@ -0,0 +1,24 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_Object_TYPE_H +#define TOS_MODELS_Object_TYPE_H + +#include "../../config.h" +#include "../../../stdlib/Types.h" + +struct ObjectType { + byte id; + byte destructable; + bool climbable; + bool collectable; + bool drops; + bool changable; +}; + +#endif \ No newline at end of file diff --git a/models/object/object_list.h b/models/object/object_list.h new file mode 100644 index 0000000..7fe2b84 --- /dev/null +++ b/models/object/object_list.h @@ -0,0 +1,279 @@ +#ifndef TOS_MODELS_OBJECT_LIST_H +#define TOS_MODELS_OBJECT_LIST_H + +// (null) +#define OBJ_UNASSIGNED 0x00000000 +#define OBJ_ALCHEMY 0x000000CC +#define OBJ_BUCKET 0x000000D8 +#define OBJ_CART 0x000000C8 +#define OBJ_CHEESE 0x000000DB +#define OBJ_COMPASS 0x000000E3 +#define OBJ_DECANTER 0x000000DA +#define OBJ_FORK 0x000000D0 +#define OBJ_FURNACE 0x000000CB +#define OBJ_GADGETS 0x000000CD +#define OBJ_GLASS 0x000000D4 +#define OBJ_GLASSES 0x000000E4 +#define OBJ_GYROSCOPE 0x000000E0 +#define OBJ_ICE 0x00000097 +#define OBJ_JUG 0x000000D5 +#define OBJ_KNIFE 0x000000D2 +#define OBJ_LECTERN 0x000000CE +#define OBJ_LOOM 0x000000C9 +#define OBJ_MONOCLE 0x000000E5 +#define OBJ_NOODLE 0x000000DF +#define OBJ_PITCHER 0x000000D6 +#define OBJ_RUSSIAN_EGG 0x000000E6 +#define OBJ_SEXTANT 0x000000E2 +#define OBJ_SNOW 0x00000096 +#define OBJ_SOUP_PLATE 0x000000D3 +#define OBJ_SPINNING_MACHINE 0x000000CF +#define OBJ_SPOON 0x000000D1 +#define OBJ_STEAK 0x000000DC +#define OBJ_TELESCOPE 0x000000E1 +#define OBJ_TRAIN 0x000000CA +#define OBJ_TRAY 0x000000D7 +#define OBJ_TURKEY 0x000000DD +#define OBJ_WINE_GLASS 0x000000D9 + +// Ore +#define OBJ_ORE 0x04000000 +#define OBJ_ALUMINUM 0x04000006 +#define OBJ_AMBER 0x04000041 +#define OBJ_AMETHYST 0x04000040 +#define OBJ_BENITOITE 0x0400003C +#define OBJ_BISMUTH 0x04000007 +#define OBJ_BLACK_OPAL 0x0400003B +#define OBJ_CLAY 0x040000AD +#define OBJ_COAL 0x04000042 +#define OBJ_COBALT 0x04000008 +#define OBJ_COBBLESTONE 0x04000052 +#define OBJ_COPPER 0x04000009 +#define OBJ_DIAMOND 0x04000043 +#define OBJ_EARTH 0x04000002 +#define OBJ_EMERALD 0x04000044 +#define OBJ_FLINTSTONE 0x04000095 +#define OBJ_GOLD 0x0400000A +#define OBJ_GRANITE 0x0400004F +#define OBJ_IRON 0x0400000B +#define OBJ_JADEIT 0x0400003F +#define OBJ_LIMESTONE 0x0400004E +#define OBJ_MANGANESE 0x0400000C +#define OBJ_MARBLE 0x04000050 +#define OBJ_METEORITE 0x04000047 +#define OBJ_NICKEL 0x0400000D +#define OBJ_PHOSPHORUS 0x0400005F +#define OBJ_PLATINUM 0x0400000E +#define OBJ_QUARTZ 0x04000051 +#define OBJ_RED_BERYL 0x0400003A +#define OBJ_RED_MEAT 0x04000062 +#define OBJ_RUBY 0x04000049 +#define OBJ_SALT 0x04000060 +#define OBJ_SAND 0x04000001 +#define OBJ_SANDSTONE 0x0400005C +#define OBJ_SAPPHIRE 0x04000048 +#define OBJ_SILVER 0x0400000F +#define OBJ_STONE 0x04000003 +#define OBJ_SULFUR 0x0400005E +#define OBJ_TAAFFEIT 0x0400003E +#define OBJ_TANZANITE 0x0400003D +#define OBJ_TIN 0x040000AE +#define OBJ_TITANIUM 0x04000010 +#define OBJ_TUNGSTEN 0x04000011 +#define OBJ_VOLCANIC_ROCK 0x040000AC +#define OBJ_WHITE_MEAT 0x04000061 +#define OBJ_ZINC 0x040000AF + +// Block +#define OBJ_BLOCK 0x05000000 +#define OBJ_COLOR_BLOCK_1 0x050000EA +#define OBJ_COLOR_BLOCK_10 0x050000FA +#define OBJ_COLOR_BLOCK_11 0x050000FD +#define OBJ_COLOR_BLOCK_12 0x050000FE +#define OBJ_COLOR_BLOCK_13 0x050000FF +#define OBJ_COLOR_BLOCK_14 0x05000100 +#define OBJ_COLOR_BLOCK_15 0x05000101 +#define OBJ_COLOR_BLOCK_16 0x05000102 +#define OBJ_COLOR_BLOCK_2 0x050000F2 +#define OBJ_COLOR_BLOCK_3 0x050000F3 +#define OBJ_COLOR_BLOCK_4 0x050000F4 +#define OBJ_COLOR_BLOCK_5 0x050000F5 +#define OBJ_COLOR_BLOCK_6 0x050000F6 +#define OBJ_COLOR_BLOCK_7 0x050000F7 +#define OBJ_COLOR_BLOCK_8 0x050000F8 +#define OBJ_COLOR_BLOCK_9 0x050000F9 +#define OBJ_EARTH_BLOCK 0x050000EB +#define OBJ_GLASS_BLOCK 0x050000ED +#define OBJ_GRANITE_BLOCK 0x05000104 +#define OBJ_GRASS_BLOCK 0x050000F1 +#define OBJ_GRAVEL_BLOCK 0x05000103 +#define OBJ_ICE_BLOCK 0x050000EC +#define OBJ_ICE_COVER 0x050000EF +#define OBJ_LAVA_BLOCK 0x050000FC +#define OBJ_SAND_BLOCK 0x050000E7 +#define OBJ_SNOW_BLOCK 0x050000EE +#define OBJ_SNOW_COVER 0x050000F0 +#define OBJ_STONE_BLOCK 0x050000E8 +#define OBJ_WATER_BLOCK 0x050000FB +#define OBJ_WOOD_BLOCK 0x050000E9 + +// Herb +#define OBJ_HERB 0x06000000 +#define OBJ_ACONITUM 0x0600002D +#define OBJ_ALMONDS 0x0600006B +#define OBJ_ANTHURIUM 0x06000030 +#define OBJ_APPLE 0x06000081 +#define OBJ_AQUILEGIA 0x06000031 +#define OBJ_ARNICA 0x06000024 +#define OBJ_ARUM 0x06000032 +#define OBJ_ASPARAGUS 0x06000084 +#define OBJ_BANANA 0x06000086 +#define OBJ_BARLEY 0x0600004C +#define OBJ_BASIL 0x0600008F +#define OBJ_BEAN 0x0600007B +#define OBJ_BETONY 0x0600001D +#define OBJ_BLACK_ANTHURIUM 0x060000A8 +#define OBJ_BLACK_BACCARA 0x060000AB +#define OBJ_BLACK_DAHLIA 0x060000A9 +#define OBJ_BLACK_MAGIC 0x060000A7 +#define OBJ_BLACK_ORCHID 0x060000AA +#define OBJ_BLACKBERRY 0x06000063 +#define OBJ_BLACKWATER 0x060000A4 +#define OBJ_BLEEDING_HEART 0x06000039 +#define OBJ_BLOOD_FLOWER 0x06000019 +#define OBJ_BROCCOLI 0x06000079 +#define OBJ_BRUGMANSIA 0x06000033 +#define OBJ_BUCKWHEAT 0x0600004D +#define OBJ_CABBAGE 0x06000080 +#define OBJ_CACAO 0x06000067 +#define OBJ_CALADIUM 0x06000034 +#define OBJ_CAMELLIA 0x06000094 +#define OBJ_CARROT 0x0600007C +#define OBJ_CASHEW 0x0600006C +#define OBJ_CAULIFLOWER 0x0600007A +#define OBJ_CHERRY 0x06000082 +#define OBJ_CHESTNUTS 0x0600006A +#define OBJ_CINAMON 0x0600008D +#define OBJ_COCONUT 0x0600006D +#define OBJ_COFFEE 0x06000068 +#define OBJ_CONEFLOWER 0x06000021 +#define OBJ_CONSOLIDA 0x06000035 +#define OBJ_CORN 0x0600004A +#define OBJ_CORPSE_FLOWER 0x0600009B +#define OBJ_COTTON 0x06000028 +#define OBJ_CUCUMBER 0x06000075 +#define OBJ_DELPHINIUM 0x06000036 +#define OBJ_DESERT_ROSE 0x0600002F +#define OBJ_DRAGONFRUIT 0x0600008A +#define OBJ_FIBRE 0x06000046 +#define OBJ_FLAME_LILY 0x06000037 +#define OBJ_FOXGLOVE 0x0600001C +#define OBJ_GARLIC 0x0600007F +#define OBJ_GHOST_ORCHID 0x0600009D +#define OBJ_GINGER 0x0600008C +#define OBJ_GINGKO 0x06000016 +#define OBJ_GRAPES 0x0600008B +#define OBJ_GREEN_ONION 0x06000078 +#define OBJ_HAZELNUT 0x0600006E +#define OBJ_HENBANE 0x06000020 +#define OBJ_HOLLYHOCK 0x060000A2 +#define OBJ_HYACINTH 0x060000A3 +#define OBJ_HYDRANGEA 0x060000A0 +#define OBJ_IRIS 0x06000038 +#define OBJ_JASMINE 0x06000091 +#define OBJ_KALE 0x06000085 +#define OBJ_LATHYRUS 0x0600002A +#define OBJ_LAVENDER 0x06000014 +#define OBJ_LEMON 0x06000098 +#define OBJ_LETTUCE 0x06000071 +#define OBJ_LILY 0x0600001E +#define OBJ_LINEN 0x06000029 +#define OBJ_MACADAMIA 0x0600006F +#define OBJ_MARIGOLD 0x0600001B +#define OBJ_MARSH_MALLOW 0x06000023 +#define OBJ_MATCHA 0x06000099 +#define OBJ_MIDDLEMIST 0x0600009C +#define OBJ_MIDNIGHT_MYSTIC 0x060000A6 +#define OBJ_MIDNIGHT_RUFFLES 0x060000A5 +#define OBJ_MUSHROOM 0x06000072 +#define OBJ_NIGHTSHADE 0x06000022 +#define OBJ_ONION 0x06000077 +#define OBJ_ORANGE 0x06000083 +#define OBJ_OREGANO 0x0600008E +#define OBJ_PEACH 0x06000088 +#define OBJ_PEANUTS 0x06000069 +#define OBJ_PEAS 0x06000064 +#define OBJ_PECANS 0x06000070 +#define OBJ_PEONY 0x0600009E +#define OBJ_PEPERMINT 0x06000092 +#define OBJ_PEPPER 0x06000073 +#define OBJ_PERIWINKLE 0x0600001A +#define OBJ_PINEAPPLE 0x06000087 +#define OBJ_PLATYCODON 0x060000A1 +#define OBJ_POTATOS 0x06000065 +#define OBJ_PUMPKIN 0x06000076 +#define OBJ_RADISH 0x0600007E +#define OBJ_RASPBERRY 0x06000093 +#define OBJ_RICE 0x0600004B +#define OBJ_ROSARY_BEAD 0x0600002C +#define OBJ_SAGE 0x06000017 +#define OBJ_SENNA 0x0600001F +#define OBJ_SILK 0x06000027 +#define OBJ_SOLANUM 0x0600002B +#define OBJ_SPINACH 0x0600007D +#define OBJ_STAR_ANISE 0x06000090 +#define OBJ_TOMATO 0x06000074 +#define OBJ_TURMERIC 0x06000018 +#define OBJ_WALNUT 0x06000066 +#define OBJ_WATERMELON 0x06000089 +#define OBJ_WELWITSCHIA 0x0600009A +#define OBJ_WHEAT 0x06000045 +#define OBJ_WHITE_BANEBERRY 0x0600002E +#define OBJ_WISTERIA 0x0600009F +#define OBJ_YARROW 0x06000025 + +// Liquid +#define OBJ_LIQUID 0x07000000 +#define OBJ_LAVA 0x0700005D +#define OBJ_WATER 0x07000005 + +// Plant +#define OBJ_PLANT 0x0A000000 +#define OBJ_ACACIA_WOOD 0x0A00005B +#define OBJ_ASH_WOOD 0x0A000058 +#define OBJ_BAMBOO_WOOD 0x0A000054 +#define OBJ_ELM_WOOD 0x0A000057 +#define OBJ_MAHOGANY_WOOD 0x0A000059 +#define OBJ_OAK_WOOD 0x0A000055 +#define OBJ_PINE_WOOD 0x0A000056 +#define OBJ_TEAK_WOOD 0x0A00005A +#define OBJ_WALNUT_WOOD 0x0A000053 +#define OBJ_WOOD 0x0A000004 + +// Static Object +#define OBJ_STATIC_OBJECT 0x0B000000 +#define OBJ_BAR 0x0B0000BA +#define OBJ_BARREL 0x0B0000BE +#define OBJ_BED 0x0B0000BB +#define OBJ_BOOK 0x0B0000C3 +#define OBJ_CHAIR 0x0B0000B6 +#define OBJ_CRATE 0x0B0000BF +#define OBJ_DOOR 0x0B0000C4 +#define OBJ_FIREPLACE 0x0B0000C1 +#define OBJ_IMAGE 0x0B0000B8 +#define OBJ_LAMP 0x0B0000B5 +#define OBJ_NIGHT_STAND 0x0B0000BC +#define OBJ_OVEN 0x0B0000BD +#define OBJ_PLATE 0x0B0000C0 +#define OBJ_POT 0x0B0000C2 +#define OBJ_SHELF 0x0B0000B9 +#define OBJ_TABLE 0x0B0000B4 +#define OBJ_TOOLS 0x0B0000C7 +#define OBJ_WALL_ORNAMENTS 0x0B0000C6 +#define OBJ_WINDOW 0x0B0000C5 + +// Static Texture +#define OBJ_STATIC_TEXTURE 0x0D000000 +#define OBJ_CARPET 0x0D0000B7 + +#endif \ No newline at end of file diff --git a/models/object/object_types.h b/models/object/object_types.h new file mode 100644 index 0000000..472ae59 --- /dev/null +++ b/models/object/object_types.h @@ -0,0 +1,27 @@ +#ifndef TOS_MODELS_OBJECT_TYPES_H +#define TOS_MODELS_OBJECT_TYPES_H + +#define OBJECT_TYPE_LADDER 0x01 +#define OBJECT_TYPE_ROPE 0x02 +#define OBJECT_TYPE_VINES 0x03 +#define OBJECT_TYPE_ORE 0x04 +#define OBJECT_TYPE_BLOCK 0x05 +#define OBJECT_TYPE_HERB 0x06 +#define OBJECT_TYPE_LIQUID 0x07 +#define OBJECT_TYPE_PARTICLE 0x08 +#define OBJECT_TYPE_FARMING 0x09 +#define OBJECT_TYPE_PLANT 0x0A +#define OBJECT_TYPE_STATIC_OBJECT 0x0B +#define OBJECT_TYPE_DYNAMIC_OBJECT 0x0C +#define OBJECT_TYPE_STATIC_TEXTURE 0x0D +#define OBJECT_TYPE_FIXED_LIGHT_SOURCE 0x0E +#define OBJECT_TYPE_DYNAMIC_LIGHT_SOURCE 0x0F +#define OBJECT_TYPE_DYNAMIC_TEXTURE 0x10 +#define OBJECT_TYPE_VEHICLE 0x11 +#define OBJECT_TYPE_MACHINE 0x12 +#define OBJECT_TYPE_MOB 0x13 +#define OBJECT_TYPE_FOOD 0x14 + +#define SIZE_OBJECT_TYPE 0x14 + +#endif \ No newline at end of file diff --git a/models/settings/Settings.h b/models/settings/Settings.h new file mode 100644 index 0000000..78705b1 --- /dev/null +++ b/models/settings/Settings.h @@ -0,0 +1,359 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_MODELS_SETTINGS_H +#define TOS_MODELS_SETTINGS_H + +#include "../../stdlib/Types.h" + +#include "../chat/ChatStatus.h" +#include "setting_types.h" + +#if SERVER + struct SSettings { + byte distance_terrain = RENDER_CHUNK_RADIUS; + byte distance_terrain_secondary = RENDER_BLOCK_OBJECT_CHUNK_RADIUS; + byte distance_terrain_tertiary = RENDER_INTERACTIVE_CHUNK_RADIUS; + byte distance_models = RENDER_OBJECT_CHUNK_RADIUS; + byte distance_monster = RENDER_MONSTER_CHUNK_RADIUS; + byte distance_npc = RENDER_NPC_CHUNK_RADIUS; + byte distance_player = RENDER_PAYER_CHUNK_RADIUS; + + uint32 player_cache = 8192; // = max active players on a server + uint32 monster_cache = 8192; + uint32 npc_cache = 8192; + uint32 guild_cache = 128; + uint32 message_cache = 1024; + + uint32 interpolation_buffer; + byte simd_version; + }; + + // Player settings that the server needs to know about + struct PSettings { + byte render_distance_models = RENDER_OBJECT_CHUNK_RADIUS; + byte render_distance_monster = RENDER_MONSTER_CHUNK_RADIUS; + byte render_distance_npc = RENDER_NPC_CHUNK_RADIUS; + byte render_distance_player = RENDER_PAYER_CHUNK_RADIUS; + + byte chat_status = CHAT_STATUS_OFFLINE; + bool allow_invites = true; + }; +#endif + +struct CSettings { + char path[MAX_PATH]; + bool is_changed = false; + byte simd_version; + + byte gpu_api = SETTING_TYPE_GPU_API_NONE; + byte gpu_type = SETTING_TYPE_GPU_MEDIUM; + byte gpu_fps = SETTING_TYPE_UNLIMITED; + + byte gpu_aspect_ratio; + byte gpu_resolution; + byte gpu_brightness; + byte gpu_contrast; + byte gpu_gamma; + byte gpu_fov; + byte gpu_sync = SETTING_TYPE_DISABLED; + + char editor_hostname[64]; + uint16 editor_port; + + uint32 gpu_number_of_npc_characters = 128; + uint32 gpu_number_of_player_characters = 512; + uint32 gpu_number_of_monster_characters = 128; + + byte gpu_render_distance_terrain = 10; + byte gpu_render_distance_terrain_secondary = 10; + byte gpu_render_distance_terrain_tertiary = 1; + byte gpu_render_distance_models = 1; + byte gpu_render_distance_monster = 3; + byte gpu_render_distance_npc = 3; + byte gpu_render_distance_player = 3; + + uint32 player_cache = 512; + uint32 monster_cache = 128; + uint32 npc_cache = 128; + uint32 guild_cache = 128; + uint32 message_cache = 64; + + byte gpu_animation_quality; + byte gpu_attack_effect_quality; + byte gpu_shadow_quality; + byte gpu_terrain_quality; + byte gpu_water_quality; + byte gpu_grass_density; + byte gpu_model_quality; + byte gpu_texture_quality; + byte gpu_foliage_distance; + byte gpu_detail_level; + byte gpu_reflection_quality; + byte gpu_refraction_quality; + byte gpu_caustics_quality; + byte gpu_footprint_quality; // mostly used for snow, sand mud + bool gpu_screen_effects; // e.g. water droplets/dust/freezing on screen + + byte gpu_memory = 7; + byte cpu_memory = 10; + + bool gpu_raytracing = false; + bool gpu_lense_effect = true; + bool gpu_fog_effect = true; + bool gpu_particles_environment = true; + bool gpu_particles_players = true; + bool gpu_particles_monster = true; + bool gpu_particles_ui = true; + bool gpu_particles_skills = true; + bool gpu_particles_weapons = true; + + byte gpu_reflection_blur = SETTING_TYPE_DISABLED; + byte gpu_motion_blur = SETTING_TYPE_DISABLED; + byte gpu_blur = SETTING_TYPE_DISABLED; + byte gpu_anti_aliasing = SETTING_TYPE_DISABLED; + byte gpu_sharpening = SETTING_TYPE_DISABLED; + byte gpu_ambient_occlusion = SETTING_TYPE_DISABLED; + + bool gpu_depth_of_field = true; + bool gpu_chromatic_aberration = true; + bool gpu_vignetting = true; + bool gpu_light_shafts = true; + bool gpu_camera_shake = false; + + byte audio_volume_master = 128; + byte audio_volume_game = 128; + byte audio_volume_environment = 128; + byte audio_volume_music = 128; + byte audio_volume_speech = 128; + + uint32 game_window1_dim[2] = {1024, 768}; + uint32 game_window1_pos[2]; + byte game_window1_mode = SETTING_TYPE_WINDOW_MODE_FULLSCREEN; + + byte game_zoom; + byte game_view = SETTING_TYPE_PERSPECTIVE_FIRST; + + // General game UI + bool game_crosshair = false; + + bool game_healthbar_self = false; + bool game_healthbar_group = false; + bool game_healthbar_players = false; + bool game_healthbar_npc = false; + bool game_healthbar_monsters = false; + + bool game_name_monsters = false; + bool game_name_npc = false; + bool game_name_mobs = false; + + bool game_show_auras = true; + bool game_show_helmets = true; + + uint32 game_interpolation_buffer; + + bool game_player_chat = false; // bubble above player + byte game_chat_status = CHAT_STATUS_OFFLINE; + + // Extra windows + byte game_window2_type = SETTING_TYPE_DISABLED; + bool game_window2_visible = false; + uint32 game_window2_dim[2] = {1024, 768}; + uint32 game_window2_pos[2]; + + byte game_window3_type = SETTING_TYPE_DISABLED; + bool game_window3_visible = false; + uint32 game_window3_dim[2] = {1024, 768}; + uint32 game_window3_pos[2]; + + byte game_window4_type = SETTING_TYPE_DISABLED; + bool game_window4_visible = false; + uint32 game_window4_dim[2] = {1024, 768}; + uint32 game_window4_pos[2]; + + byte game_window5_type = SETTING_TYPE_DISABLED; + bool game_window5_visible = false; + uint32 game_window5_dim[2] = {1024, 768}; + uint32 game_window5_pos[2]; + + // @todo Consider to allow settings for chat tabs + // define which messags go to which tab + // define custom chat tabs + + // UI settings + // Themes + uint32 game_ui_theme = 1; + byte game_ui_size = 128; + + uint32 game_item_icon_theme = 1; + + uint32 game_menu_theme = 1; + byte game_menu_size = 128; + + uint32 game_map_mini_theme = 1; + byte game_map_mini_size = 128; + int32 game_map_mini_pos[2] = { -1, -1 }; + + uint32 game_quest_theme = 1; + byte game_quest_size = 128; + int32 game_quest_pos[2] = { -1, -1 }; + + uint32 game_skill_bar_theme = 1; + bool game_skill_bar_animated = false; + byte game_skill_bar_size = 128; + int32 game_skill_bar_pos[2] = { -1, -1 }; + + uint32 game_health_theme = 1; + bool game_health_animated = false; + byte game_health_size = 128; + int32 game_health_pos[2] = { -1, -1 }; + + uint32 game_resource_theme = 1; + bool game_resource_animated = false; + byte game_resource_size = 128; + int32 game_resource_pos[2] = { -1, -1 }; + + uint32 game_party_theme = 1; + bool game_party_animated = false; + byte game_party_size = 128; + int32 game_party_pos[2] = { -1, -1 }; + + uint32 game_enemy_theme = 1; + bool game_enemy_animated = false; + byte game_enemy_size = 128; + int32 game_enemy_pos[2] = { -1, -1 }; + + uint32 game_select_info_theme = 1; + byte game_select_info_size = 128; + int32 game_select_info_pos[2] = { -1, -1 }; + + uint32 game_chat_theme = 1; + byte game_chat_size = 128; + int32 game_chat_pos[2] = { -1, -1 }; + + // HUD + bool game_show_health_bar_self = false; + bool game_show_health_bar_player = false; + bool game_show_health_bar_monster = false; + bool game_show_health_numbers = false; + bool game_show_resource_numbers = false; + bool game_show_buffs = false; + bool game_show_xp_bar_numbers = true; + + bool game_show_name_self = false; + bool game_show_name_player = false; + bool game_show_name_monster = false; + bool game_show_name_npc = false; + bool game_show_title_self = false; + bool game_show_title_other = false; + byte game_minion_visibility_self = 128; + byte game_minion_visibility_player = 128; + + bool game_show_dmg_numbers = false; + bool game_show_cooldown_times = false; + bool game_show_dodge = true; + bool game_show_effect_gains = true; // e.g. XP + + bool game_minimap_show_merchants = false; + bool game_minimap_show_quest = false; + bool game_minimap_show_dungeons = false; + bool game_minimap_show_names = false; + bool game_show_clock = false; + + bool game_map_show_merchants = false; + bool game_map_show_quest = false; + bool game_map_show_dungeons = false; + bool game_map_show_names = false; + + bool game_show_subtitles = true; + + // Mounts + uint32 game_default_mount = 0; + + // Game behavior + bool game_error_audio = true; + bool game_error_text = true; + byte game_default_zoom = 128; + bool game_block_trade = false; + bool game_block_group_invite = false; + bool game_block_guild_invite = false; + bool game_block_chat_invite = false; + bool game_block_friend_invite = false; + bool game_automatically_track_newest_quest = false; + + byte game_interact_direction = 0; + byte game_interact_radius = 1; + + // Game pad settings + byte stick_left_deadzone = 0; + byte stick_right_deadzone = 0; + + byte input_look_speed = 0; + bool input_invert_mouse = false; + bool input_lock_cursor_to_window = true; + bool input_click_to_move = true; + + // Hotkey settings + byte hotkeys_movement_up = 0x57; // W + byte hotkeys_movement_down = 0x53; // S + byte hotkeys_movement_left = 0x41; // A + byte hotkeys_movement_right = 0x44; // D + + byte hotkeys_cancel_action = 0x44; // X + + byte hotkeys_skill_tab_1 = 0x70; // F1 + byte hotkeys_skill_tab_2 = 0x71; // F2 + byte hotkeys_skill_tab_3 = 0x72; // F3 + + byte hotkeys_skill_1 = 0x31; // 1 + byte hotkeys_skill_2 = 0x32; // 2 + byte hotkeys_skill_3 = 0x33; // 3 + byte hotkeys_skill_4 = 0x34; // 4 + byte hotkeys_skill_5 = 0x35; // 5 + byte hotkeys_skill_6 = 0x36; // 6 + byte hotkeys_skill_7 = 0x37; // 7 + byte hotkeys_skill_8 = 0x38; // 8 + byte hotkeys_skill_9 = 0x39; // 9 + byte hotkeys_skill_10 = 0x30; // 0 + + byte hotkeys_interact = 45; // E + byte hotkeys_jump = 0x20; // SPACE + + byte hotkeys_dodge = 0x20; // SPACE + byte hotkeys_crouch = 0x14; // CAP + byte hotkeys_walk = 0x11; // CTRL (switches to walking speed, one click only) + byte hotkeys_emote = 0x12; // LEFT_ALT + byte hotkeys_vertical_up = 0x14; // CAPS LOCK + byte hotkeys_vertical_down = 0x10; // SHIFT + + byte hotkeys_view_next = 0x09; // TAB + byte hotkeys_view_prv = 0x14; // CAPS LOCK + byte hotkeys_compare_item = 0x11; // CTRL + + byte hotkeys_inventory = 0x49; // I + byte hotkeys_character = 0x43; // C + byte hotkeys_skills = 0x53; // S + byte hotkeys_map = 0x4D; // M + byte hotkeys_quest = 0x51; // Q + byte hotkeys_teleport = 0x54; // T + byte hotkeys_attack_move = 0x52; // R + byte hotkeys_force_move = 0x46; // F + byte hotkeys_courser_move = 0x58; // X (move to where courser is) + + byte hotkeys_chat = 0x0D; // ENTER + byte hotkeys_hide_ui = 0x48; // H + + byte hotkey_zoom_in = 0x21; // Page up (@todo make mouse scroll up) + byte hotkey_zoom_out = 0x22; // page down (@todo make mouse scroll down) + byte hotkey_camera_look = 0x00; // @todo make right mouse hold + + byte hotkeys_menu = 0x1B; // ESC + byte hotkeys_window_close = 0x1B; // ESC +}; + +#endif \ No newline at end of file diff --git a/models/settings/client_high.cfg b/models/settings/client_high.cfg new file mode 100644 index 0000000..e69de29 diff --git a/models/settings/client_low.cfg b/models/settings/client_low.cfg new file mode 100644 index 0000000..e69de29 diff --git a/models/settings/client_medium.cfg b/models/settings/client_medium.cfg new file mode 100644 index 0000000..e69de29 diff --git a/models/settings/client_vhigh.cfg b/models/settings/client_vhigh.cfg new file mode 100644 index 0000000..e69de29 diff --git a/models/settings/client_vlow.cfg b/models/settings/client_vlow.cfg new file mode 100644 index 0000000..f291ae1 --- /dev/null +++ b/models/settings/client_vlow.cfg @@ -0,0 +1,22 @@ +gpu_type +gpu_fps + +gpu_sync + +gpu_number_of_npc_characters +gpu_number_of_player_characters +gpu_number_of_monster_characters + +gpu_render_distance_terrain +gpu_render_distance_terrain_secondary +gpu_render_distance_terrain_tertiary +gpu_render_distance_models +gpu_render_distance_monster +gpu_render_distance_npc +gpu_render_distance_player + +player_cache +monster_cache +npc_cache +guild_cache +message_cache \ No newline at end of file diff --git a/models/settings/setting_types.h b/models/settings/setting_types.h new file mode 100644 index 0000000..3c66334 --- /dev/null +++ b/models/settings/setting_types.h @@ -0,0 +1,77 @@ +#ifndef TOS_MODELS_SETTING_TYPES_H +#define TOS_MODELS_SETTING_TYPES_H + +#define SETTING_TYPE_GPU_CUSTOM 0x0 +#define SETTING_TYPE_GPU_VLOW 0x1 +#define SETTING_TYPE_GPU_LOW 0x2 +#define SETTING_TYPE_GPU_MEDIUM 0x3 +#define SETTING_TYPE_GPU_HIGH 0x4 +#define SETTING_TYPE_GPU_VHIGH 0x5 +#define SETTING_TYPE_GPU_ULTRA 0x6 +#define SETTING_TYPE_GPU_NEXTGEN 0x7 + +#define SETTING_TYPE_GPU_API_NONE 0x0 +#define SETTING_TYPE_GPU_API_DIRECTX11 0x1 +#define SETTING_TYPE_GPU_API_DIRECTX12 0x2 +#define SETTING_TYPE_GPU_API_OPENGL 0x3 + +#define SETTING_TYPE_PERSPECTIVE_FIRST 0x00 +#define SETTING_TYPE_PERSPECTIVE_THIRD 0x01 +#define SETTING_TYPE_PERSPECTIVE_ISOMETRIC 0x02 + +#define SETTING_TYPE_ANTI_ALIASING_TAA 0x01 +#define SETTING_TYPE_ANTI_ALIASING_SSAA 0x02 +#define SETTING_TYPE_ANTI_ALIASING_MSAA 0x03 +#define SETTING_TYPE_ANTI_ALIASING_FXAA 0x04 + +#define SETTING_TYPE_SYNC_V 0x1 +#define SETTING_TYPE_SYNC_ADAPTIVE 0x2 +#define SETTING_TYPE_SYNC_FAST 0x3 + +#define SETTING_TYPE_ASPEC_RATIO_4x3 0x00 +#define SETTING_TYPE_ASPEC_RATIO_16x9 0x01 +#define SETTING_TYPE_ASPEC_RATIO_16x10 0x02 +#define SETTING_TYPE_ASPEC_RATIO_21x9 0x03 + +#define SETTING_TYPE_SCREEN_RESOLUTION_800x600 0x00 +#define SETTING_TYPE_SCREEN_RESOLUTION_1024x768 0x01 +#define SETTING_TYPE_SCREEN_RESOLUTION_1280x720 0x02 +#define SETTING_TYPE_SCREEN_RESOLUTION_1280x800 0x03 +#define SETTING_TYPE_SCREEN_RESOLUTION_1280x1024 0x04 +#define SETTING_TYPE_SCREEN_RESOLUTION_1360x768 0x05 +#define SETTING_TYPE_SCREEN_RESOLUTION_1366x768 0x06 +#define SETTING_TYPE_SCREEN_RESOLUTION_1440x900 0x07 +#define SETTING_TYPE_SCREEN_RESOLUTION_1536x864 0x08 +#define SETTING_TYPE_SCREEN_RESOLUTION_1600x900 0x09 +#define SETTING_TYPE_SCREEN_RESOLUTION_1600x1200 0x0A +#define SETTING_TYPE_SCREEN_RESOLUTION_1680x1050 0x0B +#define SETTING_TYPE_SCREEN_RESOLUTION_1920x1080 0x0C +#define SETTING_TYPE_SCREEN_RESOLUTION_1920x1200 0x0D +#define SETTING_TYPE_SCREEN_RESOLUTION_2048x1152 0x0E +#define SETTING_TYPE_SCREEN_RESOLUTION_2048x1536 0x0F +#define SETTING_TYPE_SCREEN_RESOLUTION_2560x1080 0x10 +#define SETTING_TYPE_SCREEN_RESOLUTION_2560x1440 0x11 +#define SETTING_TYPE_SCREEN_RESOLUTION_2560x1600 0x12 +#define SETTING_TYPE_SCREEN_RESOLUTION_3440x1440 0x13 +#define SETTING_TYPE_SCREEN_RESOLUTION_3840x2160 0x14 + +#define SETTING_TYPE_WINDOW_CHAT 0x01 +#define SETTING_TYPE_WINDOW_MAP 0x02 +#define SETTING_TYPE_WINDOW_RANKING 0x03 +#define SETTING_TYPE_WINDOW_SHOP 0x04 +#define SETTING_TYPE_WINDOW_STATS 0x05 +#define SETTING_TYPE_WINDOW_GROUPS 0x06 +#define SETTING_TYPE_WINDOW_PET 0x07 // Pet "tamagochi" window + +#define SETTING_TYPE_WINDOW_MODE_FULLSCREEN 0x00 +#define SETTING_TYPE_WINDOW_MODE_WINDOWED_FULLSCREEN 0x01 +#define SETTING_TYPE_WINDOW_MODE_WINDOWED 0x02 + +#define SETTING_TYPE_SIMD_128 1 +#define SETTING_TYPE_SIMD_256 2 +#define SETTING_TYPE_SIMD_512 3 + +#define SETTING_TYPE_DISABLED 0x00 +#define SETTING_TYPE_UNLIMITED 0x00 + +#endif \ No newline at end of file diff --git a/network/Client.h b/network/Client.h new file mode 100644 index 0000000..9c36e19 --- /dev/null +++ b/network/Client.h @@ -0,0 +1,84 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_NETWORK_CLIENT_H +#define TOS_NETWORK_CLIENT_H + +#include +#include +#include + +#include "SocketConnection.h" +#include "../stdlib/Types.h" +#include "../utils/RingMemory.h" + +#if _WIN32 + #include + #include + #define close closesocket + #define sleep Sleep +#else + #include + #include + #include +#endif + +#ifndef MAX_STATIC_NETWORK_PACKET_SIZE + #define MAX_STATIC_NETWORK_PACKET_SIZE 8192 +#endif + +SOCKET socket_client_udb_connect(const char *hostname, int port, sockaddr_in6 *server_addr) { + addrinfo hints, *res, *p; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + + char port_str[6]; + snprintf(port_str, sizeof(port_str), "%d", port); + + if (getaddrinfo(hostname, port_str, &hints, &res) != 0) { + return NULL; + } + + SOCKET sd = NULL; + for (p = res; p != NULL; p = p->ai_next) { + if ((sd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + continue; + } + + memcpy(server_addr, p->ai_addr, p->ai_addrlen); + break; + } + + freeaddrinfo(res); + + if (p == NULL) { + return NULL; + } + + return sd; +} + +int socket_client_send(SOCKET sd, char *data, size_t length, sockaddr_in6 *server_addr, socklen_t addr_len) { + int sent_bytes = sendto(sd, data, (int) length, 0, (sockaddr *)server_addr, addr_len); + if (sent_bytes == -1) { + return -1; + } + + return 0; +} + +int socket_client_disconnect(SOCKET sd) +{ + close(sd); + + return 0; +} + +#endif \ No newline at end of file diff --git a/network/Server.h b/network/Server.h new file mode 100644 index 0000000..6fb4de8 --- /dev/null +++ b/network/Server.h @@ -0,0 +1,8 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ \ No newline at end of file diff --git a/network/SocketConnection.h b/network/SocketConnection.h new file mode 100644 index 0000000..b33b879 --- /dev/null +++ b/network/SocketConnection.h @@ -0,0 +1,27 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_NETWORK_SOCKET_CONNECTION_H +#define TOS_NETWORK_SOCKET_CONNECTION_H + +#if _WIN32 + #include + #include +#else + #include + #include + #include +#endif + +struct SocketConnection { + SOCKET sd; + sockaddr_in6 server_addr; + socklen_t addr_len; +}; + +#endif \ No newline at end of file diff --git a/network/packet/PacketHeader.h b/network/packet/PacketHeader.h new file mode 100644 index 0000000..f28ce02 --- /dev/null +++ b/network/packet/PacketHeader.h @@ -0,0 +1,103 @@ +#ifndef TOS_NETWORK_PACKET_HEADER_H +#define TOS_NETWORK_PACKET_HEADER_H + +#include + +#include "../../stdlib/Types.h" + +#define HEADER_IPV6_SIZE 40 +// Size 40 bytes +struct HeaderIPv6 { + byte data[HEADER_IPV6_SIZE]; +}; + +// Size 42 bytes +struct HeaderIPv6Unpacked { + byte version; + byte traffic_class; + uint32 flow_label; + + uint16 length; + byte next_header; + byte hop_limit; + + byte src[16]; + byte dst[16]; +}; + +inline +void unpack_ipv6_header(const HeaderIPv6* ipv6, HeaderIPv6Unpacked* ipv6_unpacked) +{ + ipv6_unpacked->version = (ipv6->data[0] >> 4) & 0x0F; + ipv6_unpacked->traffic_class = ((ipv6->data[0] & 0x0F) << 4) | (ipv6->data[1] >> 4); + ipv6_unpacked->flow_label = ((ipv6->data[1] & 0x0F) << 16) | (ipv6->data[2] << 8) | ipv6->data[3]; + ipv6_unpacked->length = (ipv6->data[4] << 8) | ipv6->data[5]; + ipv6_unpacked->next_header = ipv6->data[6]; + ipv6_unpacked->hop_limit = ipv6->data[7]; + + memcpy(ipv6_unpacked->src, &ipv6->data[8], 16); + memcpy(ipv6_unpacked->dst, &ipv6->data[24], 16); +} + +inline +void pack_ipv6_header(const HeaderIPv6Unpacked* ipv6_unpacked, HeaderIPv6* ipv6) +{ + ipv6->data[0] = (ipv6_unpacked->version << 4) | (ipv6_unpacked->traffic_class >> 4); + ipv6->data[1] = (ipv6_unpacked->traffic_class << 4) | ((ipv6_unpacked->flow_label >> 16) & 0x0F); + ipv6->data[1] |= (ipv6_unpacked->flow_label >> 16) & 0x0F; + ipv6->data[2] = (ipv6_unpacked->flow_label >> 8) & 0xFF; + ipv6->data[3] = ipv6_unpacked->flow_label & 0xFF; + ipv6->data[4] = (ipv6_unpacked->length >> 8) & 0xFF; + ipv6->data[5] = ipv6_unpacked->length & 0xFF; + ipv6->data[6] = ipv6_unpacked->next_header; + ipv6->data[7] = ipv6_unpacked->hop_limit; + + memcpy(&ipv6->data[8], ipv6_unpacked->src, 16); + memcpy(&ipv6->data[24], ipv6_unpacked->dst, 16); +} + +#define HEADER_UDP_SIZE 8 +// Size 8 bytes +struct UDPHeaderIPv6 { + byte data[HEADER_UDP_SIZE]; +}; + +// Size 8 bytes +struct UDPHeaderIPv6Unpacked { + uint16 src_port; + uint16 dst_port; + uint16 length; + uint16 checksum; +}; + +inline +void unpack_udp_header_ipv6(const UDPHeaderIPv6* ipv6, UDPHeaderIPv6Unpacked* udp_unpacked) +{ + udp_unpacked->src_port = (ipv6->data[0] << 8) | ipv6->data[1]; + udp_unpacked->dst_port = (ipv6->data[2] << 8) | ipv6->data[3]; + udp_unpacked->length = (ipv6->data[4] << 8) | ipv6->data[5]; + udp_unpacked->checksum = (ipv6->data[6] << 8) | ipv6->data[7]; +} + +inline +void pack_udp_header_ipv6(const UDPHeaderIPv6Unpacked* udp_unpacked, UDPHeaderIPv6* ipv6) +{ + ipv6->data[0] = (udp_unpacked->src_port >> 8) & 0xFF; + ipv6->data[1] = udp_unpacked->src_port & 0xFF; + ipv6->data[2] = (udp_unpacked->dst_port >> 8) & 0xFF; + ipv6->data[3] = udp_unpacked->dst_port & 0xFF; + ipv6->data[4] = (udp_unpacked->length >> 8) & 0xFF; + ipv6->data[5] = udp_unpacked->length & 0xFF; + ipv6->data[6] = (udp_unpacked->checksum >> 8) & 0xFF; + ipv6->data[7] = udp_unpacked->checksum & 0xFF; +} + +// Size 7 bytes +struct CustomHeaderUnpacked { + uint16 msg_sequence; + uint16 msg_ack_sequence; + uint16 msg_ack; + byte msg_type; +}; + +#endif \ No newline at end of file diff --git a/network/packet/UDPPacket.h b/network/packet/UDPPacket.h new file mode 100644 index 0000000..0822e3f --- /dev/null +++ b/network/packet/UDPPacket.h @@ -0,0 +1,83 @@ +#ifndef TOS_NETWORK_PACKET_H +#define TOS_NETWORK_PACKET_H + +#include + +#include "../../stdlib/Types.h" +#include "../../compression/LZP.h" + +#include "PacketHeader.h" + +// The message loop is as follows: +// Game Data -> pack data +// Game Message (packed) -> compress data +// Game Message (compressed) -> combine (ipv6 header + udp header + body) +// Packet +// ... Send ... +// ... Receive ... +// Packet -> split (ipv6 header + udp header + body) +// Game Message (compressed) -> decompress data +// Game Message (packed) -> unpack data +// Game Data + +// Game messages +// Type 1: Snapshot = absolute state +// Type 2: Delta = relative data to previous data +// Can be usually much smaller data size, since deltas are usually small + +struct UDPPacketIPv6 { + byte* data; +}; + +struct UDPMessageIPv6 { + HeaderIPv6Unpacked header_ipv6; + UDPHeaderIPv6Unpacked header_udp; + CustomHeaderUnpacked header_custom; + + size_t length; + byte* data; +}; + +/** + * WARNING: This requires the original message to remain in memory since we are only referencing the data + */ +inline +void udp_packet_to_message(const UDPPacketIPv6* packet, UDPMessageIPv6* message) +{ + unpack_ipv6_header((const HeaderIPv6*) packet->data, &message->header_ipv6); + unpack_udp_header_ipv6((const UDPHeaderIPv6*) (packet->data + HEADER_IPV6_SIZE), &message->header_udp); + message->data = (byte *) (packet->data + HEADER_IPV6_SIZE + HEADER_UDP_SIZE); + + // @todo transform packet data to appropriate packet type +} + +/** + * The original message can be deleted since the data is copied over + */ +inline +void message_to_udp_packet(const UDPMessageIPv6* message, UDPPacketIPv6* packet) +{ + pack_ipv6_header(&message->header_ipv6, (HeaderIPv6 *) packet); + + packet->data = packet->data + HEADER_IPV6_SIZE; + pack_udp_header_ipv6(&message->header_udp, (UDPHeaderIPv6 *) packet); + packet->data = packet->data - HEADER_IPV6_SIZE; + + memcpy(packet->data + HEADER_IPV6_SIZE + HEADER_UDP_SIZE, message->data, message->length); +} + +inline +void decompress_data(UDPMessageIPv6* message, byte* decompress_buffer) +{ + decode_lzp(message->data, message->length, decompress_buffer); + message->data = decompress_buffer; +} + +inline +void compress_data(UDPMessageIPv6* message, byte* compressed_buffer) +{ + encode_lzp(message->data, message->length, compressed_buffer); + message->data = compressed_buffer; +} + +#endif \ No newline at end of file diff --git a/network/packet/chat/ChatMessagePacket.h b/network/packet/chat/ChatMessagePacket.h new file mode 100644 index 0000000..f66f2c4 --- /dev/null +++ b/network/packet/chat/ChatMessagePacket.h @@ -0,0 +1,24 @@ +#ifndef TOS_NETWORK_PACKET_CHAT_MESSAGE_H +#define TOS_NETWORK_PACKET_CHAT_MESSAGE_H + +#include + +#include "../../../stdlib/Types.h" +#include "../../../config.h" + +struct ChatMessagePacket { + byte* data; // fixed 8+2+? +}; + +struct ChatMessagePacketUnpacked { + uint32 from; + uint32 to; + + byte type; // 2^3 Global, Player, Group, Guild, Local + byte level; // 2^2 Normal, info (grey), important (yellow), critical (red) + + uint16 length; // 2^9 + char* message; // Max Length: MAX_MESSAGE_LENGTH +}; + +#endif \ No newline at end of file diff --git a/network/packet/mob/MobInfoPacket.h b/network/packet/mob/MobInfoPacket.h new file mode 100644 index 0000000..cd4a8ba --- /dev/null +++ b/network/packet/mob/MobInfoPacket.h @@ -0,0 +1,39 @@ +#ifndef TOS_NETWORK_PACKET_MOB_INFO_H +#define TOS_NETWORK_PACKET_MOB_INFO_H + +#include + +#include "../../../stdlib/Types.h" + +struct MobInfoPacketSnapshot { + byte* data; +}; + +struct MobInfoPacketSnapshotUnpacked { + uint32 mob_id; + byte mob_type; + uint32 chunk; + + byte level; // 2^7 + byte health; // 2^7 + byte resource; // 2^7 + byte xp; + + // Data layout + // 12223444 + // 1: scale sign + // 2: scale factor (8) + // 3: weight sign + // 4: weight factor (8) + byte custom_size; + + // Data layout + // 1122222? + // 1: body type (4) + // 2: skin color (32) + byte custom_body; + + uint64 time; +}; + +#endif \ No newline at end of file diff --git a/network/packet/mob/MobStatePacket.h b/network/packet/mob/MobStatePacket.h new file mode 100644 index 0000000..f440b57 --- /dev/null +++ b/network/packet/mob/MobStatePacket.h @@ -0,0 +1,52 @@ +#ifndef TOS_NETWORK_PACKET_MOB_STATE_H +#define TOS_NETWORK_PACKET_MOB_STATE_H + +#include + +#include "../../../stdlib/Types.h" + +struct MobStatePacketSnapshot { + byte* data; +}; + +struct MobStatePacketSnapshotUnpacked { + uint32 mob_id; + byte mob_type; + uint32 chunk; + + f16 x; + f16 y; + f16 z; + + f16 roll; + f16 pitch; + f16 yaw; + + uint32 state_flag; + + uint64 time; +}; + +struct MobStatePacketDelta { + byte* data; +}; + +struct MobStatePacketDeltaUnpacked { + uint32 mob_id; + byte mob_type; + uint32 chunk; + + f16 x; + f16 y; + f16 z; + + f16 roll; + f16 pitch; + f16 yaw; + + uint32 state_flag; + + uint64 time; +}; + +#endif \ No newline at end of file diff --git a/network/packet/mob/player/PlayerInfoPacket.h b/network/packet/mob/player/PlayerInfoPacket.h new file mode 100644 index 0000000..e9f60e6 --- /dev/null +++ b/network/packet/mob/player/PlayerInfoPacket.h @@ -0,0 +1,85 @@ +#ifndef TOS_NETWORK_PACKET_MOB_PLAYER_INFO_H +#define TOS_NETWORK_PACKET_MOB_PLAYER_INFO_H + +#include + +#include "../../../../stdlib/Types.h" +#include "../../../../config.h" + +struct PlayerInfoPacketSnapshot { + byte* data; +}; + +// 32+32+256+128+8+8+7+7+7+7+56+406+448+64=184bytes +struct PlayerInfoPacketSnapshotUnpacked { + uint32 mob_id; + uint32 chunk; + byte name[MAX_CHAR_NAME_LENGTH]; + byte title[MAX_CHAR_TITLE_LENGTH]; + byte xp; + + // Data layout + // 12223444 + // 1: scale sign + // 2: scale factor (8) + // 3: weight sign + // 4: weight factor (8) + byte scale; + byte weight; + + byte level; // 2^7 + byte health; // 2^7 + byte resource; // 2^7 + + // Data layout 2^7 + // 1122222? + // 1: body type (4) + // 2: skin color (32) + byte body_type; + byte body_color; + + // Data layout + // 1-4 race (16) + // + // 5-9 face type (32) + // + // 10-15 hair style (64) + // 16-20 hair color (32) + // + // 21-26 beard style (32) + // + // 27-30 eye style (32) + // 31-35 eye color (32) + // + // 36-40 face scar (32) + // 41-45 body scar (32) + // + // 46-51 tattoo (64) + // 52-56 tattoo color (32) + byte race; + byte face_type; + byte hair_style; + byte hair_color; + byte beard_style; + byte eye_style; + byte eye_color; + byte face_scar; + byte body_scar; + byte tattoo; + byte tattoo_color; + + // Equipment transmog data + // 11111222223333344444444455555??? + // 1: primary color (32) + // 2: secondary color (32) + // 3: tertiary color (32) + // 4: effect (512) + // 5: effect color (32) + // ?: FREE + uint32 equipmentTransmog[14]; + uint32 equipment[14]; + + uint64 time; +}; + +#endif \ No newline at end of file diff --git a/network/packet/mob/player/PlayerState.h b/network/packet/mob/player/PlayerState.h new file mode 100644 index 0000000..408c56a --- /dev/null +++ b/network/packet/mob/player/PlayerState.h @@ -0,0 +1,12 @@ +#ifndef TOS_NETWORK_PACKAGE_PLAYER_STATE_H +#define TOS_NETWORK_PACKAGE_PLAYER_STATE_H + +#include "../../../stdlib/Types.h" + +struct SPlayerState { +}; + +struct CPlayerState { +}; + +#endif \ No newline at end of file diff --git a/network/packet/packet_types.h b/network/packet/packet_types.h new file mode 100644 index 0000000..67be333 --- /dev/null +++ b/network/packet/packet_types.h @@ -0,0 +1,88 @@ +#ifndef TOS_NETWORK_PACKET_TYPES_H +#define TOS_NETWORK_PACKET_TYPES_H + +#define PACKET_TYPE_AUTH 0 +#define SUB_PACKET_TYPE_AUTH_LOGIN 0 +#define SUB_PACKET_TYPE_AUTH_LOADIN 1 +#define SUB_PACKET_TYPE_AUTH_LOADOUT 2 +#define SUB_PACKET_TYPE_AUTH_LOGOUT 3 + +#define PACKET_TYPE_MOB_STATE_SNAPSHOT 1 +#define PACKET_TYPE_MOB_STATE_DELTA 2 +#define PACKET_TYPE_MOB_STATE_POSITION_SNAPSHOT 3 +#define PACKET_TYPE_MOB_STATE_POSITION_DELTA 4 +#define PACKET_TYPE_MOB_STATE_ACTION_SNAPSHOT 5 +#define PACKET_TYPE_MOB_STATE_ACTION_DELTA 6 + +#define PACKET_TYPE_MOB_LOOKS 7 + +#define PACKET_TYPE_CHAT_MSG 8 +#define PACKET_TYPE_CHAT_ACTION 9 +#define SUB_PACKET_TYPE_CHAT_FRIENDS_LOAD 1 +#define SUB_PACKET_TYPE_CHAT_FRIENDS_ADD 2 +#define SUB_PACKET_TYPE_CHAT_FRIENDS_REMOVE 3 +#define SUB_PACKET_TYPE_CHAT_BLOCKED_LOAD 4 +#define SUB_PACKET_TYPE_CHAT_BLOCKED_ADD 5 +#define SUB_PACKET_TYPE_CHAT_BLOCKED_REMOVE 6 +#define SUB_PACKET_TYPE_CHAT_FIND 7 // no data = list all + +#define PACKET_TYPE_GUILD 10 +#define SUB_PACKET_TYPE_GUILD_INVITE 0 +#define SUB_PACKET_TYPE_GUILD_REQUEST 1 +#define SUB_PACKET_TYPE_GUILD_JOIN 2 +#define SUB_PACKET_TYPE_GUILD_LEAVE 3 +#define SUB_PACKET_TYPE_GUILD_KICK 4 +#define SUB_PACKET_TYPE_GUILD_FIND 5 // no data = list all +#define SUB_PACKET_TYPE_GUILD_LOAD_PUBLIC 6 +#define SUB_PACKET_TYPE_GUILD_LOAD_PRIVATE 7 +#define SUB_PACKET_TYPE_GUILD_LOAD_MEMBERS 8 +#define SUB_PACKET_TYPE_GUILD_ACTION_CREATE 9 +#define SUB_PACKET_TYPE_GUILD_ACTION_DELETE 10 +#define SUB_PACKET_TYPE_GUILD_ACTION_PERMISSION 11 // Change permission of member +#define SUB_PACKET_TYPE_GUILD_ACTION_RENAME 12 +#define SUB_PACKET_TYPE_GUILD_ACTION_DESCRIPTION 13 +#define SUB_PACKET_TYPE_GUILD_ACTION_DESIGN 14 +#define SUB_PACKET_TYPE_GUILD_ACTION_BANNER 15 +// @todo guild hall actions (buy/sell/add furniture/...) + +#define PACKET_TYPE_SHOP 11 +#define SUB_PACKET_TYPE_SHOP_FIND 0 +#define SUB_PACKET_TYPE_SHOP_SELL 1 +#define SUB_PACKET_TYPE_SHOP_BUY 2 +#define SUB_PACKET_TYPE_SHOP_BID 3 +#define SUB_PACKET_TYPE_SHOP_CANCEL 4 + +#define PACKET_TYPE_SHOP 12 +#define SUB_PACKET_TYPE_SHOP_FIND 0 +#define SUB_PACKET_TYPE_SHOP_SELL 1 +#define SUB_PACKET_TYPE_SHOP_BUY 2 +#define SUB_PACKET_TYPE_SHOP_BID 3 +#define SUB_PACKET_TYPE_SHOP_CANCEL 4 + +#define PACKET_TYPE_GROUP 13 +#define SUB_PACKET_TYPE_GROUP_INVITE 0 +#define SUB_PACKET_TYPE_GROUP_JOIN 1 +#define SUB_PACKET_TYPE_GROUP_LEAVE 2 +#define SUB_PACKET_TYPE_GROUP_KICK 3 +#define SUB_PACKET_TYPE_GROUP_FIND 4 + +#define PACKET_TYPE_INTERACT 14 + +#define PACKET_TYPE_MOB_ITEM 15 +#define SUB_PACKET_TYPE_MOB_ITEM_PICKUP 0 +#define SUB_PACKET_TYPE_MOB_ITEM_USE 1 +#define SUB_PACKET_TYPE_MOB_ITEM_EQUIP 2 +#define SUB_PACKET_TYPE_MOB_ITEM_DROP 3 +#define SUB_PACKET_TYPE_MOB_ITEM_MOVE 4 + +#define PACKET_TYPE_GM_ACTION 16 +#define SUB_PACKET_TYPE_GM_ACTION_MOVE 0 // moves any type of mob to any location +#define SUB_PACKET_TYPE_GM_ACTION_KILL 1 +#define SUB_PACKET_TYPE_GM_ACTION_SPAWN 2 +#define SUB_PACKET_TYPE_GM_ACTION_KICK 3 +#define SUB_PACKET_TYPE_GM_ACTION_BAN 4 +#define SUB_PACKET_TYPE_GM_ACTION_CHAT_REMOVE 5 +#define SUB_PACKET_TYPE_GM_ACTION_AWARD_QUEST 6 +#define SUB_PACKET_TYPE_GM_ACTION_RESET_QUEST 7 + +#endif \ No newline at end of file diff --git a/platform/linux/UtilsLinux.h b/platform/linux/UtilsLinux.h new file mode 100644 index 0000000..7468309 --- /dev/null +++ b/platform/linux/UtilsLinux.h @@ -0,0 +1,54 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_UTILS_LINUX_H +#define TOS_UTILS_LINUX_H + +#include +#include +#include +#include +#include + +#include "../../stdlib/Types.h" +#include "../../utils/Utils.h" +#include "../../utils/TestUtils.h" + +inline uint64 last_modification(const char* filename) +{ + struct stat buffer; + stat(filename, &buffer); + + return (uint64) buffer.st_mtime.tv_sec; +} + +inline void +file_read(const char* filename, file_body* file) +{ + FILE *fp = fopen(filename, "rb"); + fseek(fp, 0, SEEK_END); + + file->size = ftell(fp); + rewind(fp); + + fread(file->content, 1, file->size, fp); + + fclose(fp); +} + +inline +void strncpy_s(char *dest, size_t destsz, const char *src, size_t count) { + size_t i; + + for (i = 0; i < count && i < destsz - 1 && src[i] != '\0'; ++i) { + dest[i] = src[i]; + } + + dest[i] = '\0'; +} +#endif \ No newline at end of file diff --git a/platform/win32/UtilsWin32.h b/platform/win32/UtilsWin32.h new file mode 100644 index 0000000..0558395 --- /dev/null +++ b/platform/win32/UtilsWin32.h @@ -0,0 +1,369 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_UTILS_WIN32_H +#define TOS_UTILS_WIN32_H + +#include +#ifdef _MSC_VER + #include +#endif + +#include "../../stdlib/Types.h" +#include "../../utils/Utils.h" +#include "../../utils/TestUtils.h" + +#define strtok_r strtok_s + +inline uint64 +file_size(const char* filename) +{ + HANDLE fp = CreateFileA((LPCSTR) filename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (fp == INVALID_HANDLE_VALUE) { + return 0; + } + + LARGE_INTEGER size; + if (!GetFileSizeEx(fp, &size)) { + CloseHandle(fp); + } + + CloseHandle(fp); + + return size.QuadPart; +} + +inline void +file_read(const char* filename, file_body* file) +{ + HANDLE fp = CreateFileA((LPCSTR) filename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (fp == INVALID_HANDLE_VALUE) { + file->size = 0; + return; + } + + LARGE_INTEGER size; + if (!GetFileSizeEx(fp, &size)) { + CloseHandle(fp); + file->content = NULL; + + return; + } + + DWORD bytes; + ASSERT_SIMPLE(size.QuadPart < MAX_INT32); + if (!ReadFile(fp, file->content, (uint32) size.QuadPart, &bytes, NULL)) { + CloseHandle(fp); + file->content = NULL; + + return; + } + + CloseHandle(fp); + + file->content[bytes] = '\0'; + file->size = size.QuadPart; +} + +inline uint64 +file_read_struct(const char* filename, void* file, uint32 size) +{ + HANDLE fp = CreateFileA((LPCSTR) filename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (fp == INVALID_HANDLE_VALUE) { + return 0; + } + + LARGE_INTEGER fsize; + if (!GetFileSizeEx(fp, &fsize)) { + CloseHandle(fp); + + return 0; + } + + DWORD read; + ASSERT_SIMPLE(fsize.QuadPart > size); + if (!ReadFile(fp, file, (uint32) size, &read, NULL)) { + CloseHandle(fp); + + return 0; + } + + CloseHandle(fp); + + return read; +} + +inline bool +file_write(const char* filename, const file_body* file) +{ + HANDLE fp = CreateFileA((LPCSTR) filename, + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (fp == INVALID_HANDLE_VALUE) { + return false; + } + + DWORD written; + DWORD length = (DWORD) file->size; + ASSERT_SIMPLE(file->size < MAX_INT32); + if (!WriteFile(fp, file->content, length, &written, NULL)) { + CloseHandle(fp); + return false; + } + + CloseHandle(fp); + + return true; +} + +inline bool +file_write_struct(const char* filename, const void* file, uint32 size) +{ + HANDLE fp = CreateFileA((LPCSTR) filename, + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (fp == INVALID_HANDLE_VALUE) { + return false; + } + + DWORD written; + ASSERT_SIMPLE(size < MAX_INT32); + if (!WriteFile(fp, file, size, &written, NULL)) { + CloseHandle(fp); + return false; + } + + CloseHandle(fp); + + return true; +} + +inline void +file_copy(const char* src, const char* dst) +{ + CopyFileA((LPCSTR) src, (LPCSTR) dst, false); +} + +inline +HANDLE get_append_handle(const char* filename) +{ + HANDLE fp = CreateFileA((LPCSTR) filename, + FILE_APPEND_DATA, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (fp == INVALID_HANDLE_VALUE) { + return NULL; + } + + return fp; +} + +inline bool +file_append(const char* filename, const char* file) +{ + HANDLE fp = CreateFileA((LPCSTR) filename, + FILE_APPEND_DATA, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (fp == INVALID_HANDLE_VALUE) { + return false; + } + + DWORD written; + DWORD length = (DWORD) strlen(file); // @question WHY is WriteFile not supporting larger data? + ASSERT_SIMPLE(length < MAX_INT32); + if (!WriteFile(fp, file, length, &written, NULL)) { + CloseHandle(fp); + return false; + } + + CloseHandle(fp); + return true; +} + +inline bool +file_append(HANDLE fp, const char* file) +{ + if (fp == INVALID_HANDLE_VALUE) { + return false; + } + + DWORD written; + DWORD length = (DWORD) strlen(file); // @question WHY is WriteFile not supporting larger data? + ASSERT_SIMPLE(length < MAX_INT32); + if (!WriteFile(fp, file, length, &written, NULL)) { + CloseHandle(fp); + return false; + } + + CloseHandle(fp); + return true; +} + +inline bool +file_append(const char* filename, const file_body* file) +{ + HANDLE fp = CreateFileA((LPCSTR) filename, + FILE_APPEND_DATA, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (fp == INVALID_HANDLE_VALUE) { + return false; + } + + DWORD bytes; + DWORD length = (DWORD) file->size; + ASSERT_SIMPLE(file->size < MAX_INT32); + if (!WriteFile(fp, file->content, length, &bytes, NULL)) { + CloseHandle(fp); + return false; + } + + CloseHandle(fp); + return true; +} + +inline uint64 last_modified(const char* filename) +{ + FILETIME modified = {}; + + WIN32_FIND_DATA find_data; + HANDLE fp = FindFirstFileA(filename, (LPWIN32_FIND_DATAA) &find_data); + if(fp != INVALID_HANDLE_VALUE) { + modified = find_data.ftLastWriteTime; + FindClose(fp); + } + + ULARGE_INTEGER ull; + ull.LowPart = modified.dwLowDateTime; + ull.HighPart = modified.dwHighDateTime; + + return ull.QuadPart; +} + +inline void self_path(char* path) +{ + //HMODULE dll = GetModuleHandle(NULL); + GetModuleFileNameA(NULL, (LPSTR) path, MAX_PATH); +} + +void log_to_file(LogPool* logs, HANDLE fp) +{ + // we don't log an empty log pool + if (logs->pos == 0) { + return; + } + + char *offset = logs->memory; + for (uint32 i = 0; i < logs->pos * MAX_LOG_LENGTH + MAX_LOG_LENGTH; ++i) { + if (*offset == '\0') { + *offset = '\n'; + + // @performance would it make sense to jump to the next log message + // we know that after \0 until the end of this log message everything is 0 + } + + ++offset; + } + + logs->memory[logs->count * MAX_LOG_LENGTH - 1] = '\0'; + file_append(fp, logs->memory); + + // reset log position to start of memory pool + logs->pos = 0; +} + +// snprintf(logs->memory + logs->pos * MAX_LOG_LENGTH, MAX_LOG_LENGTH, "My text %s", str1); +// log(log, NULL); +void log(LogPool* logs, HANDLE fp = NULL) +{ + // Zero memory after \0 until end of THIS log message + // Older log messages that are coming after are retained + // Older log messages can come after this log message due to the ring memory + char *offset = logs->memory + logs->pos * MAX_LOG_LENGTH; + bool ended = false; + for (uint32 i = 0; i < MAX_LOG_LENGTH; ++i) { + if (ended) { + *offset = 0; + ++offset; + + continue; + } + + if (*offset == '\0') { + ended = true; + } + + ++offset; + } + + ++logs->pos; + // write log pool to file + if (logs->pos >= logs->count) { + if (fp != NULL) { + log_to_file(logs, fp); + } + + // reset log position to start of memory pool + logs->pos = 0; + } +} + +#if (LOG_LEVEL == 0) + // Don't perform any logging at log level 0 + #define LOG(logs, fp) + #define LOG_TO_FILE(logs, fp) +#else + #define LOG(logs, fp) log(logs, fp); + #define LOG_TO_FILE(logs, fp) log_to_file(logs, fp); +#endif + +#endif \ No newline at end of file diff --git a/platform/win32/UtilsWindows.h b/platform/win32/UtilsWindows.h new file mode 100644 index 0000000..39fb7ff --- /dev/null +++ b/platform/win32/UtilsWindows.h @@ -0,0 +1,86 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_UTILS_WINDOWS_H +#define TOS_UTILS_WINDOWS_H + +#include +#include "../../stdlib/Types.h" + +struct Window { + bool is_fullscreen; + int32 width; + int32 height; + char name[32]; + + int32 x; + int32 y; + + HWND hwnd; +}; + +void window_create(Window* window, void* proc) +{ + WNDPROC wndproc = (WNDPROC) proc; + WNDCLASSEX wc = {}; + HINSTANCE hinstance = GetModuleHandle(0); + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_OWNDC; + wc.lpfnWndProc = wndproc; + wc.hInstance = hinstance; + wc.lpszClassName = (LPCWSTR) window->name; + + RegisterClassEx(&wc); + + if (window->is_fullscreen) { + window->width = GetSystemMetrics(SM_CXSCREEN); + window->height = GetSystemMetrics(SM_CYSCREEN); + + DEVMODE screen_settings; + + memset(&screen_settings, 0, sizeof(screen_settings)); + screen_settings.dmSize = sizeof(screen_settings); + screen_settings.dmPelsWidth = (unsigned long) window->width; + screen_settings.dmPelsHeight = (unsigned long) window->height; + screen_settings.dmBitsPerPel = 32; + screen_settings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + + ChangeDisplaySettings(&screen_settings, CDS_FULLSCREEN); + + window->x = 0; + window->y = 0; + } + + window->hwnd = CreateWindowEx((DWORD) NULL, + wc.lpszClassName, NULL, + WS_OVERLAPPEDWINDOW, + window->x, window->y, + window->width, + window->height, + NULL, NULL, hinstance, window + ); + + //SetWindowLongA(window->hwnd, GWL_STYLE, 0); +} + +void window_open(const Window* window) +{ + ShowWindow(window->hwnd, SW_SHOW); + SetForegroundWindow(window->hwnd); + SetFocus(window->hwnd); + ShowCursor(false); + UpdateWindow(window->hwnd); +} + +void window_close(Window* window) +{ + CloseWindow(window->hwnd); +} + +#endif \ No newline at end of file diff --git a/platform/win32/audio/DirectSound.h b/platform/win32/audio/DirectSound.h new file mode 100644 index 0000000..6260f5a --- /dev/null +++ b/platform/win32/audio/DirectSound.h @@ -0,0 +1,202 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_SOUND_DIRECT_SOUND_H +#define TOS_SOUND_DIRECT_SOUND_H + +#include +#include + +#include "../../../stdlib/Types.h" +#include "../../../audio/AudioSetting.h" +#include "../../../utils/MathUtils.h" + +struct DirectSoundSetting { + LPDIRECTSOUND8 direct_sound; + LPDIRECTSOUNDBUFFER primary_buffer; + LPDIRECTSOUNDBUFFER secondary_buffer; +}; + +// BEGIN: Dynamically load DirectSound +typedef HRESULT WINAPI audio_create(LPCGUID, LPDIRECTSOUND8*, LPUNKNOWN); +HRESULT WINAPI DirectSoundCreate8Stub(LPCGUID, LPDIRECTSOUND8*, LPUNKNOWN) { + return 0; +} +// END: Dynamically load DirectSound + +void audio_load(HWND hwnd, AudioSetting* setting, DirectSoundSetting* api_setting) { + HMODULE lib = LoadLibraryExA((LPCSTR) "dsound.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (!lib) { + // @todo Log + return; + } + + audio_create* DirectSoundCreate8 = (audio_create *) GetProcAddress(lib, "DirectSoundCreate8"); + + if (!DirectSoundCreate8 || !SUCCEEDED(DirectSoundCreate8(0, &api_setting->direct_sound, 0))) { + // @todo Log + return; + } + + if(!SUCCEEDED(api_setting->direct_sound->SetCooperativeLevel(hwnd, DSSCL_PRIORITY))) { + // @todo Log + + return; + } + + WAVEFORMATEX wf = {}; + wf.wFormatTag = WAVE_FORMAT_PCM; + wf.nChannels = 2; + wf.wBitsPerSample = 16; + wf.nBlockAlign = (wf.nChannels * wf.wBitsPerSample) / 8; + wf.nSamplesPerSec = setting->sample_rate; + wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign; + wf.cbSize = 0; + + // Create primary buffer + DSBUFFERDESC bufferDesc; + ZeroMemory(&bufferDesc, sizeof(DSBUFFERDESC)); + + bufferDesc.dwSize = sizeof(DSBUFFERDESC); + bufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER; + + if(!SUCCEEDED(api_setting->direct_sound->CreateSoundBuffer(&bufferDesc, &api_setting->primary_buffer, 0))) { + // @todo Log + + return; + } + + if (!SUCCEEDED(api_setting->primary_buffer->SetFormat(&wf))) { + // @todo Log + + return; + } + + setting->buffer_size = setting->sample_rate * setting->sample_size; + setting->buffer = (int16 *) calloc(setting->sample_rate, setting->sample_size); + + // Create secondary buffer + DSBUFFERDESC bufferDesc2; + ZeroMemory(&bufferDesc2, sizeof(DSBUFFERDESC)); + + bufferDesc2.dwSize = sizeof(DSBUFFERDESC); + bufferDesc2.dwFlags = 0; + bufferDesc2.dwBufferBytes = setting->buffer_size; + bufferDesc2.lpwfxFormat = &wf; + + if(!SUCCEEDED(api_setting->direct_sound->CreateSoundBuffer(&bufferDesc2, &api_setting->secondary_buffer, 0))) { + // @todo Log + + return; + } +} + +inline +void audio_play(AudioSetting* setting, DirectSoundSetting* api_setting) +{ + if (!api_setting->secondary_buffer) { + return; + } + + api_setting->secondary_buffer->Play(0, 0, DSBPLAY_LOOPING); + setting->is_playing = true; +} + +inline +void audio_free(AudioSetting* setting, DirectSoundSetting* api_setting) +{ + if (api_setting->direct_sound) { + api_setting->direct_sound->Release(); + } + + if (api_setting->primary_buffer) { + api_setting->primary_buffer->Release(); + } + + if (api_setting->secondary_buffer) { + api_setting->secondary_buffer->Release(); + } +} + +/** + * Calculates the samples in bytes to generate for the buffer + */ +inline +uint32 audio_buffer_fillable(const AudioSetting* setting, const DirectSoundSetting* api_setting) +{ + DWORD player_cursor; + DWORD write_cursor; + if (!SUCCEEDED(api_setting->secondary_buffer->GetCurrentPosition(&player_cursor, &write_cursor))) { + // @todo Log + return 0; + } + + DWORD bytes_to_lock = (setting->sample_index * setting->sample_size) % setting->buffer_size; + DWORD bytes_to_write = 0; + + DWORD target_cursor = (player_cursor + (setting->latency * setting->sample_size)) % setting->buffer_size; + + if (bytes_to_lock == player_cursor) { + bytes_to_write = setting->is_playing ? 0 : setting->buffer_size; + } else if (bytes_to_lock > target_cursor) { + bytes_to_write = setting->buffer_size - bytes_to_lock; + bytes_to_write += target_cursor; + } else { + bytes_to_write = target_cursor - bytes_to_lock; + } + + return bytes_to_write; +} + +inline +void audio_play_buffer(AudioSetting* setting, DirectSoundSetting* api_setting, uint32 bytes_to_write) +{ + if (bytes_to_write == 0) { + return; + } + + void *region1; + DWORD region1_size; + + void *region2; + DWORD region2_size; + + DWORD bytes_to_lock = (setting->sample_index * setting->sample_size) % setting->buffer_size; + + api_setting->secondary_buffer->Lock( + bytes_to_lock, bytes_to_write, + ®ion1, ®ion1_size, + ®ion2, ®ion2_size, + 0 + ); + + // @question Do we even need to use memcpy? Can't we use the buffer directly? + // Probably depends on what lock actually does to region1/region2 + // Of course we would than need some mechanism to check when we can write into the buffer + // See XAudio2 for this, we would probably need a second buffer as well + memcpy( + (void *) region1, + (void *) setting->buffer, + region1_size + ); + + if (region2_size > 0) { + memcpy( + (void *) region2, + (void *) (setting->buffer + region1_size), + region2_size + ); + } + + api_setting->secondary_buffer->Unlock(region1, region1_size, region2, region2_size); + + setting->sample_index += bytes_to_write / setting->sample_size; + setting->sample_buffer_size = 0; +} + +#endif \ No newline at end of file diff --git a/platform/win32/audio/XAudio2.h b/platform/win32/audio/XAudio2.h new file mode 100644 index 0000000..c43717f --- /dev/null +++ b/platform/win32/audio/XAudio2.h @@ -0,0 +1,196 @@ +/** + * Jingga + * + * @package Stdlib + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_SOUND_XAUDIO2_H +#define TOS_SOUND_XAUDIO2_H + +#include +#include + +#include "../../../stdlib/Types.h" +#include "../../../audio/AudioSetting.h" +#include "../../../utils/MathUtils.h" + +struct XAudio2Setting { + IXAudio2* xaudio2; + IXAudio2SourceVoice* source_voice; + IXAudio2MasteringVoice* mastering_voice; + + XAUDIO2_BUFFER internal_buffer[2]; +}; + +// BEGIN: Dynamically load XAudio2 +typedef HRESULT WINAPI audio_create(IXAudio2**, UINT32, XAUDIO2_PROCESSOR); +HRESULT WINAPI XAudio2CreateStub(IXAudio2**, UINT32, XAUDIO2_PROCESSOR) { + return 0; +} +// END: Dynamically load XAudio2 + +void audio_load(HWND hwnd, AudioSetting* setting, XAudio2Setting* api_setting) { + HMODULE lib = LoadLibraryExA((LPCSTR) "xaudio2_9.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (!lib) { + // @todo Log + lib = LoadLibraryExA((LPCSTR) "xaudio2_8.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + } + + if (!lib) { + // @todo Log + return; + } + + audio_create* XAudio2Create = (audio_create *) GetProcAddress(lib, "XAudio2Create"); + if (!XAudio2Create || !SUCCEEDED(XAudio2Create(&api_setting->xaudio2, 0, XAUDIO2_DEFAULT_PROCESSOR))) { + // @todo Log + return; + } + + if (!SUCCEEDED(api_setting->xaudio2->CreateMasteringVoice( + &api_setting->mastering_voice, + XAUDIO2_DEFAULT_CHANNELS, + setting->sample_rate, + 0, + NULL + ))) { + // @todo Log + return; + } + + WAVEFORMATEX wf = {}; + wf.wFormatTag = WAVE_FORMAT_PCM; + wf.nChannels = 2; + wf.wBitsPerSample = (uint16) ((setting->sample_size * 8) / wf.nChannels); // = sample_size per channel + wf.nBlockAlign = (wf.nChannels * wf.wBitsPerSample) / 8; // = sample_szie + wf.nSamplesPerSec = setting->sample_rate; + wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign; // = buffer_size + wf.cbSize = 0; + + if (!SUCCEEDED(api_setting->xaudio2->CreateSourceVoice(&api_setting->source_voice, &wf))) { + // @todo Log + return; + } + + setting->buffer_size = setting->sample_rate * setting->sample_size; + setting->buffer = (int16 *) calloc(setting->sample_rate, setting->sample_size); + + // @question Consider to move to the heap? + api_setting->internal_buffer[0].Flags = 0; + api_setting->internal_buffer[0].AudioBytes = setting->buffer_size; + api_setting->internal_buffer[0].pAudioData = (byte *) malloc(setting->buffer_size * sizeof(byte)); + api_setting->internal_buffer[0].PlayBegin = 0; + api_setting->internal_buffer[0].PlayLength = 0; + api_setting->internal_buffer[0].LoopBegin = 0; + api_setting->internal_buffer[0].LoopLength = 0; + api_setting->internal_buffer[0].LoopCount = 0; + api_setting->internal_buffer[0].pContext = NULL; + + api_setting->internal_buffer[1].Flags = 0; + api_setting->internal_buffer[1].AudioBytes = setting->buffer_size; + api_setting->internal_buffer[1].pAudioData = (byte *) malloc(setting->buffer_size * sizeof(byte)); + api_setting->internal_buffer[1].PlayBegin = 0; + api_setting->internal_buffer[1].PlayLength = 0; + api_setting->internal_buffer[1].LoopBegin = 0; + api_setting->internal_buffer[1].LoopLength = 0; + api_setting->internal_buffer[1].LoopCount = 0; + api_setting->internal_buffer[1].pContext = NULL; + + setting->sample_index = 0; +} + +inline +void audio_play(AudioSetting* setting, XAudio2Setting* api_setting) { + if (!api_setting->source_voice) { + // @todo Log + + return; + } + + api_setting->source_voice->Start(0, XAUDIO2_COMMIT_NOW); + setting->is_playing = true; +} + +inline +void audio_free(AudioSetting* setting, XAudio2Setting* api_setting) +{ + if (api_setting->internal_buffer[0].pAudioData) { + free((void *) api_setting->internal_buffer[0].pAudioData); + } + + if (api_setting->internal_buffer[1].pAudioData) { + free((void *) api_setting->internal_buffer[1].pAudioData); + } + + if (setting->buffer) { + free((void *) setting->buffer); + } + + if (api_setting->source_voice) { + api_setting->source_voice->DestroyVoice(); + } + + if (api_setting->mastering_voice) { + api_setting->mastering_voice->DestroyVoice(); + } + + if (api_setting->xaudio2) { + api_setting->xaudio2->Release(); + } +} + +/** + * Calculates the samples to generate for the buffer + * + * For XAudio2 we currently always fill the entire buffer size. + * For other audio APIs we maybe have to do something else + */ +inline +uint32 audio_buffer_fillable(const AudioSetting* setting, const XAudio2Setting* api_setting) +{ + if (!api_setting->source_voice) { + // @todo Log + + return 0; + } + + XAUDIO2_VOICE_STATE state; + api_setting->source_voice->GetState(&state); + if (state.BuffersQueued > 1) { + return 0; + } + + return setting->buffer_size; +} + +inline +void audio_play_buffer(AudioSetting* setting, XAudio2Setting* api_setting, uint32 bytes_to_write) { + if (!api_setting->source_voice) { + // @todo Log + + return; + } + + if (bytes_to_write == 0) { + return; + } + + memcpy( + (void *) api_setting->internal_buffer[setting->sample_index].pAudioData, + setting->buffer, + bytes_to_write + ); + + if (!SUCCEEDED(api_setting->source_voice->SubmitSourceBuffer(&api_setting->internal_buffer[setting->sample_index]))) { + // @todo Log + return; + } + + setting->sample_index = (setting->sample_index + 1) % 2; + setting->sample_buffer_size = 0; +} + +#endif diff --git a/platform/win32/input/RawInput.h b/platform/win32/input/RawInput.h new file mode 100644 index 0000000..cb0e123 --- /dev/null +++ b/platform/win32/input/RawInput.h @@ -0,0 +1,188 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_INPUT_RAW_H +#define TOS_INPUT_RAW_H + +#include + +#include "../../../stdlib/Types.h" +#include "../../../input/Input.h" +#include "../../../utils/TestUtils.h" +#include "../../../utils/MathUtils.h" + +InputState* init_input(HWND hwnd) +{ + uint32 nDevices; + GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)); + PRAWINPUTDEVICELIST pRawInputDeviceList = (PRAWINPUTDEVICELIST) malloc(sizeof(RAWINPUTDEVICELIST) * nDevices); + nDevices = GetRawInputDeviceList(pRawInputDeviceList, &nDevices, sizeof(RAWINPUTDEVICELIST)); + + // We always want at least one empty input device slot + // @todo Change so that we store the actual number of devices + InputState *inputs = (InputState *) calloc((nDevices + 1), sizeof(InputState)); + + if (nDevices == 0) { + free(pRawInputDeviceList); + + return inputs; + } + + uint32 cb_size = 256; + + for (uint32 i = 0; i < nDevices; ++i) { + GetRawInputDeviceInfoA(pRawInputDeviceList[i].hDevice, RIDI_DEVICENAME, inputs[i].name, &cb_size); + + cb_size = sizeof(RID_DEVICE_INFO); + RID_DEVICE_INFO rdi; + GetRawInputDeviceInfoA(pRawInputDeviceList[i].hDevice, RIDI_DEVICEINFO, &rdi, &cb_size); + + switch (rdi.dwType) { + case RIM_TYPEMOUSE: { + inputs[i].handle_mouse = pRawInputDeviceList[i].hDevice; + inputs[i].is_connected = true; + inputs[i].type = INPUT_TYPE_MOUSE; + } break; + case RIM_TYPEKEYBOARD: { + inputs[i].handle_keyboard = pRawInputDeviceList[i].hDevice; + inputs[i].is_connected = true; + inputs[i].type = INPUT_TYPE_KEYBOARD; + } break; + case RIM_TYPEHID: { + inputs[i].type = INPUT_TYPE_OTHER; + } break; + default: { + + } + } + } + + RAWINPUTDEVICE rid[4]; + + // Mouse + rid[0].usUsagePage = 0x01; // @todo doesn't work with 0x05 for games? + rid[0].usUsage = 0x02; + rid[0].dwFlags = RIDEV_DEVNOTIFY; + rid[0].hwndTarget = hwnd; + + // Joystick + rid[1].usUsagePage = 0x01; // @todo doesn't work with 0x05 for games? + rid[1].usUsage = 0x04; + rid[1].dwFlags = RIDEV_DEVNOTIFY; + rid[1].hwndTarget = hwnd; + + // Gamepad + rid[2].usUsagePage = 0x01; // @todo doesn't work with 0x05 for games? + rid[2].usUsage = 0x05; + rid[2].dwFlags = RIDEV_DEVNOTIFY; + rid[2].hwndTarget = hwnd; + + // Keyboard + rid[3].usUsagePage = 0x01; // @todo doesn't work with 0x05 for games? + rid[3].usUsage = 0x06; + rid[3].dwFlags = RIDEV_DEVNOTIFY; + rid[3].hwndTarget = hwnd; + + if (!RegisterRawInputDevices((PCRAWINPUTDEVICE) rid, 4, sizeof(RAWINPUTDEVICE))) { + // @todo Log + } + + // free(rid); + free(pRawInputDeviceList); + + return inputs; +} + +void handle_input(LPARAM lParam, InputState* states) +{ + uint32 db_size; + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &db_size, sizeof(RAWINPUTHEADER)); + + // @todo pull out, we only need to register this memory once + // Maybe even put it into the general memory pool + LPBYTE lpb = (BYTE *) malloc(db_size * sizeof(BYTE)); + + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &db_size, sizeof(RAWINPUTHEADER)); + + RAWINPUT* raw = (RAWINPUT*) lpb; + + uint32 i = 0; + if (raw->header.dwType == RIM_TYPEMOUSE) { + // @todo Change so we can directly access the correct state (maybe map handle address to index?) + while (states[i].is_connected && states[i].handle_mouse != raw->header.hDevice) {++i;} + + if (!states[i].is_connected) { + return; + } + + // https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-rawmouse + if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) { + RECT rect; + if (raw->data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) { + rect.left = GetSystemMetrics(SM_XVIRTUALSCREEN); + rect.top = GetSystemMetrics(SM_YVIRTUALSCREEN); + rect.right = GetSystemMetrics(SM_CXVIRTUALSCREEN); + rect.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN); + } else { + rect.left = 0; + rect.top = 0; + rect.right = GetSystemMetrics(SM_CXSCREEN); + rect.bottom = GetSystemMetrics(SM_CYSCREEN); + } + + states[i].x_last = states[i].x; + states[i].y_last = states[i].y; + + states[i].x = MulDiv(raw->data.mouse.lLastX, rect.right, 65535) + rect.left; + states[i].y = MulDiv(raw->data.mouse.lLastY, rect.bottom, 65535) + rect.top; + + states[i].state_change_mouse = true; + } else if (raw->data.mouse.lLastX != 0 || raw->data.mouse.lLastY != 0) { + states[i].x_last = states[i].x; + states[i].y_last = states[i].y; + + states[i].x = states[i].x + raw->data.mouse.lLastX; + states[i].y = states[i].y + raw->data.mouse.lLastY; + + states[i].state_change_mouse = true; + } + } else if (raw->header.dwType == RIM_TYPEKEYBOARD) { + // @todo Change so we can directly access the correct state (maybe map handle address to index?) + while (states[i].is_connected && states[i].handle_keyboard != raw->header.hDevice) {++i;} + + if (!states[i].is_connected) { + return; + } + + // https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-rawkeyboard + + RAWKEYBOARD rawKB = raw->data.keyboard; + + states[i].key = raw->data.keyboard.MakeCode; + states[i].key_up = raw->data.keyboard.Flags & RI_KEY_BREAK; + states[i].key_down = raw->data.keyboard.Flags & RI_KEY_MAKE; + + if (states[i].key_down) { + for (int j = 0; j < MAX_KEY_PRESSES; ++j) { + if (states[i].keys_down[j] == NULL) { + states[i].keys_down[j] = states[i].key; + } + } + } else if (states[i].key_up) { + for (int j = 0; j < MAX_KEY_PRESSES; ++j) { + if (states[i].keys_down[j] == states[i].key) { + states[i].keys_down[j] = NULL; + } + } + } + + states[i].state_change_keyboard = true; + } +} + +#endif \ No newline at end of file diff --git a/platform/win32/input/XInput.h b/platform/win32/input/XInput.h new file mode 100644 index 0000000..f865bcd --- /dev/null +++ b/platform/win32/input/XInput.h @@ -0,0 +1,131 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_INPUT_XINPUT_H +#define TOS_INPUT_XINPUT_H + +#include +#include + +#include "../../../input/Input.h" +#include "../../../stdlib/Types.h" +#include "../../../utils/MathUtils.h" + +// @todo consider to remove some global_persist and defines since we are never calling it somewhere else + +// BEGIN: Dynamically load XInput +typedef DWORD WINAPI x_input_get_state(DWORD, XINPUT_STATE*); +DWORD WINAPI XInputGetStateStub(DWORD, XINPUT_STATE*) { + return 0; +} +global_persist x_input_get_state* XInputGetState_ = XInputGetStateStub; +#define XInputGetState XInputGetState_ + +typedef DWORD WINAPI x_input_set_state(DWORD, XINPUT_VIBRATION*); +DWORD WINAPI XInputSetStateStub(DWORD, XINPUT_VIBRATION*) { + return 0; +} +global_persist x_input_set_state* XInputSetState_ = XInputSetStateStub; +#define XInputSetState XInputSetState_ + +void xinput_load() { + HMODULE lib = LoadLibraryExA((LPCSTR) "xinput1_4.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + if(!lib) { + // @todo Log + lib = LoadLibraryExA((LPCSTR) "xinput1_3.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + } + + if (!lib) { + // @todo Log + return; + } + + XInputGetState = (x_input_get_state *) GetProcAddress(lib, "XInputGetState"); + XInputSetState = (x_input_set_state *) GetProcAddress(lib, "XInputSetState"); + + if (!XInputGetState || !XInputSetState) { + // @todo Log + return; + } +} +// END: Dynamically load XInput + +ControllerState* init_controllers() +{ + uint32 c = 0; + for (uint32 controller_index = 0; controller_index < XUSER_MAX_COUNT; ++controller_index) { + XINPUT_STATE controller_state; + if (XInputGetState(controller_index, &controller_state) == ERROR_SUCCESS) { + ++c; + } + } + + // We always want at least one empty controller slot + // @todo Change so that we store the actual number of devices + ControllerState *controllers = (ControllerState *) calloc((c + 1), sizeof(ControllerState)); + + if (c == 0) { + return controllers; + } + + c = 0; + for (uint32 controller_index = 0; controller_index < XUSER_MAX_COUNT; ++controller_index) { + XINPUT_STATE controller_state; + if (XInputGetState(controller_index, &controller_state) == ERROR_SUCCESS) { + ++c; + + controllers[c].id = controller_index; + controllers[c].is_connected = true; + } + } + + return controllers; +} + +void handle_controller_input(ControllerState* states) +{ + uint32 controller_index = 0; + while(states[controller_index].is_connected) { + XINPUT_STATE controller_state; + if (XInputGetState(controller_index, &controller_state) != ERROR_SUCCESS) { + ++controller_index; + + continue; + } + + states[controller_index].up = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP; + states[controller_index].down = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN; + states[controller_index].left = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT; + states[controller_index].right = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT; + states[controller_index].start = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_START; + states[controller_index].back = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK; + + states[controller_index].shoulder_left = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER; + states[controller_index].shoulder_right = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER; + + states[controller_index].trigger_left = controller_state.Gamepad.bLeftTrigger; + states[controller_index].trigger_right = controller_state.Gamepad.bRightTrigger; + + states[controller_index].button_a = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_A; + states[controller_index].button_b = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_B; + states[controller_index].button_x = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_X; + states[controller_index].button_y = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_Y; + + states[controller_index].stickl_x = controller_state.Gamepad.sThumbLX; + states[controller_index].stickl_y = controller_state.Gamepad.sThumbLY; + states[controller_index].stickl_press = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB; + + states[controller_index].stickr_x = controller_state.Gamepad.sThumbRX; + states[controller_index].stickr_y = controller_state.Gamepad.sThumbRY; + states[controller_index].stickr_press = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB; + + ++controller_index; + } +} + +#endif \ No newline at end of file diff --git a/render/liquid.cpp b/render/liquid.cpp new file mode 100644 index 0000000..e69de29 diff --git a/render/mob.cpp b/render/mob.cpp new file mode 100644 index 0000000..e69de29 diff --git a/render/object.cpp b/render/object.cpp new file mode 100644 index 0000000..e69de29 diff --git a/render/sky.cpp b/render/sky.cpp new file mode 100644 index 0000000..e69de29 diff --git a/render/text.cpp b/render/text.cpp new file mode 100644 index 0000000..e69de29 diff --git a/shaders/liquids/lava.hlsl b/shaders/liquids/lava.hlsl new file mode 100644 index 0000000..e69de29 diff --git a/shaders/liquids/water/cube_fragment.hlsl b/shaders/liquids/water/cube_fragment.hlsl new file mode 100644 index 0000000..9cf8bd2 --- /dev/null +++ b/shaders/liquids/water/cube_fragment.hlsl @@ -0,0 +1,13 @@ +#include "helper.hlsli" + +varying vec3 position; +uniform sampler2D water; +const vec3 underwaterColor = vec3(0.4, 0.9, 1.0); + +void main() { + gl_FragColor = vec4(getSphereColor(position), 1.0); + vec4 info = texture2D(water, position.xz * 0.5 + 0.5); + if (position.y < info.r) { + gl_FragColor.rgb *= underwaterColor * 1.2; + } +} \ No newline at end of file diff --git a/shaders/liquids/water/cube_vertex.hlsl b/shaders/liquids/water/cube_vertex.hlsl new file mode 100644 index 0000000..f995e1c --- /dev/null +++ b/shaders/liquids/water/cube_vertex.hlsl @@ -0,0 +1,8 @@ +varying vec3 position; +float poolHeight = 1.0; + +void main() { + position = gl_Vertex.xyz; + position.y = ((1.0 - position.y) * (7.0 / 12.0) - 1.0) * poolHeight; + gl_Position = gl_ModelViewProjectionMatrix * vec4(position, 1.0); +} \ No newline at end of file diff --git a/shaders/liquids/water/helper.hlsli b/shaders/liquids/water/helper.hlsli new file mode 100644 index 0000000..df208be --- /dev/null +++ b/shaders/liquids/water/helper.hlsli @@ -0,0 +1,130 @@ +const float IOR_AIR = 1.0; +const float IOR_WATER = 1.333; + +float poolHeight = 1.0; +uniform vec3 light; +uniform vec3 sphereCenter; +uniform float sphereRadius; +uniform sampler2D tiles; +uniform sampler2D causticTex; +uniform sampler2D water; + +vec2 intersectCube(vec3 origin, vec3 ray, vec3 cubeMin, vec3 cubeMax) { + vec3 tMin = (cubeMin - origin) / ray; + vec3 tMax = (cubeMax - origin) / ray; + + vec3 t1 = min(tMin, tMax); + vec3 t2 = max(tMin, tMax); + + float tNear = max(max(t1.x, t1.y), t1.z); + float tFar = min(min(t2.x, t2.y), t2.z); + + return vec2(tNear, tFar); +} + +float intersectSphere(vec3 origin, vec3 ray, vec3 sphereCenter, float sphereRadius) { + vec3 toSphere = origin - sphereCenter; + + float a = dot(ray, ray); + float b = 2.0 * dot(toSphere, ray); + float c = dot(toSphere, toSphere) - sphereRadius * sphereRadius; + + float discriminant = b * b - 4.0 * a * c; + if (discriminant > 0.0) { + float t = (-b - sqrt(discriminant)) / (2.0 * a); + if (t > 0.0) { + return t; + } + } + + return 1.0e6; +} + +uniform sampler2D causticTex; +vec3 getSphereColor(vec3 point) { + vec3 color = vec3(0.5); + + /* ambient occlusion with walls */ + color *= 1.0 - 0.9 / pow((1.0 + sphereRadius - abs(point.x)) / sphereRadius, 3.0); + color *= 1.0 - 0.9 / pow((1.0 + sphereRadius - abs(point.z)) / sphereRadius, 3.0); + color *= 1.0 - 0.9 / pow((point.y + 1.0 + sphereRadius) / sphereRadius, 3.0); + + /* caustics */ + vec3 sphereNormal = (point - sphereCenter) / sphereRadius; + vec3 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), IOR_AIR / IOR_WATER); + float diffuse = max(0.0, dot(-refractedLight, sphereNormal)) * 0.5; + vec4 info = texture2D(water, point.xz * 0.5 + 0.5); + if (point.y < info.r) { + vec4 caustic = texture2D(causticTex, 0.75 * (point.xz - point.y * refractedLight.xz / refractedLight.y) * 0.5 + 0.5); + diffuse *= caustic.r * 4.0; + } + color += diffuse; + + return color; +} + +uniform sampler2D tiles; +vec3 getWallColor(vec3 point) { + float scale = 0.5; + + vec3 wallColor; + vec3 normal; + if (abs(point.x) > 0.999) { + wallColor = texture2D(tiles, point.yz * 0.5 + vec2(1.0, 0.5)).rgb; + normal = vec3(-point.x, 0.0, 0.0); + } else if (abs(point.z) > 0.999) { + wallColor = texture2D(tiles, point.yx * 0.5 + vec2(1.0, 0.5)).rgb; + normal = vec3(0.0, 0.0, -point.z); + } else { + wallColor = texture2D(tiles, point.xz * 0.5 + 0.5).rgb; + normal = vec3(0.0, 1.0, 0.0); + } + + scale /= length(point); /* pool ambient occlusion */ + scale *= 1.0 - 0.9 / pow(length(point - sphereCenter) / sphereRadius, 4.0); /* sphere ambient occlusion */ + + /* caustics */ + vec3 refractedLight = -refract(-light, vec3(0.0, 1.0, 0.0), IOR_AIR / IOR_WATER); + float diffuse = max(0.0, dot(refractedLight, normal)); + vec4 info = texture2D(water, point.xz * 0.5 + 0.5); + if (point.y < info.r) { + vec4 caustic = texture2D(causticTex, 0.75 * (point.xz - point.y * refractedLight.xz / refractedLight.y) * 0.5 + 0.5); + scale += diffuse * caustic.r * 2.0 * caustic.g; + } else { + /* shadow for the rim of the pool */ + vec2 t = intersectCube(point, refractedLight, vec3(-1.0, -poolHeight, -1.0), vec3(1.0, 2.0, 1.0)); + diffuse *= 1.0 / (1.0 + exp(-200.0 / (1.0 + 10.0 * (t.y - t.x)) * (point.y + refractedLight.y * t.y - 2.0 / 12.0))); + + scale += diffuse * 0.5; + } + + return wallColor * scale; +} + +uniform samplerCube sky; +vec3 getSurfaceRayColor(vec3 origin, vec3 ray, vec3 waterColor) { + vec3 color; + float q = intersectSphere(origin, ray, sphereCenter, sphereRadius); + + if (q < 1.0e6) { + color = getSphereColor(origin + ray * q); + } else if (ray.y < 0.0) { + vec2 t = intersectCube(origin, ray, vec3(-1.0, -poolHeight, -1.0), vec3(1.0, 2.0, 1.0)); + color = getWallColor(origin + ray * t.y); + } else { + vec2 t = intersectCube(origin, ray, vec3(-1.0, -poolHeight, -1.0), vec3(1.0, 2.0, 1.0)); + vec3 hit = origin + ray * t.y; + if (hit.y < 2.0 / 12.0) { + color = getWallColor(hit); + } else { + color = textureCube(sky, ray).rgb; + color += vec3(pow(max(0.0, dot(light, ray)), 5000.0)) * vec3(10.0, 8.0, 6.0); + } + } + + if (ray.y < 0.0) { + color *= waterColor; + } + + return color; +} \ No newline at end of file diff --git a/shaders/liquids/water/sphere_fragment.hlsl b/shaders/liquids/water/sphere_fragment.hlsl new file mode 100644 index 0000000..70f961f --- /dev/null +++ b/shaders/liquids/water/sphere_fragment.hlsl @@ -0,0 +1,12 @@ +varying vec3 position; +const vec3 underwaterColor = vec3(0.4, 0.9, 1.0); +uniform sampler2D water; + +void main() { + gl_FragColor = vec4(getSphereColor(position), 1.0); + vec4 info = texture2D(water, position.xz * 0.5 + 0.5); + + if (position.y < info.r) { + gl_FragColor.rgb *= underwaterColor * 1.2; + } +} diff --git a/shaders/liquids/water/sphere_vertex.hlsl b/shaders/liquids/water/sphere_vertex.hlsl new file mode 100644 index 0000000..90a737f --- /dev/null +++ b/shaders/liquids/water/sphere_vertex.hlsl @@ -0,0 +1,8 @@ +uniform vec3 sphereCenter; +uniform float sphereRadius; +varying vec3 position; + +void main() { + position = sphereCenter + gl_Vertex.xyz * sphereRadius; + gl_Position = gl_ModelViewProjectionMatrix * vec4(position, 1.0); +} \ No newline at end of file diff --git a/shaders/liquids/water/water_above_fragment.hlsl b/shaders/liquids/water/water_above_fragment.hlsl new file mode 100644 index 0000000..26271d5 --- /dev/null +++ b/shaders/liquids/water/water_above_fragment.hlsl @@ -0,0 +1,28 @@ +#include "helper.hlsli" + +uniform vec3 eye; +varying vec3 position; +const vec3 abovewaterColor = vec3(0.25, 1.0, 1.25); + +void main() { + vec2 coord = position.xz * 0.5 + 0.5; + vec4 info = texture2D(water, coord); + + /* make water look more "peaked" */ + for (int i = 0; i < 5; i++) { + coord += info.ba * 0.005; + info = texture2D(water, coord); + } + + vec3 normal = vec3(info.b, sqrt(1.0 - dot(info.ba, info.ba)), info.a); + vec3 incomingRay = normalize(position - eye); + + vec3 reflectedRay = reflect(incomingRay, normal); + vec3 refractedRay = refract(incomingRay, normal, IOR_AIR / IOR_WATER); + float fresnel = mix(0.25, 1.0, pow(1.0 - dot(normal, -incomingRay), 3.0)); + + vec3 reflectedColor = getSurfaceRayColor(position, reflectedRay, abovewaterColor); + vec3 refractedColor = getSurfaceRayColor(position, refractedRay, abovewaterColor); + + gl_FragColor = vec4(mix(refractedColor, reflectedColor, fresnel), 1.0); +} \ No newline at end of file diff --git a/shaders/liquids/water/water_below_fragment.hlsl b/shaders/liquids/water/water_below_fragment.hlsl new file mode 100644 index 0000000..161e480 --- /dev/null +++ b/shaders/liquids/water/water_below_fragment.hlsl @@ -0,0 +1,30 @@ +#include "helper.hlsli" + +uniform vec3 eye; +varying vec3 position; +const vec3 underwaterColor = vec3(0.4, 0.9, 1.0); + +void main() { + vec2 coord = position.xz * 0.5 + 0.5; + vec4 info = texture2D(water, coord); + + /* make water look more "peaked" */ + for (int i = 0; i < 5; i++) { + coord += info.ba * 0.005; + info = texture2D(water, coord); + } + + vec3 normal = vec3(info.b, sqrt(1.0 - dot(info.ba, info.ba)), info.a); + vec3 incomingRay = normalize(position - eye); + + // @todo avove and below water are almost the same maybe we can merge the shaders + normal = -normal; + vec3 reflectedRay = reflect(incomingRay, normal); + vec3 refractedRay = refract(incomingRay, normal, IOR_WATER / IOR_AIR); + float fresnel = mix(0.5, 1.0, pow(1.0 - dot(normal, -incomingRay), 3.0)); + + vec3 reflectedColor = getSurfaceRayColor(position, reflectedRay, underwaterColor); + vec3 refractedColor = getSurfaceRayColor(position, refractedRay, vec3(1.0)) * vec3(0.8, 1.0, 1.1); + + gl_FragColor = vec4(mix(reflectedColor, refractedColor, (1.0 - fresnel) * length(refractedRay)), 1.0); +} \ No newline at end of file diff --git a/shaders/liquids/water/water_caustics_fragment.hlsl b/shaders/liquids/water/water_caustics_fragment.hlsl new file mode 100644 index 0000000..3ca7c8f --- /dev/null +++ b/shaders/liquids/water/water_caustics_fragment.hlsl @@ -0,0 +1,32 @@ +// if has derivative +#extension GL_OES_standard_derivatives : enablen + +varying vec3 oldPos; +varying vec3 newPos; +varying vec3 ray; + +void main() { + /* if the triangle gets smaller, it gets brighter, and vice versa */ + // if has derivative + float oldArea = length(dFdx(oldPos)) * length(dFdy(oldPos)); + float newArea = length(dFdx(newPos)) * length(dFdy(newPos)); + gl_FragColor = vec4(oldArea / newArea * 0.2, 1.0, 0.0, 0.0); + + // gl_FragColor = vec4(0.2, 0.2, 0.0, 0.0); + + vec3 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), IOR_AIR / IOR_WATER); + + /* compute a blob shadow and make sure we only draw a shadow if the player is blocking the light */ + vec3 dir = (sphereCenter - newPos) / sphereRadius; + vec3 area = cross(dir, refractedLight); + float shadow = dot(area, area); + float dist = dot(dir, -refractedLight); + shadow = 1.0 + (shadow - 1.0) / (0.05 + dist * 0.025); + shadow = clamp(1.0 / (1.0 + exp(-shadow)), 0.0, 1.0); + shadow = mix(1.0, shadow, clamp(dist * 2.0, 0.0, 1.0)); + gl_FragColor.g = shadow; + + /* shadow for the rim of the pool */ + vec2 t = intersectCube(newPos, -refractedLight, vec3(-1.0, -poolHeight, -1.0), vec3(1.0, 2.0, 1.0)); + gl_FragColor.r *= 1.0 / (1.0 + exp(-200.0 / (1.0 + 10.0 * (t.y - t.x)) * (newPos.y - refractedLight.y * t.y - 2.0 / 12.0))); +} \ No newline at end of file diff --git a/shaders/liquids/water/water_caustics_vertex.hlsl b/shaders/liquids/water/water_caustics_vertex.hlsl new file mode 100644 index 0000000..f33f441 --- /dev/null +++ b/shaders/liquids/water/water_caustics_vertex.hlsl @@ -0,0 +1,38 @@ +varying vec3 oldPos; +varying vec3 newPos; +varying vec3 ray; + +vec2 intersectCube(vec3 origin, vec3 ray, vec3 cubeMin, vec3 cubeMax) { + vec3 tMin = (cubeMin - origin) / ray; + vec3 tMax = (cubeMax - origin) / ray; + + vec3 t1 = min(tMin, tMax); + vec3 t2 = max(tMin, tMax); + + float tNear = max(max(t1.x, t1.y), t1.z); + float tFar = min(min(t2.x, t2.y), t2.z); + + return vec2(tNear, tFar); +} + +/* project the ray onto the plane */ +vec3 project(vec3 origin, vec3 ray, vec3 refractedLight) { + vec2 tcube = intersectCube(origin, ray, vec3(-1.0, -poolHeight, -1.0), vec3(1.0, 2.0, 1.0)); + origin += ray * tcube.y; + float tplane = (-origin.y - 1.0) / refractedLight.y; + return origin + refractedLight * tplane; +} + +void main() { + vec4 info = texture2D(water, gl_Vertex.xy * 0.5 + 0.5); + info.ba *= 0.5; + vec3 normal = vec3(info.b, sqrt(1.0 - dot(info.ba, info.ba)), info.a); + + /* project the vertices along the refracted vertex ray */ + vec3 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), IOR_AIR / IOR_WATER); + ray = refract(-light, normal, IOR_AIR / IOR_WATER); + oldPos = project(gl_Vertex.xzy, refractedLight, refractedLight); + newPos = project(gl_Vertex.xzy + vec3(0.0, info.r, 0.0), ray, refractedLight); + + gl_Position = vec4(0.75 * (newPos.xz + refractedLight.xz / refractedLight.y), 0.0, 1.0); +} diff --git a/shaders/liquids/water/water_vertex.hlsl b/shaders/liquids/water/water_vertex.hlsl new file mode 100644 index 0000000..8c0549f --- /dev/null +++ b/shaders/liquids/water/water_vertex.hlsl @@ -0,0 +1,9 @@ +uniform sampler2D water; +varying vec3 position; + +void main() { + vec4 info = texture2D(water, gl_Vertex.xy * 0.5 + 0.5); + position = gl_Vertex.xzy; + position.y += info.r; + gl_Position = gl_ModelViewProjectionMatrix * vec4(position, 1.0); +} \ No newline at end of file diff --git a/shaders/nature/cloud.hlsl b/shaders/nature/cloud.hlsl new file mode 100644 index 0000000..e69de29 diff --git a/shaders/nature/fire.hlsl b/shaders/nature/fire.hlsl new file mode 100644 index 0000000..e69de29 diff --git a/shaders/nature/fog.hlsl b/shaders/nature/fog.hlsl new file mode 100644 index 0000000..e69de29 diff --git a/shaders/nature/godray.hlsl b/shaders/nature/godray.hlsl new file mode 100644 index 0000000..e69de29 diff --git a/shaders/nature/lightning.hlsl b/shaders/nature/lightning.hlsl new file mode 100644 index 0000000..e69de29 diff --git a/shaders/nature/rain.hlsl b/shaders/nature/rain.hlsl new file mode 100644 index 0000000..e69de29 diff --git a/shaders/nature/smoke.hlsl b/shaders/nature/smoke.hlsl new file mode 100644 index 0000000..e69de29 diff --git a/shaders/nature/snow.hlsl b/shaders/nature/snow.hlsl new file mode 100644 index 0000000..e69de29 diff --git a/shaders/shaders.hlsl b/shaders/shaders.hlsl new file mode 100644 index 0000000..c13404b --- /dev/null +++ b/shaders/shaders.hlsl @@ -0,0 +1,20 @@ +struct PSInput +{ + float4 position : SV_POSITION; + float4 color : COLOR; +}; + +PSInput VSMain(float4 position : POSITION, float4 color : COLOR) +{ + PSInput result; + + result.position = position; + result.color = color; + + return result; +} + +float4 PSMain(PSInput input) : SV_TARGET +{ + return input.color; +} \ No newline at end of file diff --git a/stdlib/Intrinsics.h b/stdlib/Intrinsics.h new file mode 100644 index 0000000..e0d24b5 --- /dev/null +++ b/stdlib/Intrinsics.h @@ -0,0 +1,68 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_STDLIB_INTRINSICS_H +#define TOS_STDLIB_INTRINSICS_H + +#include +#include +#include + +#ifdef _LINUX + #include +#endif + +#include "Types.h" + +inline f32 sqrt(f32 a) { return _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(a))); } +inline f64 sqrt(f64 a) +{ + __m128d temp =_mm_set_sd(a); + + return _mm_cvtsd_f64(_mm_sqrt_sd(temp, temp)); +} + +inline f32 rsqrt(f32 a) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(a))); } +inline f64 rsqrt(f64 a) +{ + __m128d temp =_mm_set_sd(a); + + return _mm_cvtsd_f64( + _mm_div_sd( + _mm_set_sd(1.0), + _mm_sqrt_sd(temp, temp) + ) + ); +} + +inline f32 round(f32 a) +{ + return _mm_cvtss_f32( + _mm_round_ss(_mm_setzero_ps(), _mm_set_ss(a), (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC))); +} + +inline uint32 round_to_int(f32 a) { return (uint32) _mm_cvtss_si32(_mm_set_ss(a)); } + +inline f32 floor(f32 a) { return _mm_cvtss_f32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(a))); } + +inline f32 ceil(f32 a) { return _mm_cvtss_f32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(a))); } + +inline uint32 hash(uint64 a, uint64 b = 0) +{ + uint8 seed[16] = { + 0xaa, 0x9b, 0xbd, 0xb8, 0xa1, 0x98, 0xac, 0x3f, 0x1f, 0x94, 0x07, 0xb3, 0x8c, 0x27, 0x93, 0x69, + }; + + __m128i hash = _mm_set_epi64x(a, b); + hash = _mm_aesdec_si128(hash, _mm_loadu_si128((__m128i *) seed)); + hash = _mm_aesdec_si128(hash, _mm_loadu_si128((__m128i *) seed)); + + return _mm_extract_epi32(hash, 0); +} + +#endif \ No newline at end of file diff --git a/stdlib/Mathtypes.h b/stdlib/Mathtypes.h new file mode 100644 index 0000000..ba718f7 --- /dev/null +++ b/stdlib/Mathtypes.h @@ -0,0 +1,214 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_STDLIB_MATHTYPES_H +#define TOS_STDLIB_MATHTYPES_H + +#include "Types.h" + +struct v2_int32 { + union { + struct { + int32 x; + int32 y; + }; + + int32 v[2]; + }; +}; + +struct v3_int32 { + union { + struct { + union { + int32 x; + int32 r; + }; + union { + int32 y; + int32 g; + }; + union { + int32 z; + int32 b; + }; + }; + + int32 v[3]; + }; +}; + +struct v4_int32 { + union { + struct { + int32 x; + int32 y; + int32 z; + int32 w; + }; + + int32 v[4]; + }; +}; + +struct v2_int64 { + union { + struct { + int64 x; + int64 y; + }; + + int64 v[2]; + }; +}; + +struct v3_int64 { + union { + struct { + union { + int64 x; + int64 r; + }; + union { + int64 y; + int64 g; + }; + union { + int64 z; + int64 b; + }; + }; + + int64 v[3]; + }; +}; + +struct v4_int64 { + union { + struct { + int64 x; + int64 y; + int64 z; + int64 w; + }; + + int64 v[4]; + }; +}; + +struct v2_f32 { + union { + struct { + f32 x; + f32 y; + }; + + f32 v[2]; + }; +}; + +struct v3_f32 { + union { + struct { + union { + f32 x; + f32 r; + }; + union { + f32 y; + f32 g; + }; + union { + f32 z; + f32 b; + }; + }; + + f32 v[3]; + }; +}; + +struct v4_f32 { + union { + struct { + f32 x; + f32 y; + f32 z; + f32 w; + }; + + f32 v[4]; + }; +}; + +struct v2_f64 { + union { + struct { + f64 x; + f64 y; + }; + + f64 v[2]; + }; +}; + +struct v3_f64 { + union { + struct { + union { + f64 x; + f64 r; + }; + union { + f64 y; + f64 g; + }; + union { + f64 z; + f64 b; + }; + }; + + f64 v[3]; + }; +}; + +struct v4_f64 { + union { + struct { + f64 x; + f64 y; + f64 z; + f64 w; + }; + + f64 v[4]; + }; +}; + +struct m_int32 { + int32 *e; + size_t m, n; +}; + +struct m_int64 { + int64 *e; + size_t m, n; +}; + +struct m_f32 { + f32 *e; + size_t m, n; +}; + +struct m_f64 { + f64 *e; + size_t m, n; +}; + +#endif \ No newline at end of file diff --git a/stdlib/Types.h b/stdlib/Types.h new file mode 100644 index 0000000..1302060 --- /dev/null +++ b/stdlib/Types.h @@ -0,0 +1,109 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_TYPES_H +#define TOS_TYPES_H + +#include + +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; + +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; + +typedef uint16_t f16; +typedef float f32; +typedef double f64; + +typedef unsigned char byte; + +#define KILOBYTE 1024 +#define MEGABYTE 1048576 +#define GIGABYTE 1073741824 + +#define MAX_BYTE 0xFF +#define MAX_INT16 0xFFFF +#define MAX_INT32 0xFFFFFFFF + +#define internal static // only allows local "file" access +#define local_persist static +#define global_persist static + +#define HALF_FLOAT_SIGN_MASK 0x8000 +#define HALF_FLOAT_EXP_MASK 0x7C00 +#define HALF_FLOAT_FRAC_MASK 0x03FF + +#define HALF_FLOAT_EXP_SHIFT 10 +#define HALF_FLOAT_EXP_BIAS 15 + +#define FLOAT32_SIGN_MASK 0x80000000 +#define FLOAT32_EXP_MASK 0x7F800000 +#define FLOAT32_FRAC_MASK 0x007FFFFF + +#define FLOAT32_EXP_SHIFT 23 +#define FLOAT32_EXP_BIAS 127 + +uint16 float_to_f16(float f) { + uint32_t f_bits = *((uint32_t*)&f); + uint16_t f16_bits = 0; + + // Extract sign, exponent, and fraction from float + uint16_t sign = (f_bits & FLOAT32_SIGN_MASK) >> 16; + int32_t exponent = (int32_t) ((f_bits & FLOAT32_EXP_MASK) >> FLOAT32_EXP_SHIFT) - FLOAT32_EXP_BIAS + HALF_FLOAT_EXP_BIAS; + uint32_t fraction = (f_bits & FLOAT32_FRAC_MASK) >> (FLOAT32_EXP_SHIFT - HALF_FLOAT_EXP_SHIFT); + + if (exponent <= 0) { + if (exponent < -10) { + fraction = 0; + } else { + fraction = (fraction | 0x0400) >> (1 - exponent); + } + exponent = 0; + } else if (exponent >= 0x1F) { + exponent = 0x1F; + fraction = 0; + } + + f16_bits = (uint16_t) (sign | (exponent << HALF_FLOAT_EXP_SHIFT) | (fraction & HALF_FLOAT_FRAC_MASK)); + + return f16_bits; +} + +float f16_to_float(f16 f) { + uint32_t f_bits = 0; + + uint32_t sign = (f & HALF_FLOAT_SIGN_MASK) << 16; + int32_t exponent = (f & HALF_FLOAT_EXP_MASK) >> HALF_FLOAT_EXP_SHIFT; + uint32_t fraction = (f & HALF_FLOAT_FRAC_MASK) << (FLOAT32_EXP_SHIFT - HALF_FLOAT_EXP_SHIFT); + + if (exponent == 0) { + if (fraction != 0) { + exponent = 1; + while ((fraction & (1 << FLOAT32_EXP_SHIFT)) == 0) { + fraction <<= 1; + --exponent; + } + fraction &= ~FLOAT32_EXP_MASK; + } + } else if (exponent == 0x1F) { + exponent = 0xFF; + } else { + exponent += FLOAT32_EXP_BIAS - HALF_FLOAT_EXP_BIAS; + } + + f_bits = sign | (exponent << FLOAT32_EXP_SHIFT) | fraction; + + return *((float*)&f_bits); +} + +#endif diff --git a/stdlib/simd/SIMD_F32.h b/stdlib/simd/SIMD_F32.h new file mode 100644 index 0000000..0084b17 --- /dev/null +++ b/stdlib/simd/SIMD_F32.h @@ -0,0 +1,931 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_STDLIB_SIMD_F32_H +#define TOS_STDLIB_SIMD_F32_H + +#include +#include + +#include "../Types.h" + +struct f32_4 { + union { + __m128 s; + f32 v[4]; + }; +}; + +struct f32_8 { + union { + __m256 s; + f32 v[8]; + }; +}; + +struct f32_16 { + union { + __m512 s; + f32 v[16]; + }; +}; + +inline f32_4 load_f32_4(f32 *mem) +{ + f32_4 simd; + simd.s = _mm_loadu_ps(mem); + + return simd; +} + +inline f32_4 init_f32_4(f32 *mem) +{ + f32_4 simd; + simd.s = _mm_set_ps(mem[0], mem[1], mem[2], mem[3]); + + return simd; +} + +inline void unload_f32_4(f32_4 a, f32 *array) { _mm_store_ps(array, a.s); } + +inline f32_8 load_f32_8(f32 *mem) +{ + f32_8 simd; + simd.s = _mm256_loadu_ps(mem); + + return simd; +} + +inline f32_8 init_f32_8(f32 *mem) +{ + f32_8 simd; + simd.s = _mm256_set_ps(mem[0], mem[1], mem[2], mem[3], mem[4], mem[5], mem[6], mem[7]); + + return simd; +} + +inline void unload_f32_8(f32_8 a, f32 *array) { _mm256_store_ps(array, a.s); } + +inline f32_16 load_f32_16(f32 *mem) +{ + f32_16 simd; + simd.s = _mm512_loadu_ps(mem); + + return simd; +} + +inline f32_16 init_f32_16(f32 *mem) +{ + f32_16 simd; + simd.s = _mm512_set_ps(mem[0], mem[1], mem[2], mem[3], mem[4], mem[5], mem[6], mem[7], mem[8], mem[9], mem[10], + mem[11], mem[12], mem[13], mem[14], mem[15]); + + return simd; +} + +inline void unload_f32_16(f32_16 a, f32 *array) { _mm512_store_ps(array, a.s); } + +inline f32_4 init_zero_f32_4() +{ + f32_4 simd; + simd.s = _mm_setzero_ps(); + + return simd; +} + +inline f32_8 init_zero_f32_8() +{ + f32_8 simd; + simd.s = _mm256_setzero_ps(); + + return simd; +} + +inline f32_16 init_zero_f32_16() +{ + f32_16 simd; + simd.s = _mm512_setzero_ps(); + + return simd; +} + +inline f32_4 operator+(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_add_ps(a.s, b.s); + + return simd; +} + +inline f32_8 operator+(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_add_ps(a.s, b.s); + + return simd; +} + +inline f32_16 operator+(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_add_ps(a.s, b.s); + + return simd; +} + +inline f32_4 operator-(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_sub_ps(a.s, b.s); + + return simd; +} + +inline f32_4 operator-(f32_4 a) { return init_zero_f32_4() - a; } + +inline f32_8 operator-(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_sub_ps(a.s, b.s); + + return simd; +} + +inline f32_8 operator-(f32_8 a) { return init_zero_f32_8() - a; } + +inline f32_16 operator-(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_sub_ps(a.s, b.s); + + return simd; +} + +inline f32_16 operator-(f32_16 a) { return init_zero_f32_16() - a; } + +inline f32_4 operator*(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_mul_ps(a.s, b.s); + + return simd; +} + +inline f32_8 operator*(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_mul_ps(a.s, b.s); + + return simd; +} + +inline f32_16 operator*(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_mul_ps(a.s, b.s); + + return simd; +} + +inline f32_4 operator/(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_div_ps(a.s, b.s); + + return simd; +} + +inline f32_8 operator/(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_div_ps(a.s, b.s); + + return simd; +} + +inline f32_16 operator/(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_div_ps(a.s, b.s); + + return simd; +} + +inline f32_4 operator^(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_xor_ps(a.s, b.s); + + return simd; +} + +inline f32_8 operator^(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_xor_ps(a.s, b.s); + + return simd; +} + +inline f32_16 operator^(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_xor_ps(a.s, b.s); + + return simd; +} + +inline f32_4 &operator-=(f32_4 &a, f32_4 b) +{ + a = a - b; + + return a; +} + +inline f32_8 &operator-=(f32_8 &a, f32_8 b) +{ + a = a - b; + + return a; +} + +inline f32_16 &operator-=(f32_16 &a, f32_16 b) +{ + a = a - b; + + return a; +} + +inline f32_4 &operator+=(f32_4 &a, f32_4 b) +{ + a = a + b; + + return a; +} + +inline f32_8 &operator+=(f32_8 &a, f32_8 b) +{ + a = a + b; + + return a; +} + +inline f32_16 &operator+=(f32_16 &a, f32_16 b) +{ + a = a + b; + + return a; +} + +inline f32_4 &operator*=(f32_4 &a, f32_4 b) +{ + a = a * b; + + return a; +} + +inline f32_8 &operator*=(f32_8 &a, f32_8 b) +{ + a = a * b; + + return a; +} + +inline f32_16 &operator*=(f32_16 &a, f32_16 b) +{ + a = a * b; + + return a; +} + +inline f32_4 &operator/=(f32_4 &a, f32_4 b) +{ + a = a / b; + + return a; +} + +inline f32_8 &operator/=(f32_8 &a, f32_8 b) +{ + a = a / b; + + return a; +} + +inline f32_16 &operator/=(f32_16 &a, f32_16 b) +{ + a = a / b; + + return a; +} + +inline f32_4 &operator^=(f32_4 &a, f32_4 b) +{ + a = a ^ b; + + return a; +} + +inline f32_8 &operator^=(f32_8 &a, f32_8 b) +{ + a = a ^ b; + + return a; +} + +inline f32_16 &operator^=(f32_16 &a, f32_16 b) +{ + a = a ^ b; + + return a; +} + +inline f32_4 operator<(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_cmplt_ps(a.s, b.s); + + return simd; +} + +inline f32_8 operator<(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_cmp_ps(a.s, b.s, _CMP_LT_OQ); + + return simd; +} + +inline f32_16 operator<(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_mask_blend_ps(_mm512_cmplt_ps_mask(a.s, b.s), a.s, b.s); + + return simd; +} + +inline f32_4 operator<=(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_cmple_ps(a.s, b.s); + + return simd; +} + +inline f32_8 operator<=(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_cmp_ps(a.s, b.s, _CMP_LE_OQ); + + return simd; +} + +inline f32_16 operator<=(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_mask_blend_ps(_mm512_cmp_ps_mask(a.s, b.s, _CMP_LE_OQ), a.s, b.s); + + return simd; +} + +inline f32_4 operator>(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_cmpgt_ps(a.s, b.s); + + return simd; +} + +inline f32_8 operator>(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_cmp_ps(a.s, b.s, _CMP_GT_OQ); + + return simd; +} + +inline f32_16 operator>(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_mask_blend_ps(_mm512_cmp_ps_mask(a.s, b.s, _CMP_GT_OQ), a.s, b.s); + + return simd; +} + +inline f32_4 operator>=(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_cmpge_ps(a.s, b.s); + + return simd; +} + +inline f32_8 operator>=(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_cmp_ps(a.s, b.s, _CMP_GE_OQ); + + return simd; +} + +inline f32_16 operator>=(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_mask_blend_ps(_mm512_cmp_ps_mask(a.s, b.s, _CMP_GE_OQ), a.s, b.s); + + return simd; +} + +inline f32_4 operator==(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_cmpeq_ps(a.s, b.s); + + return simd; +} + +inline f32_8 operator==(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_cmp_ps(a.s, b.s, _CMP_EQ_OQ); + + return simd; +} + +inline f32_16 operator==(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_mask_blend_ps(_mm512_cmp_ps_mask(a.s, b.s, _CMP_EQ_OQ), a.s, b.s); + + return simd; +} + +inline f32_4 operator!=(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_cmpneq_ps(a.s, b.s); + + return simd; +} + +inline f32_8 operator!=(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_cmp_ps(a.s, b.s, _CMP_NEQ_OQ); + + return simd; +} + +inline f32_16 operator!=(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_mask_blend_ps(_mm512_cmp_ps_mask(a.s, b.s, _CMP_NEQ_OQ), a.s, b.s); + + return simd; +} + +inline f32_4 operator&(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_and_ps(a.s, b.s); + + return simd; +} + +inline f32_8 operator&(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_and_ps(a.s, b.s); + + return simd; +} + +inline f32_16 operator&(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_and_ps(a.s, b.s); + + return simd; +} + +inline f32_4 operator|(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_or_ps(a.s, b.s); + + return simd; +} + +inline f32_8 operator|(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_or_ps(a.s, b.s); + + return simd; +} + +inline f32_16 operator|(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_or_ps(a.s, b.s); + + return simd; +} + +inline f32_4 &operator&=(f32_4 &a, f32_4 b) +{ + a = a & b; + + return a; +} + +inline f32_8 &operator&=(f32_8 &a, f32_8 b) +{ + a = a & b; + + return a; +} + +inline f32_16 &operator&=(f32_16 &a, f32_16 b) +{ + a = a & b; + + return a; +} + +inline f32_4 &operator|=(f32_4 &a, f32_4 b) +{ + a = a | b; + + return a; +} + +inline f32_8 &operator|=(f32_8 &a, f32_8 b) +{ + a = a | b; + + return a; +} + +inline f32_16 &operator|=(f32_16 &a, f32_16 b) +{ + a = a | b; + + return a; +} + +inline f32_4 abs(f32_4 a) +{ + unsigned int unsigned_mask = (unsigned int) (1 << 31); + __m128 mask = _mm_set1_ps(*(float *) &unsigned_mask); + + f32_4 simd; + simd.s = _mm_and_ps(a.s, mask); + + return simd; +} + +inline f32_8 abs(f32_8 a) +{ + unsigned int unsigned_mask = (unsigned int) (1 << 31); + __m256 mask = _mm256_set1_ps(*(float *) &unsigned_mask); + + f32_8 simd; + simd.s = _mm256_and_ps(a.s, mask); + + return simd; +} + +inline f32_16 abs(f32_16 a) +{ + unsigned int unsigned_mask = (unsigned int) (1 << 31); + __m512 mask = _mm512_set1_ps(*(float *) &unsigned_mask); + + f32_16 simd; + simd.s = _mm512_and_ps(a.s, mask); + + return simd; +} + +inline f32_4 simd_min(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_min_ps(a.s, b.s); + + return simd; +} + +inline f32_8 simd_min(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_min_ps(a.s, b.s); + + return simd; +} + +inline f32_16 simd_min(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_min_ps(a.s, b.s); + + return simd; +} + +inline f32_4 simd_max(f32_4 a, f32_4 b) +{ + f32_4 simd; + simd.s = _mm_max_ps(a.s, b.s); + + return simd; +} + +inline f32_8 simd_max(f32_8 a, f32_8 b) +{ + f32_8 simd; + simd.s = _mm256_max_ps(a.s, b.s); + + return simd; +} + +inline f32_16 simd_max(f32_16 a, f32_16 b) +{ + f32_16 simd; + simd.s = _mm512_max_ps(a.s, b.s); + + return simd; +} + +inline f32_4 sign(f32_4 a) +{ + unsigned int umask = (unsigned int) (1 << 31); + __m128 mask = _mm_set1_ps(*(float *) &umask); + + f32_4 signBit; + signBit.s = _mm_and_ps(a.s, mask); + + f32_4 b; + b.s = _mm_set1_ps(1.0f); + + f32_4 simd = b | signBit; + + return simd; +} + +inline f32_8 sign(f32_8 a) +{ + unsigned int umask = (unsigned int) (1 << 31); + __m256 mask = _mm256_set1_ps(*(float *) &umask); + + f32_8 signBit; + signBit.s = _mm256_and_ps(a.s, mask); + + f32_8 b; + b.s = _mm256_set1_ps(1.0f); + + f32_8 simd = b | signBit; + + return simd; +} + +inline f32_16 sign(f32_16 a) +{ + unsigned int umask = (unsigned int) (1 << 31); + __m512 mask = _mm512_set1_ps(*(float *) &umask); + + f32_16 signBit; + signBit.s = _mm512_and_ps(a.s, mask); + + f32_16 b; + b.s = _mm512_set1_ps(1.0f); + + f32_16 simd = b | signBit; + + return simd; +} + +inline f32_4 floor(f32_4 a) +{ + f32_4 simd; + simd.s = _mm_floor_ps(a.s); + + return simd; +} + +inline f32_8 floor(f32_8 a) +{ + f32_8 simd; + simd.s = _mm256_floor_ps(a.s); + + return simd; +} + +inline f32_16 floor(f32_16 a) +{ + f32_16 simd; + simd.s = _mm512_floor_ps(a.s); + + return simd; +} + +inline f32_4 ceil(f32_4 a) +{ + f32_4 simd; + simd.s = _mm_ceil_ps(a.s); + + return simd; +} + +inline f32_8 ceil(f32_8 a) +{ + f32_8 simd; + simd.s = _mm256_ceil_ps(a.s); + + return simd; +} + +inline f32_16 ceil(f32_16 a) +{ + f32_16 simd; + simd.s = _mm512_ceil_ps(a.s); + + return simd; +} + +inline f32_4 sqrt(f32_4 a) +{ + f32_4 simd; + simd.s = _mm_sqrt_ps(a.s); + + return simd; +} + +inline f32_8 sqrt(f32_8 a) +{ + f32_8 simd; + simd.s = _mm256_sqrt_ps(a.s); + + return simd; +} + +inline f32_16 sqrt(f32_16 a) +{ + f32_16 simd; + simd.s = _mm512_sqrt_ps(a.s); + + return simd; +} + +inline f32_4 sqrt_inv_approx(f32_4 a) +{ + f32_4 simd; + simd.s = _mm_rsqrt_ps(a.s); + + return simd; +} + +inline f32_8 sqrt_inv_approx(f32_8 a) +{ + f32_8 simd; + simd.s = _mm256_rsqrt_ps(a.s); + + return simd; +} + +inline f32_16 sqrt_inv_approx(f32_16 a) +{ + f32_16 simd; + simd.s = _mm512_rsqrt14_ps(a.s); + + return simd; +} + +inline f32_4 one_over_approx(f32_4 a) +{ + f32_4 simd; + simd.s = _mm_rcp_ps(a.s); + + return simd; +} + +inline f32_8 one_over_approx(f32_8 a) +{ + f32_8 simd; + simd.s = _mm256_rcp_ps(a.s); + + return simd; +} + +inline f32_16 one_over_approx(f32_16 a) +{ + f32_16 simd; + simd.s = _mm512_rcp14_ps(a.s); + + return simd; +} + +inline f32_4 clamp(f32_4 min_value, f32_4 a, f32_4 max_value) +{ + return simd_min(simd_max(a, min_value), max_value); +} + +inline f32_8 clamp(f32_8 min_value, f32_8 a, f32_8 max_value) +{ + return simd_min(simd_max(a, min_value), max_value); +} + +inline f32_16 clamp(f32_16 min_value, f32_16 a, f32_16 max_value) +{ + return simd_min(simd_max(a, min_value), max_value); +} + +inline int32 which_true(f32_4 a) +{ + int32 which_true = _mm_movemask_ps(a.s); + + return which_true; +} + +inline int32 which_true(f32_8 a) +{ + int32 which_true = _mm256_movemask_ps(a.s); + + return which_true; +} + +inline int32 which_true(f32_16 a) +{ + int32 which_true = _mm512_movepi32_mask(_mm512_castps_si512(a.s)); + + return which_true; +} + +inline bool any_true(f32_4 a) +{ + bool is_any_true = _mm_movemask_ps(a.s) > 0; + + return is_any_true; +} + +inline bool any_true(f32_8 a) +{ + bool is_any_true = _mm256_movemask_ps(a.s) > 0; + + return is_any_true; +} + +inline bool any_true(f32_16 a) +{ + bool is_any_true = _mm512_movepi32_mask(_mm512_castps_si512(a.s)) > 0; + + return is_any_true; +} + +inline bool all_true(f32_4 a) +{ + bool is_true = _mm_movemask_ps(a.s) == 15; + + return is_true; +} + +inline bool all_true(f32_8 a) +{ + bool is_true = _mm256_movemask_ps(a.s) == 255; + + return is_true; +} + +inline bool all_true(f32_16 a) +{ + bool is_true = _mm512_movepi32_mask(_mm512_castps_si512(a.s)) == 65535; + + return is_true; +} + +inline bool all_false(f32_4 a) +{ + bool is_false = _mm_movemask_ps(a.s) == 0; + + return is_false; +} + +inline bool all_false(f32_8 a) +{ + bool is_false = _mm256_movemask_ps(a.s) == 0; + + return is_false; +} + +inline bool all_false(f32_16 a) +{ + // @todo This can be optimized (requires also changes in the comparison functions return) + bool is_false = _mm512_movepi32_mask(_mm512_castps_si512(a.s)) == 0; + + return is_false; +} + +#endif diff --git a/stdlib/simd/SIMD_F64.h b/stdlib/simd/SIMD_F64.h new file mode 100644 index 0000000..061093f --- /dev/null +++ b/stdlib/simd/SIMD_F64.h @@ -0,0 +1,38 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_STDLIB_SIMD_F64_H +#define TOS_STDLIB_SIMD_F64_H + +#include +#include + +#include "../Types.h" + +struct f64_2 { + union { + __m128 s; + f64 v[2]; + }; +}; + +struct f64_4 { + union { + __m256 s; + f64 v[4]; + }; +}; + +struct f64_8 { + union { + __m512 s; + f64 v[8]; + }; +}; + +#endif \ No newline at end of file diff --git a/stdlib/simd/SIMD_Helper.h b/stdlib/simd/SIMD_Helper.h new file mode 100644 index 0000000..2e92808 --- /dev/null +++ b/stdlib/simd/SIMD_Helper.h @@ -0,0 +1,97 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_STDLIB_SIMD_HELPER_H +#define TOS_STDLIB_SIMD_HELPER_H + +#include +#include +#include + +#ifdef _MSC_VER + #include +#endif + +inline +bool is_sse_supported() +{ + #ifdef _MSC_VER + int cpuInfo[4] = {-1}; + __cpuid(cpuInfo, 1); // CPUID function 1 + + // Check the SSE feature bit in EDX + return (cpuInfo[3] >> 25) & 1; + #else + uint32_t eax, ebx, ecx, edx; + + eax = 1; // CPUID function 1 + + __asm__ __volatile__("cpuid;" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(eax)); + + // Check the AVX feature bit in ECX + return (ecx >> 28) & 1; + #endif +} + +inline +bool is_avx256_supported() +{ + #ifdef _MSC_VER + int cpuInfo[4] = {-1}; + __cpuid(cpuInfo, 1); // CPUID function 1 + + // Check the AVX feature bit in ECX + if ((cpuInfo[2] >> 28) & 1) { + __cpuid(cpuInfo, 7); // CPUID function 7, sub-function 0 + // Check the AVX2 feature bit in EBX + return (cpuInfo[1] >> 5) & 1; + } + + return false; + #else + uint32_t eax, ebx, ecx, edx; + + eax = 7; // CPUID function 7 + ecx = 0; // Sub-function 0 + + __asm__ __volatile__("cpuid;" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(eax), "c"(ecx)); + + // Check the AVX-256 (AVX2) feature bit in EBX + return (ebx >> 5) & 1; + #endif +} + +inline +bool is_avx512_supported() +{ + #ifdef _MSC_VER + int cpuInfo[4] = {-1}; + __cpuid(cpuInfo, 1); // CPUID function 1 + + // Check the AVX feature bit in ECX + if ((cpuInfo[2] >> 28) & 1) { + __cpuid(cpuInfo, 7); // CPUID function 7, sub-function 0 + // Check the AVX-512 feature bit in EBX + return (cpuInfo[1] >> 16) & 1; + } + + return false; + #else + uint32_t eax, ebx, ecx, edx; + + eax = 7; // CPUID function 7 + ecx = 0; // Sub-function 0 + + __asm__ __volatile__("cpuid;" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(eax), "c"(ecx)); + + // Check the AVX-512 feature bit in EBX + return (ebx >> 16) & 1; + #endif +} + +#endif \ No newline at end of file diff --git a/stdlib/simd/SIMD_I32.h b/stdlib/simd/SIMD_I32.h new file mode 100644 index 0000000..7c09ad4 --- /dev/null +++ b/stdlib/simd/SIMD_I32.h @@ -0,0 +1,867 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_TOS_STDLIB_SIMD_I32_H +#define TOS_TOS_STDLIB_SIMD_I32_H + +#include +#include + +#include "../Types.h" +#include "SIMD_F32.h" + +struct int32_4 { + union { + __m128i s; + int32 v[4]; + }; +}; + +struct int32_8 { + union { + __m256i s; + int32 v[8]; + }; +}; + +struct int32_16 { + union { + __m512i s; + int32 v[16]; + }; +}; + +inline int32_4 load_int32_4(int32 *mem) +{ + int32_4 simd; + simd.s = _mm_loadu_epi32(mem); + + return simd; +} + +inline int32_4 init_int32_4(int32 *mem) +{ + int32_4 simd; + simd.s = _mm_set_epi32(mem[0], mem[1], mem[2], mem[3]); + + return simd; +} + +inline void unload_int32_4(int32_4 a, int32 *array) { _mm_store_si128((__m128i *) array, a.s); } + +inline int32_8 load_int32_8(int32 *mem) +{ + int32_8 simd; + simd.s = _mm256_loadu_epi32(mem); + + return simd; +} + +inline int32_8 init_int32_8(int32 *mem) +{ + int32_8 simd; + simd.s = _mm256_set_epi32(mem[0], mem[1], mem[2], mem[3], mem[4], mem[5], mem[6], mem[7]); + + return simd; +} + +inline void unload_int32_8(int32_8 a, int32 *array) { _mm256_store_si256((__m256i *) array, a.s); } + +inline int32_16 load_int32_16(int32 *mem) +{ + int32_16 simd; + simd.s = _mm512_loadu_epi32(mem); + + return simd; +} + +inline int32_16 init_int32_16(int32 *mem) +{ + int32_16 simd; + simd.s = _mm512_set_epi32(mem[0], mem[1], mem[2], mem[3], mem[4], mem[5], mem[6], mem[7], mem[8], mem[9], + mem[10], mem[11], mem[12], mem[13], mem[14], mem[15]); + + return simd; +} + +inline void unload_int32_16(int32_16 a, int32 *array) { _mm512_store_epi32(array, a.s); } + +inline int32_4 init_zero_int32_4() +{ + int32_4 simd; + simd.s = _mm_setzero_si128(); + + return simd; +} + +inline int32_8 init_zero_int32_8() +{ + int32_8 simd; + simd.s = _mm256_setzero_si256(); + + return simd; +} + +inline int32_16 init_zero_int32_16() +{ + int32_16 simd; + simd.s = _mm512_setzero_epi32(); + + return simd; +} + +inline int32_4 operator+(int32_4 a, int32_4 b) +{ + int32_4 simd; + simd.s = _mm_add_epi32(a.s, b.s); + + return simd; +} + +inline int32_8 operator+(int32_8 a, int32_8 b) +{ + int32_8 simd; + simd.s = _mm256_add_epi32(a.s, b.s); + + return simd; +} + +inline int32_16 operator+(int32_16 a, int32_16 b) +{ + int32_16 simd; + simd.s = _mm512_add_epi32(a.s, b.s); + + return simd; +} + +inline int32_4 operator-(int32_4 a, int32_4 b) +{ + int32_4 simd; + simd.s = _mm_sub_epi32(a.s, b.s); + + return simd; +} + +inline int32_4 operator-(int32_4 a) { return init_zero_int32_4() - a; } + +inline int32_8 operator-(int32_8 a, int32_8 b) +{ + int32_8 simd; + simd.s = _mm256_sub_epi32(a.s, b.s); + + return simd; +} + +inline int32_8 operator-(int32_8 a) { return init_zero_int32_8() - a; } + +inline int32_16 operator-(int32_16 a, int32_16 b) +{ + int32_16 simd; + simd.s = _mm512_sub_epi32(a.s, b.s); + + return simd; +} + +inline int32_16 operator-(int32_16 a) { return init_zero_int32_16() - a; } + +inline int32_4 operator*(int32_4 a, int32_4 b) +{ + int32_4 simd; + simd.s = _mm_mul_epi32(a.s, b.s); + + return simd; +} + +inline int32_8 operator*(int32_8 a, int32_8 b) +{ + int32_8 simd; + simd.s = _mm256_mul_epi32(a.s, b.s); + + return simd; +} + +inline int32_16 operator*(int32_16 a, int32_16 b) +{ + int32_16 simd; + simd.s = _mm512_mul_epi32(a.s, b.s); + + return simd; +} + +inline f32_4 operator/(int32_4 a, int32_4 b) +{ + f32_4 simd; + simd.s = _mm_div_ps(_mm_cvtepi32_ps(a.s), _mm_cvtepi32_ps(b.s)); + + return simd; +} + +inline f32_8 operator/(int32_8 a, int32_8 b) +{ + f32_8 simd; + simd.s = _mm256_div_ps(_mm256_cvtepi32_ps(a.s), _mm256_cvtepi32_ps(b.s)); + + return simd; +} + +inline f32_16 operator/(int32_16 a, int32_16 b) +{ + f32_16 simd; + simd.s = _mm512_div_ps(_mm512_cvtepi32_ps(a.s), _mm512_cvtepi32_ps(b.s)); + + return simd; +} + +inline int32_4 operator^(int32_4 a, int32_4 b) +{ + int32_4 simd; + simd.s = _mm_xor_epi32(a.s, b.s); + + return simd; +} + +inline int32_8 operator^(int32_8 a, int32_8 b) +{ + int32_8 simd; + simd.s = _mm256_xor_epi32(a.s, b.s); + + return simd; +} + +inline int32_16 operator^(int32_16 a, int32_16 b) +{ + int32_16 simd; + simd.s = _mm512_xor_epi32(a.s, b.s); + + return simd; +} + +inline int32_4 &operator-=(int32_4 &a, int32_4 b) +{ + a = a - b; + + return a; +} + +inline int32_8 &operator-=(int32_8 &a, int32_8 b) +{ + a = a - b; + + return a; +} + +inline int32_16 &operator-=(int32_16 &a, int32_16 b) +{ + a = a - b; + + return a; +} + +inline int32_4 &operator+=(int32_4 &a, int32_4 b) +{ + a = a + b; + + return a; +} + +inline int32_8 &operator+=(int32_8 &a, int32_8 b) +{ + a = a + b; + + return a; +} + +inline int32_16 &operator+=(int32_16 &a, int32_16 b) +{ + a = a + b; + + return a; +} + +inline int32_4 &operator*=(int32_4 &a, int32_4 b) +{ + a = a * b; + + return a; +} + +inline int32_8 &operator*=(int32_8 &a, int32_8 b) +{ + a = a * b; + + return a; +} + +inline int32_16 &operator*=(int32_16 &a, int32_16 b) +{ + a = a * b; + + return a; +} + +inline int32_4 &operator/=(int32_4 &a, int32_4 b) +{ + a.s = _mm_cvtps_epi32((a / b).s); + + return a; +} + +inline int32_8 &operator/=(int32_8 &a, int32_8 b) +{ + a.s = _mm256_cvtps_epi32((a / b).s); + + return a; +} + +inline int32_16 &operator/=(int32_16 &a, int32_16 b) +{ + a.s = _mm512_cvtps_epi32((a / b).s); + + return a; +} + +inline int32_4 &operator^=(int32_4 &a, int32_4 b) +{ + a = a ^ b; + + return a; +} + +inline int32_8 &operator^=(int32_8 &a, int32_8 b) +{ + a = a ^ b; + + return a; +} + +inline int32_16 &operator^=(int32_16 &a, int32_16 b) +{ + a = a ^ b; + + return a; +} + +inline int32_4 operator<(int32_4 a, int32_4 b) +{ + int32_4 simd; + simd.s = _mm_cmplt_epi32(a.s, b.s); + + return simd; +} + +inline int32_8 operator<(int32_8 a, int32_8 b) +{ + int32_8 simd; + simd.s = _mm256_xor_si256(_mm256_cmpgt_epi32(a.s, b.s), _mm256_set1_epi32(-1)); + + return simd; +} + +inline int32_16 operator<(int32_16 a, int32_16 b) +{ + int32_16 simd; + simd.s = _mm512_mask_blend_epi32(_mm512_cmplt_epi32_mask(a.s, b.s), a.s, b.s); + + return simd; +} + +inline int32_4 operator<=(int32_4 a, int32_4 b) +{ + int32_4 simd; + simd.s = _mm_andnot_si128(_mm_cmplt_epi32(b.s, a.s), _mm_set1_epi32(-1)); + + return simd; +} + +inline int32_8 operator<=(int32_8 a, int32_8 b) +{ + int32_8 simd; + simd.s = _mm256_andnot_si256(_mm256_cmpgt_epi32(a.s, b.s), _mm256_set1_epi32(-1)); + + return simd; +} + +inline int32_16 operator<=(int32_16 a, int32_16 b) +{ + int32_16 simd; + simd.s = _mm512_mask_blend_epi32(_mm512_knot(_mm512_cmpgt_epi32_mask(b.s, a.s)), b.s, a.s); + + return simd; +} + +inline int32_4 operator>(int32_4 a, int32_4 b) +{ + int32_4 simd; + simd.s = _mm_cmpgt_epi32(a.s, b.s); + + return simd; +} + +inline int32_8 operator>(int32_8 a, int32_8 b) +{ + int32_8 simd; + simd.s = _mm256_cmpgt_epi32(a.s, b.s); + + return simd; +} + +inline int32_16 operator>(int32_16 a, int32_16 b) +{ + int32_16 simd; + simd.s = _mm512_mask_blend_epi32(_mm512_cmpgt_epi32_mask(a.s, b.s), a.s, b.s); + + return simd; +} + +inline int32_4 operator>=(int32_4 a, int32_4 b) +{ + int32_4 simd; + simd.s = _mm_andnot_si128(_mm_cmplt_epi32(a.s, b.s), _mm_set1_epi32(-1)); + + return simd; +} + +inline int32_8 operator>=(int32_8 a, int32_8 b) +{ + int32_8 simd; + simd.s = _mm256_andnot_si256(_mm256_cmpgt_epi32(b.s, a.s), _mm256_set1_epi32(-1)); + + return simd; +} + +inline int32_16 operator>=(int32_16 a, int32_16 b) +{ + int32_16 simd; + simd.s = _mm512_mask_blend_epi32(_mm512_cmpge_epi32_mask(a.s, b.s), a.s, b.s); + + return simd; +} + +inline int32_4 operator==(int32_4 a, int32_4 b) +{ + int32_4 simd; + simd.s = _mm_cmpeq_epi32(a.s, b.s); + + return simd; +} + +inline int32_8 operator==(int32_8 a, int32_8 b) +{ + int32_8 simd; + simd.s = _mm256_cmpeq_epi32(a.s, b.s); + + return simd; +} + +inline int32_16 operator==(int32_16 a, int32_16 b) +{ + int32_16 simd; + simd.s = _mm512_mask_blend_epi32(_mm512_cmpeq_epi32_mask(a.s, b.s), a.s, b.s); + + return simd; +} + +inline int32_4 operator!=(int32_4 a, int32_4 b) +{ + int32_4 simd; + simd.s = _mm_andnot_si128(_mm_cmpeq_epi32(a.s, b.s), _mm_set1_epi32(-1)); + + return simd; +} + +inline int32_8 operator!=(int32_8 a, int32_8 b) +{ + int32_8 simd; + simd.s = _mm256_mask_blend_epi32(_mm256_cmp_epi32_mask(a.s, b.s, _MM_CMPINT_NE), a.s, b.s); + + return simd; +} + +inline int32_16 operator!=(int32_16 a, int32_16 b) +{ + int32_16 simd; + simd.s = _mm512_mask_blend_epi32(_mm512_cmp_epi32_mask(a.s, b.s, _MM_CMPINT_NE), a.s, b.s); + + return simd; +} + +inline int32_4 operator&(int32_4 a, int32_4 b) +{ + int32_4 simd; + simd.s = _mm_and_epi32(a.s, b.s); + + return simd; +} + +inline int32_8 operator&(int32_8 a, int32_8 b) +{ + int32_8 simd; + simd.s = _mm256_and_epi32(a.s, b.s); + + return simd; +} + +inline int32_16 operator&(int32_16 a, int32_16 b) +{ + int32_16 simd; + simd.s = _mm512_and_epi32(a.s, b.s); + + return simd; +} + +inline int32_4 operator|(int32_4 a, int32_4 b) +{ + int32_4 simd; + simd.s = _mm_or_epi32(a.s, b.s); + + return simd; +} + +inline int32_8 operator|(int32_8 a, int32_8 b) +{ + int32_8 simd; + simd.s = _mm256_or_epi32(a.s, b.s); + + return simd; +} + +inline int32_16 operator|(int32_16 a, int32_16 b) +{ + int32_16 simd; + simd.s = _mm512_or_epi32(a.s, b.s); + + return simd; +} + +inline int32_4 &operator&=(int32_4 &a, int32_4 b) +{ + a = a & b; + + return a; +} + +inline int32_8 &operator&=(int32_8 &a, int32_8 b) +{ + a = a & b; + + return a; +} + +inline int32_16 &operator&=(int32_16 &a, int32_16 b) +{ + a = a & b; + + return a; +} + +inline int32_4 &operator|=(int32_4 &a, int32_4 b) +{ + a = a | b; + + return a; +} + +inline int32_8 &operator|=(int32_8 &a, int32_8 b) +{ + a = a | b; + + return a; +} + +inline int32_16 &operator|=(int32_16 &a, int32_16 b) +{ + a = a | b; + + return a; +} + +inline int32_4 abs(int32_4 a) +{ + __m128i mask = _mm_set1_epi32(0x7FFFFFFF); + + int32_4 simd; + simd.s = _mm_and_si128(a.s, mask); + + return simd; +} + +inline int32_8 abs(int32_8 a) +{ + __m256i mask = _mm256_set1_epi32(0x7FFFFFFF); + int32_8 simd; + simd.s = _mm256_and_si256(a.s, mask); + + return simd; +} + +inline int32_16 abs(int32_16 a) +{ + __m512i mask = _mm512_set1_epi32(0x7FFFFFFF); + int32_16 simd; + simd.s = _mm512_and_epi32(a.s, mask); + + return simd; +} + +inline int32_4 simd_min(int32_4 a, int32_4 b) +{ + int32_4 simd; + simd.s = _mm_min_epi32(a.s, b.s); + + return simd; +} + +inline int32_8 simd_min(int32_8 a, int32_8 b) +{ + int32_8 simd; + simd.s = _mm256_min_epi32(a.s, b.s); + + return simd; +} + +inline int32_16 simd_min(int32_16 a, int32_16 b) +{ + int32_16 simd; + simd.s = _mm512_min_epi32(a.s, b.s); + + return simd; +} + +inline int32_4 simd_max(int32_4 a, int32_4 b) +{ + int32_4 simd; + simd.s = _mm_max_epi32(a.s, b.s); + + return simd; +} + +inline int32_8 simd_max(int32_8 a, int32_8 b) +{ + int32_8 simd; + simd.s = _mm256_max_epi32(a.s, b.s); + + return simd; +} + +inline int32_16 simd_max(int32_16 a, int32_16 b) +{ + int32_16 simd; + simd.s = _mm512_max_epi32(a.s, b.s); + + return simd; +} + +inline int32_4 sign(int32_4 a) +{ + __m128i mask = _mm_set1_epi32(0x80000000); + __m128i signBit = _mm_and_epi32(a.s, mask); + __m128i b = _mm_set1_epi32(1); + + int32_4 simd; + simd.s = _mm_or_si128(b, signBit); + + return simd; +} + +inline int32_8 sign(int32_8 a) +{ + __m256i mask = _mm256_set1_epi32(0x80000000); + __m256i signBit = _mm256_and_epi32(a.s, mask); + __m256i b = _mm256_set1_epi32(1); + + int32_8 simd; + simd.s = _mm256_or_si256(b, signBit); + + return simd; +} + +inline int32_16 sign(int32_16 a) +{ + __m512i mask = _mm512_set1_epi32(0x80000000); + __m512i signBit = _mm512_and_epi32(a.s, mask); + __m512i b = _mm512_set1_epi32(1); + int32_16 simd; + + simd.s = _mm512_or_si512(b, signBit); + + return simd; +} + +inline f32_4 sqrt(int32_4 a) +{ + f32_4 simd; + simd.s = _mm_sqrt_ps(_mm_cvtepi32_ps(a.s)); + + return simd; +} + +inline f32_8 sqrt(int32_8 a) +{ + f32_8 simd; + simd.s = _mm256_sqrt_ps(_mm256_cvtepi32_ps(a.s)); + + return simd; +} + +inline f32_16 sqrt(int32_16 a) +{ + f32_16 simd; + simd.s = _mm512_sqrt_ps(_mm512_cvtepi32_ps(a.s)); + + return simd; +} + +inline f32_4 sqrt_inv_approx(int32_4 a) +{ + f32_4 simd; + simd.s = _mm_rsqrt_ps(_mm_cvtepi32_ps(a.s)); + + return simd; +} + +inline f32_8 sqrt_inv_approx(int32_8 a) +{ + f32_8 simd; + simd.s = _mm256_rsqrt_ps(_mm256_cvtepi32_ps(a.s)); + + return simd; +} + +inline f32_16 sqrt_inv_approx(int32_16 a) +{ + f32_16 simd; + simd.s = _mm512_rsqrt14_ps(_mm512_cvtepi32_ps(a.s)); + + return simd; +} + +inline f32_4 one_over_approx(int32_4 a) +{ + f32_4 simd; + simd.s = _mm_rcp_ps(_mm_cvtepi32_ps(a.s)); + + return simd; +} + +inline f32_8 one_over_approx(int32_8 a) +{ + f32_8 simd; + simd.s = _mm256_rcp_ps(_mm256_cvtepi32_ps(a.s)); + + return simd; +} + +inline f32_16 one_over_approx(int32_16 a) +{ + f32_16 simd; + simd.s = _mm512_rcp14_ps(_mm512_cvtepi32_ps(a.s)); + + return simd; +} + +inline int32_4 clamp(int32_4 min_value, int32_4 a, int32_4 max_value) +{ + return simd_min(simd_max(a, min_value), max_value); +} + +inline int32_8 clamp(int32_8 min_value, int32_8 a, int32_8 max_value) +{ + return simd_min(simd_max(a, min_value), max_value); +} + +inline int32_16 clamp(int32_16 min_value, int32_16 a, int32_16 max_value) +{ + return simd_min(simd_max(a, min_value), max_value); +} + +inline int32 which_true(int32_4 a) +{ + int32 which_true = _mm_movemask_epi8(a.s); + + return which_true; +} + +inline int32 which_true(int32_8 a) +{ + int32 which_true = _mm256_movemask_epi8(a.s); + + return which_true; +} + +inline int32 which_true(int32_16 a) +{ + int32 which_true = _mm512_movepi32_mask(a.s); + + return which_true; +} + +inline bool any_true(int32_4 a) +{ + bool is_any_true = _mm_movemask_epi8(a.s) > 0; + + return is_any_true; +} + +inline bool any_true(int32_8 a) +{ + bool is_any_true = _mm256_movemask_epi8(a.s) > 0; + + return is_any_true; +} + +inline bool any_true(int32_16 a) +{ + bool is_any_true = _mm512_movepi32_mask(a.s) > 0; + + return is_any_true; +} + +inline bool all_true(int32_4 a) +{ + bool is_true = _mm_movemask_epi8(a.s) == 15; + + return is_true; +} + +inline bool all_true(int32_8 a) +{ + bool is_true = _mm256_movemask_epi8(a.s) == 255; + + return is_true; +} + +inline bool all_true(int32_16 a) +{ + bool is_true = _mm512_movepi32_mask(a.s) == 65535; + + return is_true; +} + +inline bool all_false(int32_4 a) +{ + bool is_false = _mm_movemask_epi8(a.s) == 0; + + return is_false; +} + +inline bool all_false(int32_8 a) +{ + bool is_false = _mm256_movemask_epi8(a.s) == 0; + + return is_false; +} + +inline bool all_false(int32_16 a) +{ + // @todo This can be optimized (requires also changes in the comparison functions return) + bool is_false = _mm512_movepi32_mask(a.s) == 0; + + return is_false; +} + +#endif diff --git a/stdlib/simd/SIMD_I64.h b/stdlib/simd/SIMD_I64.h new file mode 100644 index 0000000..86368dc --- /dev/null +++ b/stdlib/simd/SIMD_I64.h @@ -0,0 +1,39 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_TOS_STDLIB_SIMD_I64_H +#define TOS_TOS_STDLIB_SIMD_I64_H + +#include +#include + +#include "../Types.h" +#include "SIMD_F64.h" + +struct int64_2 { + union { + __m128i s; + int64 v[2]; + }; +}; + +struct int64_4 { + union { + __m256i s; + int64 v[4]; + }; +}; + +struct int64_8 { + union { + __m512i s; + int64 v[8]; + }; +}; + +#endif \ No newline at end of file diff --git a/thread/Thread.h b/thread/Thread.h new file mode 100644 index 0000000..99eff84 --- /dev/null +++ b/thread/Thread.h @@ -0,0 +1,210 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_THREADS_THREAD_H +#define TOS_THREADS_THREAD_H + +#include +#include + +#ifdef _WIN32 + #include +#else + #include + #include +#endif + +#include "ThreadOSWrapper.h" +#include "ThreadJob.h" +#include "ThreadPool.h" + +void thread_create(Worker* worker, ThreadJobFunc routine, void* arg) +{ + for (int i = 0; i < worker->mutex_size; ++i) { + pthread_mutex_init(&worker->mutex[i], NULL); + } + + pthread_cond_init(&worker->condition, NULL); + pthread_create(&worker->thread, NULL, routine, arg); +} + +void thread_stop(Worker* worker) +{ + pthread_join(worker->thread, NULL); + pthread_cond_destroy(&worker->condition); + + for (int i = 0; i < worker->mutex_size; ++i) { + pthread_mutex_destroy(&worker->mutex[i]); + } +} + +ThreadJob *thread_pool_work_poll(ThreadPool *pool) +{ + if (pool == NULL) { + return NULL; + } + + ThreadJob *work = pool->work_first; + if (work == NULL) { + return NULL; + } + + if (work->next == NULL) { + pool->work_first = NULL; + pool->work_last = NULL; + } else { + pool->work_first = work->next; + } + + return work; +} + +#ifdef _WIN32 +static DWORD WINAPI thread_pool_worker(void* arg) +#else +static void* thread_pool_worker(void *arg) +#endif +{ + ThreadPool *pool = (ThreadPool *) arg; + ThreadJob *work; + + while (true) { + pthread_mutex_lock(&pool->work_mutex); + + while (pool->work_first == NULL && !pool->stop) { + pthread_cond_wait(&pool->work_cond, &pool->work_mutex); + } + + if (pool->stop) { + break; + } + + work = thread_pool_work_poll(pool); + ++(pool->working_cnt); + pthread_mutex_unlock(&pool->work_mutex); + + if (work != NULL) { + work->func(work); + } + + pthread_mutex_lock(&pool->work_mutex); + --(pool->working_cnt); + + if (!pool->stop && pool->working_cnt == 0 && pool->work_first == NULL) { + pthread_cond_signal(&pool->working_cond); + } + + pthread_mutex_unlock(&pool->work_mutex); + } + + --(pool->thread_cnt); + pthread_cond_signal(&pool->working_cond); + pthread_mutex_unlock(&pool->work_mutex); + + return NULL; +} + +ThreadPool *thread_pool_create(size_t num, ThreadPool* pool) +{ + pthread_t thread; + size_t i; + + if (num == 0) { + num = 2; + } + + pool->thread_cnt = num; + + // @todo switch from pool mutex and pool cond to threadjob mutex/cond + // thread_pool_wait etc. should just itereate over all mutexes + pthread_mutex_init(&pool->work_mutex, NULL); + pthread_cond_init(&pool->work_cond, NULL); + pthread_cond_init(&pool->working_cond, NULL); + + pool->work_first = NULL; + pool->work_last = NULL; + + for (i = 0; i < num; i++) { + pthread_create(&thread, NULL, thread_pool_worker, pool); + ++(pool->size); + + pthread_detach(thread); + } + + return pool; +} + +void thread_pool_wait(ThreadPool *pool) +{ + if (pool == NULL) { + return; + } + + pthread_mutex_lock(&pool->work_mutex); + + while (true) { + if ((!pool->stop && pool->working_cnt != 0) || (pool->stop && pool->thread_cnt != 0)) { + pthread_cond_wait(&pool->working_cond, &pool->work_mutex); + } else { + break; + } + } + + pthread_mutex_unlock(&pool->work_mutex); +} + +void thread_pool_destroy(ThreadPool *pool) +{ + if (pool == NULL) { + return; + } + + pthread_mutex_lock(&pool->work_mutex); + ThreadJob *work = pool->work_first; + + while (work != NULL) { + work = work->next; + } + + pool->stop = true; + pthread_cond_broadcast(&pool->work_cond); + pthread_mutex_unlock(&pool->work_mutex); + + thread_pool_wait(pool); + + pthread_mutex_destroy(&pool->work_mutex); + pthread_cond_destroy(&pool->work_cond); + pthread_cond_destroy(&pool->working_cond); +} + +ThreadJob* thread_pool_add_work(ThreadPool *pool, ThreadJob* job) +{ + if (pool == NULL) { + return NULL; + } + + if (job == NULL) { + return NULL; + } + + pthread_mutex_lock(&pool->work_mutex); + if (pool->work_first == NULL) { + pool->work_first = job; + pool->work_last = pool->work_first; + } else { + pool->work_last->next = job; + pool->work_last = job; + } + + pthread_cond_broadcast(&pool->work_cond); + pthread_mutex_unlock(&pool->work_mutex); + + return job; +} + +#endif \ No newline at end of file diff --git a/thread/ThreadJob.h b/thread/ThreadJob.h new file mode 100644 index 0000000..43cda5c --- /dev/null +++ b/thread/ThreadJob.h @@ -0,0 +1,44 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_THREADS_JOB_H +#define TOS_THREADS_JOB_H + +#include +#include + +#ifdef _WIN32 + #include + + typedef DWORD (WINAPI *ThreadJobFunc)(void*); +#else + typedef void (*ThreadJobFunc)(void*); +#endif + +#include "ThreadOSWrapper.h" + +struct job_t { + ThreadJobFunc func; + void *arg; + int state; + job_t *next; +}; + +typedef job_t ThreadJob; + +struct Worker { + int index; // @todo When are we using this? + int state; + + pthread_t thread; + pthread_cond_t condition; + int mutex_size; + pthread_mutex_t* mutex; +}; + +#endif \ No newline at end of file diff --git a/thread/ThreadOSWrapper.h b/thread/ThreadOSWrapper.h new file mode 100644 index 0000000..7a1ee96 --- /dev/null +++ b/thread/ThreadOSWrapper.h @@ -0,0 +1,286 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_THREADS_OS_WRAPPER_H +#define TOS_THREADS_OS_WRAPPER_H + +#include "../stdlib/Types.h" + +#ifdef _WIN32 + #include + #include + #include +#else + #include + #include +#endif + +#include "ThreadJob.h" + +void ms_to_timespec(timespec *ts, uint32 ms) +{ + if (ts == 0) { + return; + } + + ts->tv_sec = (ms / 1000) + time(0); + ts->tv_nsec = (ms % 1000) * 1000000; +} + +#ifdef _WIN32 + typedef CRITICAL_SECTION pthread_mutex_t; + typedef void pthread_mutexattr_t; + typedef void pthread_condattr_t; + typedef void pthread_rwlockattr_t; + typedef HANDLE pthread_t; + typedef CONDITION_VARIABLE pthread_cond_t; + + struct pthread_rwlock_t { + SRWLOCK lock; + bool exclusive; + }; + + int pthread_create(pthread_t* thread, void*, ThreadJobFunc start_routine, void* arg) + { + if (thread == NULL || start_routine == NULL) { + return 1; + } + + *thread = CreateThread(NULL, 0, start_routine, arg, 0, NULL); + if (*thread == NULL) { + return 1; + } + + return 0; + } + + int pthread_join(pthread_t thread, void** value_ptr) + { + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + + return 0; + } + + int pthread_detach(pthread_t thread) + { + CloseHandle(thread); + + return 0; + } + + int pthread_mutex_init(pthread_mutex_t* mutex, pthread_mutexattr_t*) + { + if (mutex == NULL) { + return 1; + } + + InitializeCriticalSection(mutex); + + return 0; + } + + int pthread_mutex_destroy(pthread_mutex_t* mutex) + { + if (mutex == NULL) { + return 1; + } + + DeleteCriticalSection(mutex); + + return 0; + } + + int pthread_mutex_lock(pthread_mutex_t* mutex) + { + if (mutex == NULL) { + return 1; + } + + EnterCriticalSection(mutex); + + return 0; + } + + int pthread_mutex_unlock(pthread_mutex_t* mutex) + { + if (mutex == NULL) { + return 1; + } + + LeaveCriticalSection(mutex); + + return 0; + } + + int pthread_cond_init(pthread_cond_t* cond, pthread_condattr_t*) + { + if (cond == NULL) { + return 1; + } + + InitializeConditionVariable(cond); + + return 0; + } + + int pthread_cond_destroy(pthread_cond_t*) + { + /* Windows does not have a destroy for conditionals */ + return 0; + } + + static DWORD timespec_to_ms(const timespec* abstime) + { + if (abstime == NULL) { + return INFINITE; + } + + DWORD t = (DWORD) (((abstime->tv_sec - time(0)) * 1000) + (abstime->tv_nsec / 1000000)); + + return t < 0 ? 1 : t; + } + + int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const timespec* abstime) + { + if (cond == NULL || mutex == NULL) { + return 1; + } + + if (!SleepConditionVariableCS(cond, mutex, timespec_to_ms(abstime))) { + return 1; + } + + return 0; + } + + int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) + { + if (cond == NULL || mutex == NULL) { + return 1; + } + + return pthread_cond_timedwait(cond, mutex, NULL); + } + + int pthread_cond_signal(pthread_cond_t* cond) + { + if (cond == NULL) { + return 1; + } + + WakeConditionVariable(cond); + + return 0; + } + + int pthread_cond_broadcast(pthread_cond_t* cond) + { + if (cond == NULL) { + return 1; + } + + WakeAllConditionVariable(cond); + + return 0; + } + + int pthread_rwlock_init(pthread_rwlock_t* rwlock, const pthread_rwlockattr_t*) + { + if (rwlock == NULL) { + return 1; + } + + InitializeSRWLock(&rwlock->lock); + rwlock->exclusive = false; + + return 0; + } + + int pthread_rwlock_destroy(pthread_rwlock_t* rwlock) + { + return 0; + } + + int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock) + { + if (rwlock == NULL) { + return 1; + } + + AcquireSRWLockShared(&rwlock->lock); + + return 0; + } + + int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock) + { + if (rwlock == NULL) { + return 1; + } + + return !TryAcquireSRWLockShared(&rwlock->lock); + } + + int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock) + { + if (rwlock == NULL) { + return 1; + } + + AcquireSRWLockExclusive(&rwlock->lock); + rwlock->exclusive = true; + + return 0; + } + + int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) + { + if (rwlock == NULL) { + return 1; + } + + BOOLEAN ret = TryAcquireSRWLockExclusive(&rwlock->lock); + if (ret) { + rwlock->exclusive = true; + } + + return ret; + } + + int pthread_rwlock_unlock(pthread_rwlock_t* rwlock) + { + if (rwlock == NULL) { + return 1; + } + + if (rwlock->exclusive) { + rwlock->exclusive = false; + ReleaseSRWLockExclusive(&rwlock->lock); + } else { + ReleaseSRWLockShared(&rwlock->lock); + } + + return 0; + } + + unsigned int pcthread_get_num_procs() + { + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + + return sysinfo.dwNumberOfProcessors; + } +#else + unsigned int pcthread_get_num_procs() + { + return (unsigned int) sysconf(_SC_NPROCESSORS_ONLN); + } +#endif + +#endif \ No newline at end of file diff --git a/thread/ThreadPool.h b/thread/ThreadPool.h new file mode 100644 index 0000000..828d7c2 --- /dev/null +++ b/thread/ThreadPool.h @@ -0,0 +1,41 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_THREADS_THREAD_POOL_H +#define TOS_THREADS_THREAD_POOL_H + +#include +#include + +#ifdef _WIN32 + #include +#else + #include + #include +#endif + +#include "../stdlib/Types.h" +#include "ThreadJob.h" +#include "ThreadOSWrapper.h" + +typedef struct { + ThreadJob *work_first; + ThreadJob *work_last; + + pthread_mutex_t work_mutex; + pthread_cond_t work_cond; + pthread_cond_t working_cond; + + size_t working_cnt; + size_t thread_cnt; + + int32 size; + bool stop; +} ThreadPool; + +#endif \ No newline at end of file diff --git a/utils/BitUtils.h b/utils/BitUtils.h new file mode 100644 index 0000000..03270b0 --- /dev/null +++ b/utils/BitUtils.h @@ -0,0 +1,43 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_UTILS_BIT_H +#define TOS_UTILS_BIT_H + +#include "../stdlib/Types.h" + +uint32 bytes_merge(byte b0, byte b1, byte b2, byte b3) { + uint32 result = 0; + + result |= ((uint32) b0 << 24); + result |= ((uint32) b1 << 16); + result |= ((uint32) b2 << 8); + result |= (uint32) b3; + + return result; +} + +uint64 bytes_merge( + byte b0, byte b1, byte b2, byte b3, + byte b4, byte b5, byte b6, byte b7 +) { + uint64 result = 0; + + result |= ((uint32) b0 << 56); + result |= ((uint32) b1 << 48); + result |= ((uint32) b2 << 40); + result |= ((uint32) b3 << 32); + result |= ((uint32) b4 << 24); + result |= ((uint32) b5 << 16); + result |= ((uint32) b6 << 8); + result |= (uint32) b3; + + return result; +} + +#endif \ No newline at end of file diff --git a/utils/Compiler.h b/utils/Compiler.h new file mode 100644 index 0000000..739b4cd --- /dev/null +++ b/utils/Compiler.h @@ -0,0 +1,31 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_UTILS_COMPILER_H +#define TOS_UTILS_COMPILER_H + +#ifdef _MSC_VER + inline + void* aligned_alloc(size_t alignment, size_t size) { + return _aligned_malloc(size, alignment); + } + + inline + void aligned_free(void* ptr) { + _aligned_free(ptr); + } +#else + #include + + inline + void aligned_free(void* ptr) { + free(ptr); + } +#endif + +#endif diff --git a/utils/EndianUtils.h b/utils/EndianUtils.h new file mode 100644 index 0000000..52b6bff --- /dev/null +++ b/utils/EndianUtils.h @@ -0,0 +1,94 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_UTILS_ENDIAN_H +#define TOS_UTILS_ENDIAN_H + +#include "../stdlib/Types.h" + +// Automatically perform endian swap if necessary +// If we are on little endian (e.g. Win32) we swap big endian data but not little endian +#if _WIN32 || __LITTLE_ENDIAN + #define SWAP_ENDIAN_LITTLE(val) (val) + #define SWAP_ENDIAN_BIG(val) endian_swap(val) +#else + #define SWAP_ENDIAN_LITTLE(val) endian_swap(val) + #define SWAP_ENDIAN_BIG(val) (val) +#endif + +inline +bool is_little_endian() +{ + uint32 num = 1; + + return ((int32) (*(char *) & num)) == 1; +} + +inline +void endian_swap(uint16 *val) +{ + uint16 v = *val; + *val = ((v << 8) | (v >> 8)); +} + +inline +void endian_swap(int16 *val) +{ + uint16 v = (uint16) (*val); + *val = (int16) ((v << 8) | (v >> 8)); +} + +inline +void endian_swap(uint32 *val) +{ + uint32 v = *val; + *val = ((v << 24) + | ((v & 0xFF00) << 8) + | ((v >> 8) & 0xFF00) + | (v >> 24)); +} + +inline +void endian_swap(int32 *val) +{ + uint32 v = (uint32) (*val); + *val = (int32) ((v << 24) + | ((v & 0xFF00) << 8) + | ((v >> 8) & 0xFF00) + | (v >> 24)); +} + +inline +void endian_swap(uint64 *val) +{ + uint64 v = *val; + *val = ((v << 56) + | ((v & 0x000000000000FF00ULL) << 40) + | ((v & 0x0000000000FF0000ULL) << 24) + | ((v & 0x00000000FF000000ULL) << 8) + | ((v & 0x000000FF00000000ULL) >> 8) + | ((v & 0x0000FF0000000000ULL) >> 24) + | ((v & 0x00FF000000000000ULL) >> 40) + | (v >> 56)); +} + +inline +void endian_swap(int64 *val) +{ + uint64 v = (uint64) (*val); + *val = (int64) ((v << 56) + | ((v & 0x000000000000FF00ULL) << 40) + | ((v & 0x0000000000FF0000ULL) << 24) + | ((v & 0x00000000FF000000ULL) << 8) + | ((v & 0x000000FF00000000ULL) >> 8) + | ((v & 0x0000FF0000000000ULL) >> 24) + | ((v & 0x00FF000000000000ULL) >> 40) + | (v >> 56)); +} + +#endif \ No newline at end of file diff --git a/utils/MathUtils.h b/utils/MathUtils.h new file mode 100644 index 0000000..f530234 --- /dev/null +++ b/utils/MathUtils.h @@ -0,0 +1,61 @@ +/** + * Jingga + * + * @package Utils + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_UTILS_MATH_UTILS_H +#define TOS_UTILS_MATH_UTILS_H + +#include "../stdlib/Intrinsics.h" + +#define OMS_PI 3.14159265358979323846f +#define OMS_PI_OVER_TWO OMS_PI / 2.0f +#define OMS_TWO_PI 2 * OMS_PI + +#define OMS_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define OMS_MIN(a, b) ((a) > (b) ? (b) : (a)) +#define OMS_CLAMP(a, b, c) (OMS_MAX(OMS_MIN((a), (b))), (c)) +#define OMS_ABS(a) ((a) > 0 ? (a) : -(a)) +#define OMS_DEG2RAD(angle) ((angle) * OMS_PI / 180.0f) +#define OMS_RAD2DEG(angle) ((angle) * 180.0f / OMS_PI) +#define ROUND_TO_NEAREST(a, b) (((a) + ((b) - 1)) & ~((b) - 1)) + +// @question Consider to implement table based sine wave + approximation if necessary +// [-PI/2, PI/2] +inline +float sin_approx_pih_pih(float x) +{ + return x - (x * x * x / 6.0f); +} + +inline +float sinf_approx(float x) +{ + x = OMS_RAD2DEG(x); + return 4 * x * (180 - x) / (40500 - x * (180 - x)); +} + +inline +float cosf_approx(float x) +{ + return sinf_approx(x + OMS_PI_OVER_TWO); +} + +inline +float tanf_approx(float x) +{ + float sin_x = sinf_approx(x); + float cos_x = cosf_approx(x); + + if (cos_x == 0.0f) { + return (sin_x > 0.0f) ? 1e10f : -1e10f; + } + + return sin_x / cos_x; +} + +#endif diff --git a/utils/RingMemory.h b/utils/RingMemory.h new file mode 100644 index 0000000..be7e8cc --- /dev/null +++ b/utils/RingMemory.h @@ -0,0 +1,86 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_UTILS_RING_MEMORY_H +#define TOS_UTILS_RING_MEMORY_H + +#include "../stdlib/Types.h" +#include "MathUtils.h" +#include "TestUtils.h" + +struct RingMemory { + byte* memory; + + uint64 size; + uint64 pos; + + // The following two indices are only used in special cases such as iterating through a portion + // of the ring memory. In such cases it may be necessary to know where the start and end are. + // Examples for such cases are if a worker thread is pulling data from this ring memory in chunks. + uint64 start; + uint64 end; +}; + +inline +uint64 ring_calculate_position(const RingMemory* ring, uint64 pos, uint64 size, byte aligned = 1) +{ + if (aligned > 1 && ring->pos > 0) { + pos = ROUND_TO_NEAREST(pos, aligned); + } + + size = ROUND_TO_NEAREST(size, aligned); + if (pos + size > ring->size) { + pos = 0; + } + + return pos; +} + +byte* ring_get_memory(RingMemory* ring, uint64 size, byte aligned = 1, bool zeroed = false) +{ + ASSERT_SIMPLE(size <= ring->size); + + if (aligned > 1 && ring->pos > 0) { + ring->pos = ROUND_TO_NEAREST(ring->pos, aligned); + } + + size = ROUND_TO_NEAREST(size, aligned); + if (ring->pos + size > ring->size) { + ring->pos = 0; + } + + byte* offset = (byte *) ring->memory[ring->pos]; + if (zeroed) { + memset((void *) offset, 0, size); + } + + ring->pos += size; + + return offset; +} + +inline +void ring_reset(RingMemory* ring) +{ + ring->pos = 0; +} + +/** + * Checks if one additional element can be inserted without overwriting the start index + */ +inline +bool ring_commit_safe(const RingMemory* ring, uint64 size, byte aligned = 1) +{ + uint64 pos = ring_calculate_position(ring, ring->pos, size, aligned); + + return ring->start < ring->pos + ? ring->start < pos + : pos < ring->start; +} + +#endif \ No newline at end of file diff --git a/utils/StringUtils.h b/utils/StringUtils.h new file mode 100644 index 0000000..a92c225 --- /dev/null +++ b/utils/StringUtils.h @@ -0,0 +1,200 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_UTILS_STRING_UTILS_H +#define TOS_UTILS_STRING_UTILS_H + +#include +#include +#include + +#include "../stdlib/Types.h" +#include "../stdlib/Mathtypes.h" + +inline size_t str_count(const char *str, const char *substr) +{ + size_t l1 = strlen(str); + size_t l2 = strlen(substr); + + if (l2 == 0 || l1 < l2) { + return 0; + } + + size_t count = 0; + for (str = strstr(str, substr); str; str = strstr(str + l2, substr)) { + ++count; + } + + return count; +} + +inline char *strsep(const char **sp, const char *sep) +{ + char *p, *s; + + if (sp == NULL || *sp == NULL || **sp == '\0') { + return (NULL); + } + + s = (char *) *sp; + p = s + strcspn(s, sep); + + if (*p != '\0') { + *p++ = '\0'; + } + + *sp = p; + + return s; +} + +inline void +str_concat( + const char* src1, size_t src1_length, + const char* src2, size_t src2_length, + char* dst +) { + for (size_t i = 0; i < src1_length; ++i) { + *dst++ = *src1++; + } + + for (size_t i = 0; i < src2_length; ++i) { + *dst++ = *src2++; + } + + *dst++ = '\0'; +} + +char *strtok(char *str, const char *delim, char **saveptr) +{ + if (str == NULL) { + str = *saveptr; + } + + if (str == NULL || *str == '\0') { + return NULL; + } + + char *token_start = str; + char *token_end = strpbrk(token_start, delim); + + if (token_end == NULL) { + *saveptr = NULL; + } else { + *token_end = '\0'; + *saveptr = token_end + 1; + } + + return token_start; +} + +inline +void format_number_render(int length, char* buffer, const char thousands = ',') +{ + int count = (int) (length / 3) - (length % 3 == 0 ? 1 : 0); + + int j = -1; + for (int i = length; i > 0; --i) { + ++j; + + if (j % 3 == 0 && j != 0) { + buffer[i + count] = buffer[i]; + --count; + buffer[i + count] = thousands; + } else { + buffer[i + count] = buffer[i]; + } + } +} + +char* format_number(size_t number, char* buffer, const char thousands = ',') +{ + int length = snprintf(buffer, 32, "%zu", number); + format_number_render(length, buffer, thousands); + + return buffer; +} + +char * format_number(int number, char* buffer, const char thousands = ',') +{ + int length = snprintf(buffer, 32, "%i", number); + format_number_render(length, buffer, thousands); + + return buffer; +} + +void create_const_name(const unsigned char *name, unsigned char* modified_name) +{ + // Print block + if (name == NULL) { + modified_name = NULL; + } else { + size_t i; + const size_t length = strlen((const char *) name); + for (i = 0; i < length; ++i) { + modified_name[i] = name[i] == ' ' ? '_' : (unsigned char) toupper(name[i]); + } + + modified_name[i] = '\0'; + } +} + +void font_string_dimension(const char *str, v2_int32* dim, const int* width_lookup) +{ + size_t length = strlen(str); + int width = 0; + + for (int i = 0; i < length; ++i) { + if (str[i] == '\n') { + if (width > dim->x) { + dim->x = width; + } + + width = 0; + ++dim->y; + } + + width += width_lookup[str[i]]; + } + + if (width > dim->x) { + dim->x = width; + } + + if (width > 0) { + ++dim->y; + } +} + +/** + * Custom implementation of strtok_r/strtok_s + */ +char* strtok_(char *str, const char *delim, char **key) { + char *result; + if (str == NULL) { + str = *key; + } + + str += strspn(str, delim); + if (*str == '\0') { + return NULL; + } + + result = str; + str += strcspn(str, delim); + + if (*str) { + *str++ = '\0'; + } + + *key = str; + + return result; +} + +#endif \ No newline at end of file diff --git a/utils/TestUtils.h b/utils/TestUtils.h new file mode 100644 index 0000000..8d5858d --- /dev/null +++ b/utils/TestUtils.h @@ -0,0 +1,182 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_UTILS_TEST_UTILS_H +#define TOS_UTILS_TEST_UTILS_H + +#include +#include "../stdlib/Types.h" + +#define MAX_LOG_LENGTH 128 + +global_persist uint64 performance_count_frequency; +struct TimingStat { + uint64 old_tick_count; + uint64 new_tick_count; + + uint64 delta_tick; + double delta_time; +}; + +struct LogPool { + char* memory; + uint32 pos; + uint32 count; + + // uint32 size = count * MAX_LOG_LENGTH +}; + +#if _WIN32 + inline + void update_timing_stat(TimingStat *stat) + { + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + + stat->new_tick_count = counter.QuadPart; + + // @performance Consider to only do the following two calculations when outputting the tick/time + stat->delta_tick = stat->new_tick_count - stat->old_tick_count; + stat->delta_time = (double) stat->delta_tick / (double) performance_count_frequency; + + stat->old_tick_count = stat->new_tick_count; + } +#else + void update_timing_stat(TimingStat *stat) + { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + stat->new_tick_count = now.tv_sec + now.tv_nsec; + + // @performance Consider to only do the following two calculations when outputting the tick/time + stat->delta_tick = stat->new_tick_count - stat->old_tick_count; + stat->delta_time = (double) stat->delta_tick / (double) performance_count_frequency; + + stat->old_tick_count = stat->new_tick_count; + } +#endif + +#if DEBUG + #define UPDATE_TIMING_STAT(stat) update_timing_stat(stat) +#else + #define UPDATE_TIMING_STAT(stat) ((void)0) +#endif + +void profile_function(const char* func_name, void (*func)(void*), void* data, int iterations) +{ + clock_t start = clock(); + for (int i = 0; i < iterations; ++i) { + func(data); + } + + clock_t end = clock(); + double elapsed_time = (double)(end - start) / CLOCKS_PER_SEC; + + printf("Time taken by %s: %f seconds\n", func_name, elapsed_time); +} + +#define ASSERT_EQUALS(a, b, t1, t2) \ + ({ \ + if ((a) == (b)) { \ + printf("."); \ + } else { \ + printf("\033[31m[F]\033[0m"); \ + printf("\n\n%s - %i: ", __FILE__, __LINE__); \ + printf((t1), (a)); \ + printf(" != "); \ + printf((t2), (b)); \ + printf("\n"); \ + return 0; \ + } \ + }) + +#define ASSERT_NOT_EQUALS(a, b, t1, t2) \ + ({ \ + if ((a) != (b)) { \ + printf("."); \ + } else { \ + printf("\033[31m[F]\033[0m"); \ + printf("\n\n%s - %i: ", __FILE__, __LINE__); \ + printf((t1), (a)); \ + printf(" == "); \ + printf((t2), (b)); \ + printf("\n"); \ + return 0; \ + } \ + }) + +#define ASSERT_EQUALS_WITH_DELTA(a, b, delta, t1, t2) \ + ({ \ + if (OMS_ABS((a) - (b)) <= (delta)) { \ + printf("."); \ + } else { \ + printf("\033[31m[F]\033[0m"); \ + printf("\n\n%s - %i: ", __FILE__, __LINE__); \ + printf((t1), (a)); \ + printf(" != "); \ + printf((t2), (b)); \ + printf("\n"); \ + return 0; \ + } \ + }) + +#define ASSERT_CONTAINS(a, b) \ + ({ \ + if (strstr((a), (b)) != NULL) { \ + printf("."); \ + } else { \ + printf("\033[31m[F]\033[0m"); \ + printf("\n\n%s - %i: ", __FILE__, __LINE__); \ + printf("%s", (a)); \ + printf(" !contains "); \ + printf("%s", (b)); \ + printf("\n"); \ + return 0; \ + } \ + }) + +#if DEBUG + #define ASSERT_SIMPLE(a) \ + if ((a) == false) { \ + *(volatile int *)0 = 0; \ + } +#else + #define ASSERT_SIMPLE(a) ((void)0) +#endif + +#define ASSERT_TRUE(a) \ + ({ \ + if ((a) == true) { \ + printf("."); \ + } else { \ + printf("\033[31m[F]\033[0m"); \ + printf("\n\n%s - %i: ", __FILE__, __LINE__); \ + printf("%d", (a)); \ + printf(" != "); \ + printf("1"); \ + printf("\n"); \ + return 0; \ + } \ + }) + +#define ASSERT_FALSE(a) \ + ({ \ + if ((a) == false) { \ + printf("."); \ + } else { \ + printf("\033[31m[F]\033[0m"); \ + printf("\n\n%s - %i: ", __FILE__, __LINE__); \ + printf("%d", (a)); \ + printf(" != "); \ + printf("1"); \ + printf("\n"); \ + return 0; \ + } \ + }) + +#endif diff --git a/utils/Utils.h b/utils/Utils.h new file mode 100644 index 0000000..f9c4ccf --- /dev/null +++ b/utils/Utils.h @@ -0,0 +1,72 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_UTILS_H +#define TOS_UTILS_H + +#include "../stdlib/Types.h" + +struct file_body { + uint64 size = 0; // doesn't include null termination (same as strlen) + byte* content; +}; + +global_persist uint32 fast_seed; +#define FAST_RAND_MAX 32767 + +inline +uint32 fast_rand(void) { + fast_seed = (214013 * fast_seed + 2531011); + + return (fast_seed >> 16) & 0x7FFF; +} + +inline +f32 fast_rand_percentage(void) { + return (f32) fast_rand() / (f32) FAST_RAND_MAX; +} + +inline +bool is_bit_set(byte data, byte bit) +{ + return (data & (1 << bit)) == 0; +} + +void make_character( + float *data, + float x, float y, float n, float m, char c) +{ + float *d = data; + + // Texture atlas is 16 characters + // 1 / 16 = 0.0625 + float a = 0.0625; + float b = 0.0625 * 2; + + // ascii offset + int w = c - 32; + + float du = (w % 16) * a; + float dv = 1 - (w / 16) * b - b; + + // Quad data (2 triangles) + *(d++) = x - n; *(d++) = y - m; + *(d++) = du + 0; *(d++) = dv; + *(d++) = x + n; *(d++) = y - m; + *(d++) = du + a; *(d++) = dv; + *(d++) = x + n; *(d++) = y + m; + *(d++) = du + a; *(d++) = dv + b; + *(d++) = x - n; *(d++) = y - m; + *(d++) = du + 0; *(d++) = dv; + *(d++) = x + n; *(d++) = y + m; + *(d++) = du + a; *(d++) = dv + b; + *(d++) = x - n; *(d++) = y + m; + *(d++) = du + 0; *(d++) = dv + b; +} + +#endif \ No newline at end of file