diff --git a/assets/atlas.kra b/assets/atlas.kra deleted file mode 100644 index 76039e4..0000000 Binary files a/assets/atlas.kra and /dev/null differ diff --git a/assets/atlas.png b/assets/atlas.png index 0ea3926..0bceb70 100644 Binary files a/assets/atlas.png and b/assets/atlas.png differ diff --git a/assets/bleh.png b/assets/bleh.png deleted file mode 100644 index c656ed5..0000000 Binary files a/assets/bleh.png and /dev/null differ diff --git a/assets/bleh.txt b/assets/bleh.txt deleted file mode 100644 index 35d5689..0000000 --- a/assets/bleh.txt +++ /dev/null @@ -1,256 +0,0 @@ -unsigned char atlas_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x68, - 0x04, 0x03, 0x00, 0x00, 0x01, 0x8b, 0xe2, 0xd8, 0xf0, 0x00, 0x00, 0x00, - 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, - 0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x0f, 0x50, 0x4c, - 0x54, 0x45, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, 0xff, 0xff, 0xff, 0x60, - 0x60, 0x60, 0xff, 0xff, 0xff, 0xb1, 0x03, 0xf0, 0x56, 0x00, 0x00, 0x00, - 0x03, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x00, 0x00, 0xfa, 0x76, 0xc4, 0xde, - 0x00, 0x00, 0x04, 0x90, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xdd, 0x97, - 0x6b, 0x6e, 0x24, 0x39, 0x0e, 0x84, 0x3f, 0x2c, 0xe3, 0x40, 0x1a, 0x48, - 0x07, 0x88, 0x86, 0xe2, 0xfe, 0x67, 0x9a, 0x1f, 0x7a, 0x54, 0x96, 0xdb, - 0x9e, 0x71, 0xf7, 0x0c, 0xb0, 0x8b, 0x15, 0x0a, 0x56, 0xca, 0x4c, 0x8a, - 0xef, 0x20, 0x13, 0xd6, 0x92, 0x4a, 0xd2, 0x7e, 0x24, 0x03, 0x25, 0x5c, - 0x1a, 0xa0, 0x7b, 0x2a, 0x24, 0xe8, 0xad, 0x01, 0x8c, 0xc6, 0x87, 0x4d, - 0xf7, 0x74, 0x56, 0xe8, 0x8c, 0x7b, 0x6a, 0xe0, 0xe7, 0xd5, 0x96, 0xd7, - 0xb3, 0xf1, 0xc4, 0x86, 0x0e, 0x18, 0x72, 0x37, 0xbd, 0x9d, 0x30, 0x20, - 0xfd, 0x20, 0x0a, 0x26, 0x48, 0xb2, 0xa8, 0xbe, 0xf4, 0x77, 0x0d, 0x28, - 0x61, 0x4c, 0x59, 0x83, 0x68, 0x00, 0x46, 0x22, 0xa0, 0xa9, 0x60, 0x14, - 0x81, 0x88, 0x2c, 0x60, 0x30, 0x0a, 0x0d, 0x2c, 0x1d, 0x43, 0x1b, 0x48, - 0x8c, 0x2c, 0x53, 0x04, 0xdc, 0x43, 0x5e, 0x87, 0x24, 0x09, 0xef, 0xaf, - 0x95, 0x1b, 0xed, 0xe9, 0xb1, 0xbb, 0xec, 0x84, 0x24, 0x45, 0x20, 0x4a, - 0x26, 0xbd, 0xab, 0x4d, 0x83, 0xd3, 0x44, 0xb5, 0xeb, 0x8c, 0xbb, 0xd4, - 0xa6, 0x8d, 0xad, 0x06, 0xb4, 0x64, 0x98, 0xc8, 0x4a, 0x90, 0xcb, 0xae, - 0x36, 0x7f, 0x12, 0xc3, 0x34, 0x41, 0xb1, 0x82, 0xf1, 0x72, 0x8b, 0xbc, - 0x7e, 0x11, 0xc1, 0xc1, 0x3f, 0x29, 0x87, 0x83, 0x86, 0x20, 0xd0, 0x70, - 0x43, 0x4d, 0x06, 0x44, 0x68, 0xc8, 0x22, 0xa1, 0xf7, 0xf3, 0x36, 0x70, - 0x52, 0xe4, 0xeb, 0x43, 0xde, 0x28, 0xbe, 0x87, 0xed, 0xb7, 0x4d, 0xd1, - 0xdf, 0xdc, 0xf6, 0xca, 0x90, 0x27, 0x09, 0x40, 0x2b, 0x3b, 0x34, 0x96, - 0x9e, 0x52, 0x92, 0x95, 0x27, 0xf1, 0x8a, 0x79, 0x8c, 0x82, 0x95, 0x44, - 0x82, 0xea, 0xbd, 0xcb, 0x9a, 0xe2, 0x79, 0xf1, 0x89, 0xf8, 0x7b, 0xda, - 0x86, 0x4a, 0x5c, 0x49, 0x5b, 0x72, 0x02, 0xcc, 0x6e, 0xf5, 0x0c, 0x1d, - 0x79, 0x2e, 0xa9, 0x2c, 0x90, 0xad, 0xf4, 0x29, 0x64, 0xa5, 0xa6, 0xba, - 0xd0, 0x75, 0xb2, 0xe6, 0x8e, 0xc0, 0x6c, 0xc8, 0x5b, 0xee, 0xd3, 0x0e, - 0xdf, 0xbf, 0x1d, 0x35, 0x8e, 0x6b, 0xa4, 0xc4, 0x4a, 0x82, 0x62, 0xe4, - 0x4c, 0x05, 0xdd, 0x12, 0x78, 0xfa, 0x4e, 0xb1, 0x25, 0x1b, 0xd2, 0x88, - 0xa9, 0x75, 0x71, 0x01, 0xdd, 0x30, 0x0d, 0x0c, 0x98, 0x60, 0x0c, 0x95, - 0x86, 0x68, 0x35, 0xa7, 0x35, 0x66, 0x23, 0x6d, 0x11, 0x14, 0x50, 0x2d, - 0x76, 0xcd, 0x55, 0x6d, 0x8a, 0x02, 0xd5, 0x3f, 0x3a, 0x08, 0x45, 0x66, - 0x24, 0x69, 0x0f, 0xf7, 0x5d, 0x9f, 0x1e, 0x02, 0xbf, 0x4b, 0x58, 0xe6, - 0x7c, 0x24, 0xe4, 0xae, 0x9f, 0x39, 0xbc, 0xca, 0xf9, 0x13, 0x19, 0xd7, - 0xd9, 0x5f, 0x0a, 0xaf, 0xc4, 0x9f, 0x12, 0x28, 0xf3, 0xa9, 0x81, 0x5f, - 0xaf, 0x67, 0x68, 0xb3, 0xe2, 0xad, 0x4e, 0x43, 0xc8, 0xc9, 0x0f, 0x6f, - 0x2b, 0x8c, 0x1a, 0x4a, 0x37, 0xc6, 0x5e, 0xff, 0x60, 0x21, 0xef, 0xda, - 0x8d, 0x85, 0x93, 0x78, 0x0a, 0xfa, 0xe8, 0x8d, 0x61, 0xe4, 0x95, 0xf5, - 0x4e, 0xe6, 0xaa, 0xee, 0xde, 0x18, 0xc7, 0x76, 0x59, 0x8c, 0xfc, 0xb8, - 0x6a, 0x86, 0xe3, 0x94, 0x6f, 0x28, 0xce, 0x85, 0x31, 0x3d, 0x6c, 0x51, - 0xd2, 0x2a, 0x2b, 0xaf, 0x88, 0x81, 0x61, 0xd4, 0x87, 0x01, 0x0b, 0x99, - 0xe1, 0xcd, 0xd5, 0x07, 0xb3, 0x4f, 0xaf, 0x6a, 0xb7, 0xdd, 0x64, 0xab, - 0x19, 0x87, 0xe1, 0xd1, 0x27, 0xd0, 0x2c, 0x6c, 0x69, 0xc5, 0x50, 0x32, - 0x63, 0x76, 0x83, 0x3c, 0x5c, 0xc6, 0xdd, 0xab, 0x72, 0x32, 0xd1, 0x1c, - 0x14, 0x43, 0xf2, 0xe8, 0x2f, 0x80, 0x65, 0x29, 0x00, 0x32, 0xe3, 0x59, - 0x51, 0x7f, 0x15, 0x0f, 0x9f, 0xaa, 0xb9, 0xf7, 0x54, 0x43, 0x1e, 0xbb, - 0xa7, 0x40, 0x76, 0xbd, 0xc3, 0x68, 0x04, 0x6c, 0x16, 0x57, 0x56, 0x0d, - 0x9a, 0x9a, 0x2c, 0x82, 0xee, 0x55, 0xf6, 0xe9, 0x77, 0x83, 0x38, 0xbe, - 0x3a, 0xda, 0xaf, 0xb2, 0x0f, 0x0b, 0x8c, 0xe2, 0x0d, 0xca, 0x47, 0xdb, - 0x38, 0xce, 0x0e, 0x67, 0xa8, 0xfc, 0x8c, 0x41, 0x6f, 0x21, 0x39, 0x5d, - 0xa9, 0xed, 0x72, 0x5e, 0xc5, 0xb9, 0x6c, 0x09, 0x10, 0x6b, 0x42, 0xcd, - 0xa5, 0x94, 0x88, 0x77, 0x67, 0x12, 0x35, 0xa7, 0xc7, 0x98, 0x30, 0x59, - 0x1c, 0x95, 0x79, 0x10, 0xa7, 0x39, 0x41, 0x99, 0xa7, 0x3e, 0x8e, 0x0e, - 0xad, 0x65, 0x0e, 0x90, 0x97, 0x65, 0xba, 0x39, 0xdd, 0x56, 0x22, 0x0c, - 0xb6, 0xc9, 0xfd, 0x13, 0x87, 0x5b, 0xa6, 0xf7, 0xde, 0x3f, 0xb1, 0x01, - 0x92, 0xcc, 0xff, 0x19, 0x42, 0xfc, 0x39, 0x21, 0xba, 0x15, 0xf4, 0x4e, - 0xf0, 0xc5, 0xf5, 0x27, 0xe1, 0xa2, 0x92, 0xbf, 0x4b, 0xf8, 0xf2, 0xaa, - 0xbf, 0x12, 0xfe, 0xa5, 0xba, 0xff, 0xc4, 0x25, 0x7a, 0x87, 0xc4, 0xc7, - 0xe4, 0xf2, 0xce, 0xf0, 0x20, 0xa8, 0x7d, 0x41, 0x78, 0x07, 0x3f, 0x3e, - 0x01, 0xd4, 0x31, 0xef, 0x64, 0x70, 0x5a, 0x78, 0x4c, 0x25, 0xc9, 0x1f, - 0x2f, 0x8c, 0x46, 0xc7, 0x67, 0xfb, 0xc2, 0xae, 0x05, 0x8b, 0x64, 0x41, - 0xa4, 0x92, 0x64, 0xc6, 0x0b, 0xa0, 0x59, 0xe7, 0xc5, 0xb1, 0x7b, 0xa2, - 0x56, 0x93, 0x90, 0x51, 0x90, 0xcf, 0x0b, 0x6b, 0x12, 0x82, 0xea, 0x23, - 0x99, 0xbd, 0xbd, 0x33, 0x4c, 0xd0, 0xae, 0xd1, 0xc3, 0x50, 0xd9, 0xda, - 0x56, 0xef, 0xbd, 0x37, 0x60, 0x58, 0x73, 0x69, 0xb2, 0x8d, 0xc9, 0x02, - 0xda, 0x24, 0xf9, 0x21, 0x33, 0x96, 0xdf, 0xaa, 0xaa, 0x7a, 0x15, 0x8a, - 0x41, 0xf1, 0xcb, 0x68, 0x76, 0xff, 0x7a, 0xcc, 0xc8, 0xbb, 0xd7, 0x54, - 0xb1, 0xba, 0x33, 0x95, 0x46, 0xf8, 0xc7, 0xab, 0x3e, 0x04, 0xf7, 0x9e, - 0xef, 0x8c, 0x96, 0x0f, 0x4d, 0x7d, 0x25, 0xd9, 0x64, 0x4d, 0x0c, 0x23, - 0x1f, 0xd3, 0x60, 0x07, 0xb2, 0x92, 0xa4, 0x51, 0xe9, 0x7d, 0x24, 0x6d, - 0x8f, 0x6a, 0x54, 0x76, 0x42, 0x79, 0xb4, 0x9a, 0x82, 0x35, 0x78, 0x42, - 0xcd, 0x31, 0xe6, 0x1c, 0x4d, 0xb3, 0x8f, 0xf4, 0xe1, 0xc3, 0x70, 0xe2, - 0x13, 0x5b, 0xa7, 0x2d, 0x24, 0x09, 0x65, 0xb5, 0xb2, 0x9a, 0xa6, 0x02, - 0x87, 0xe1, 0x11, 0x1f, 0x4f, 0x18, 0xb2, 0xcc, 0x98, 0xc8, 0x50, 0x73, - 0x81, 0x71, 0xd2, 0x7b, 0x5f, 0x83, 0xa0, 0xc6, 0x34, 0x09, 0xd5, 0x97, - 0x4f, 0xcf, 0xa4, 0xee, 0x8f, 0x1d, 0x62, 0xcf, 0x13, 0x4d, 0xad, 0x4c, - 0x4f, 0x12, 0xda, 0x6e, 0xc2, 0xbc, 0xf6, 0x6f, 0x34, 0x4f, 0xbf, 0xef, - 0x5b, 0xa4, 0x9c, 0xdd, 0xb7, 0xd7, 0xfe, 0x1c, 0xc0, 0x6f, 0xf5, 0xf4, - 0xc6, 0xc9, 0xfb, 0x3d, 0x00, 0x9c, 0x79, 0xc6, 0x3c, 0xe5, 0x6f, 0x2c, - 0x56, 0xeb, 0xed, 0x26, 0x97, 0x80, 0xb1, 0x18, 0x9f, 0xb8, 0xf3, 0x78, - 0x40, 0xab, 0x1b, 0xe4, 0xe2, 0x88, 0x32, 0xce, 0x88, 0x75, 0x24, 0xec, - 0xd4, 0xd6, 0x7e, 0x7f, 0x00, 0x4a, 0x23, 0xda, 0x83, 0x28, 0x9c, 0x31, - 0xc3, 0xbb, 0x0b, 0x5a, 0x7e, 0x7d, 0x21, 0x8d, 0x2d, 0xdb, 0xbb, 0x84, - 0x6f, 0x47, 0x7c, 0x39, 0x70, 0x4b, 0x58, 0x4a, 0x8c, 0xfb, 0xf4, 0x60, - 0xf0, 0xc3, 0x81, 0x3a, 0x36, 0x18, 0xa8, 0x61, 0xfe, 0xc5, 0x55, 0x79, - 0x9b, 0xfd, 0xeb, 0x60, 0xc7, 0x09, 0x5d, 0xdf, 0x65, 0x3f, 0x97, 0xf7, - 0xe6, 0xca, 0x9d, 0xca, 0x3c, 0xde, 0x3b, 0x1f, 0x56, 0xdb, 0xb6, 0xbe, - 0x01, 0x56, 0x64, 0xc2, 0x29, 0xbb, 0xd1, 0xe7, 0xe8, 0x2f, 0xc7, 0x3f, - 0x6c, 0x6b, 0xc9, 0xdc, 0x5f, 0x8a, 0x35, 0xa1, 0xa7, 0xa7, 0x6f, 0x14, - 0x19, 0xde, 0x05, 0xf6, 0x3e, 0x1f, 0xfb, 0xbc, 0x2f, 0x80, 0xde, 0x7b, - 0xef, 0x1d, 0x91, 0xcc, 0x6c, 0x8d, 0xbd, 0x5d, 0xbd, 0x20, 0x69, 0xa7, - 0xfb, 0xc9, 0x8a, 0x06, 0x45, 0x21, 0xab, 0x4f, 0xf3, 0x48, 0x83, 0x3d, - 0xe1, 0x40, 0x66, 0x2f, 0x1a, 0x63, 0xab, 0xba, 0x25, 0x40, 0x65, 0xb9, - 0x7e, 0xe1, 0xfe, 0x83, 0xe1, 0x17, 0x57, 0xdf, 0xab, 0x7d, 0xf1, 0xd1, - 0xc5, 0xc7, 0x4b, 0xc7, 0xca, 0xde, 0xf9, 0xdb, 0x0c, 0xfc, 0xff, 0x31, - 0xdc, 0x46, 0xf7, 0x4d, 0x06, 0x99, 0xf8, 0x3f, 0xf9, 0x3e, 0xc3, 0x6a, - 0x01, 0x6f, 0x18, 0xf9, 0x15, 0x43, 0x7e, 0x5e, 0xfe, 0x77, 0x25, 0xfc, - 0xa6, 0x0d, 0xbf, 0xec, 0xa5, 0xff, 0x4a, 0xa4, 0x6b, 0x31, 0xb4, 0x6f, - 0x33, 0x9c, 0xb6, 0xfb, 0xed, 0x7a, 0x38, 0x1d, 0xe8, 0x17, 0x18, 0xa8, - 0xe7, 0xf7, 0x6e, 0xfb, 0x9b, 0x92, 0xfe, 0x13, 0xdc, 0x2c, 0x81, 0x38, - 0xc8, 0xfa, 0xf8, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, - 0xae, 0x42, 0x60, 0x82 -}; -unsigned int atlas_png_len = 1288; -unsigned char atlas_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x68, - 0x08, 0x06, 0x00, 0x00, 0x00, 0x0e, 0xcb, 0xf5, 0x55, 0x00, 0x00, 0x00, - 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, - 0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x06, 0x52, 0x49, 0x44, - 0x41, 0x54, 0x78, 0xda, 0xed, 0x5d, 0x8b, 0x4e, 0xeb, 0x30, 0x0c, 0x65, - 0xd5, 0x3e, 0x14, 0xbe, 0x0c, 0xfe, 0x74, 0x97, 0x4a, 0x04, 0x05, 0x5f, - 0x3f, 0x8e, 0x1d, 0xa7, 0xe9, 0x56, 0x5b, 0x42, 0x6c, 0xb4, 0x69, 0x52, - 0x1f, 0xbf, 0xf3, 0xe0, 0xed, 0xad, 0xe8, 0x9c, 0xf4, 0x20, 0xf4, 0xcc, - 0xef, 0x10, 0x69, 0xfb, 0xfe, 0xfe, 0xfe, 0xfb, 0xee, 0xfb, 0xe7, 0x99, - 0x7d, 0xa9, 0x8c, 0x7f, 0x46, 0x20, 0x32, 0xc6, 0xee, 0x6d, 0xdb, 0x83, - 0xd5, 0xc0, 0x93, 0x80, 0x13, 0x01, 0xd5, 0x3a, 0xd4, 0xae, 0xf5, 0xd2, - 0x22, 0xd1, 0xcf, 0xc0, 0x86, 0x24, 0xd1, 0x62, 0xea, 0x03, 0xa4, 0x19, - 0x00, 0x34, 0xc6, 0x5b, 0xbc, 0x6a, 0xd7, 0xdd, 0x2a, 0x94, 0xf1, 0xe2, - 0x3b, 0x00, 0xfb, 0xcf, 0x08, 0x23, 0xb8, 0x71, 0x3c, 0x82, 0x34, 0xcb, - 0x04, 0x71, 0xc2, 0x47, 0x9f, 0xe9, 0x02, 0x20, 0x4b, 0xf2, 0xa8, 0x34, - 0xa3, 0xd2, 0x3f, 0x0a, 0x52, 0x54, 0x13, 0x22, 0x82, 0x82, 0x8e, 0xa7, - 0xb5, 0xbb, 0xf5, 0x2a, 0x71, 0xfb, 0x26, 0x4d, 0x5d, 0xda, 0x75, 0x7a, - 0x7f, 0xd4, 0x37, 0x70, 0xfd, 0x71, 0x7d, 0x5b, 0xf7, 0xa9, 0xaa, 0x1d, - 0xe8, 0x37, 0xd2, 0x7f, 0x7f, 0x2f, 0x32, 0x8e, 0xf6, 0x4c, 0x15, 0x00, - 0x8e, 0xf9, 0x33, 0x00, 0xb0, 0xfa, 0xb7, 0x18, 0x40, 0x4d, 0xc4, 0xe7, - 0xe7, 0x27, 0x7b, 0xdf, 0xc7, 0xc7, 0xc7, 0x9f, 0xef, 0x5f, 0x5f, 0x5f, - 0xb7, 0x15, 0x00, 0xec, 0xe3, 0x68, 0x7d, 0x6f, 0x88, 0x34, 0xa1, 0x12, - 0x33, 0x4a, 0x3d, 0x23, 0xdb, 0x67, 0xca, 0x34, 0x84, 0xf6, 0x36, 0x7d, - 0x3b, 0xfa, 0xdd, 0x6b, 0xfa, 0x50, 0x3f, 0x40, 0xc7, 0x2d, 0xf1, 0xad, - 0x07, 0xde, 0x34, 0x29, 0x9a, 0x59, 0xca, 0xd2, 0x80, 0x7d, 0xd0, 0x4d, - 0x6a, 0x2d, 0xad, 0xf0, 0x68, 0x82, 0x44, 0x9a, 0xe4, 0x6b, 0x63, 0xe9, - 0x25, 0x17, 0xd5, 0x96, 0xfe, 0x79, 0x5c, 0xfb, 0x8d, 0x76, 0xe4, 0x65, - 0xbe, 0x57, 0x32, 0xbd, 0x0c, 0xf1, 0x30, 0xdf, 0x7a, 0x4e, 0x7f, 0x9d, - 0x6a, 0x5b, 0x23, 0xca, 0xfc, 0xfe, 0xf3, 0x7e, 0xcd, 0x13, 0x19, 0xb5, - 0x3e, 0x1b, 0xa9, 0xe3, 0x43, 0x23, 0x84, 0xd1, 0x30, 0x54, 0x7a, 0x06, - 0x17, 0xef, 0x7b, 0xd5, 0x9e, 0xfb, 0xdd, 0xc7, 0xe7, 0xf4, 0x77, 0xf4, - 0xdd, 0x35, 0x1e, 0xa4, 0x65, 0x90, 0x2b, 0x12, 0xb1, 0x8c, 0xac, 0x5b, - 0x03, 0x43, 0x32, 0x53, 0xa7, 0x01, 0xe0, 0x0c, 0xa5, 0x88, 0x8c, 0x7e, - 0x10, 0xa6, 0x47, 0x92, 0x2e, 0xed, 0xbe, 0x74, 0xfe, 0xbc, 0x42, 0x31, - 0xce, 0xe3, 0x98, 0x8b, 0x8a, 0x8a, 0xb2, 0xcd, 0x21, 0xd2, 0x7e, 0x9b, - 0xa5, 0xf6, 0xd1, 0x88, 0xe6, 0x2c, 0xfd, 0xd3, 0x44, 0x2c, 0xc2, 0xfc, - 0x91, 0xf6, 0x87, 0x3b, 0x71, 0x24, 0x92, 0xd2, 0x98, 0xd9, 0xd7, 0xe1, - 0x81, 0x68, 0xec, 0x11, 0x79, 0x87, 0x51, 0x1e, 0x1c, 0xca, 0x7c, 0xcf, - 0x35, 0x4f, 0xba, 0x2f, 0x55, 0x48, 0xad, 0x4a, 0xeb, 0x0a, 0x6d, 0x0c, - 0x33, 0x3e, 0xa2, 0xc2, 0x54, 0xc2, 0xe8, 0x8f, 0x25, 0x0d, 0x5e, 0x09, - 0xd3, 0xfa, 0x1f, 0x8d, 0xea, 0xb2, 0x4c, 0xa8, 0x1b, 0x00, 0x54, 0x85, - 0xad, 0xf8, 0xd8, 0x62, 0xbe, 0x14, 0x47, 0x47, 0x01, 0x50, 0x27, 0x3a, - 0x04, 0x93, 0x20, 0xf5, 0xcf, 0x4d, 0x27, 0xd2, 0xbf, 0xa1, 0x02, 0x84, - 0x08, 0x1b, 0x5b, 0xfe, 0x95, 0x6a, 0x36, 0x5c, 0x9d, 0xc4, 0x6a, 0xd7, - 0x97, 0x86, 0xdb, 0x75, 0xee, 0x39, 0xfb, 0x33, 0x3c, 0x75, 0x7a, 0xad, - 0x3c, 0x6e, 0x55, 0x75, 0xa5, 0x62, 0x62, 0x2b, 0x25, 0x73, 0x45, 0xb3, - 0x56, 0x54, 0xeb, 0xcb, 0xcd, 0x5a, 0xe1, 0x50, 0x2b, 0xc2, 0xfd, 0x77, - 0x7f, 0x8f, 0x70, 0xff, 0x99, 0xce, 0x64, 0x49, 0x13, 0xce, 0x92, 0xf4, - 0x73, 0xce, 0x4f, 0x92, 0xd6, 0x11, 0x0d, 0xf0, 0xfa, 0x1d, 0x69, 0xf6, - 0x8a, 0x8b, 0x5e, 0xb8, 0x68, 0xe6, 0x91, 0x48, 0xac, 0xed, 0xa4, 0x1d, - 0xd1, 0x81, 0x71, 0xe0, 0xf4, 0x2a, 0xac, 0x31, 0x5f, 0xb2, 0xd7, 0x1e, - 0x00, 0x90, 0x32, 0x00, 0xe2, 0x90, 0x4f, 0x01, 0x00, 0x32, 0x01, 0x61, - 0x5d, 0xa7, 0x0c, 0x45, 0x0b, 0x77, 0x51, 0x0d, 0xb0, 0x6c, 0x2d, 0x12, - 0x71, 0x49, 0x8c, 0xb6, 0xfc, 0x9c, 0xd5, 0x7e, 0xa8, 0x6e, 0x24, 0xbd, - 0x84, 0x95, 0x54, 0x68, 0x8e, 0x56, 0x32, 0x4b, 0x5e, 0x27, 0xac, 0x45, - 0x31, 0x52, 0xff, 0x5a, 0x9e, 0x70, 0x16, 0x27, 0xbc, 0xd1, 0x09, 0x93, - 0xd6, 0xd1, 0x8d, 0x50, 0x1b, 0x04, 0xe7, 0x68, 0xb9, 0x89, 0x06, 0x6b, - 0x0a, 0xd0, 0x33, 0x09, 0x43, 0xfb, 0x6d, 0xe3, 0xd4, 0x9e, 0x45, 0x1d, - 0xa2, 0xd5, 0x47, 0xbb, 0x7f, 0x7f, 0xd6, 0xfe, 0xfc, 0x7e, 0xf2, 0x65, - 0xff, 0xdc, 0x3b, 0x52, 0xce, 0xd9, 0x7b, 0x26, 0xa8, 0xd4, 0x7b, 0xb5, - 0x50, 0xd4, 0x93, 0x41, 0x6a, 0x0e, 0xd9, 0x93, 0x88, 0x71, 0xa6, 0x8d, - 0x33, 0x8b, 0x52, 0x1f, 0x88, 0x4f, 0x3a, 0x73, 0x69, 0x7d, 0x59, 0x29, - 0x82, 0xfa, 0x18, 0xcd, 0x27, 0x79, 0x4a, 0x11, 0x88, 0x56, 0x3c, 0x6d, - 0x29, 0x62, 0x66, 0x31, 0x2e, 0x23, 0x93, 0xf5, 0x48, 0xfe, 0x28, 0xf3, - 0x5e, 0x65, 0x3e, 0xe5, 0xe5, 0xcb, 0xd1, 0x45, 0x67, 0xa4, 0xa8, 0x09, - 0xe1, 0x12, 0x1c, 0xed, 0x73, 0x76, 0xfb, 0xd9, 0xb5, 0xf7, 0x8c, 0x67, - 0x53, 0x33, 0x78, 0xf3, 0x76, 0x22, 0xd5, 0x5b, 0x46, 0x56, 0xcf, 0x8d, - 0xb6, 0x47, 0x6a, 0x42, 0x99, 0x00, 0x44, 0x9f, 0x4f, 0x85, 0x78, 0x0f, - 0x6b, 0x37, 0x2f, 0xc2, 0x59, 0xd1, 0xc0, 0xa8, 0x34, 0x65, 0x66, 0xd2, - 0xb3, 0x35, 0xa1, 0x59, 0x10, 0xd7, 0xc2, 0x2c, 0x69, 0xe5, 0x58, 0x46, - 0x48, 0x96, 0x0d, 0x80, 0xa7, 0xf6, 0x82, 0x2e, 0x3b, 0xc9, 0xdc, 0xe8, - 0xc1, 0xd5, 0xcb, 0x42, 0x21, 0x93, 0xa7, 0x3c, 0xe1, 0x01, 0x2f, 0x23, - 0xd2, 0x18, 0xdd, 0x1b, 0x30, 0x63, 0x8f, 0x01, 0xb7, 0x27, 0x82, 0x15, - 0x80, 0x68, 0xb6, 0x8b, 0x30, 0x10, 0xd1, 0x80, 0x8c, 0x49, 0xef, 0x15, - 0x00, 0x44, 0x98, 0xaf, 0xee, 0x8e, 0xf1, 0xee, 0x46, 0xf1, 0xdc, 0x4b, - 0xd5, 0x70, 0x86, 0x0f, 0xf0, 0x26, 0x69, 0x52, 0x35, 0x77, 0xf4, 0xdd, - 0x5d, 0xcc, 0x47, 0x6a, 0xe7, 0x11, 0x0d, 0xd0, 0x26, 0x43, 0x66, 0x85, - 0x8e, 0xd1, 0xad, 0x47, 0x99, 0x5b, 0x96, 0xdc, 0xcc, 0xb7, 0x4c, 0x90, - 0xb6, 0xf7, 0x09, 0x51, 0x5f, 0xd4, 0x84, 0x78, 0x19, 0xec, 0xda, 0x81, - 0x98, 0x08, 0x80, 0x37, 0x87, 0x82, 0xf6, 0xb9, 0x69, 0xd5, 0x4a, 0x24, - 0x9a, 0x88, 0xda, 0xc8, 0x55, 0xa9, 0x7d, 0x14, 0x00, 0x14, 0x20, 0x17, - 0xf3, 0x11, 0x67, 0x19, 0xdd, 0x25, 0x99, 0x15, 0x57, 0x67, 0x56, 0x17, - 0x47, 0x7c, 0x80, 0xc7, 0x3f, 0xa0, 0xcc, 0xbf, 0x69, 0x8c, 0x90, 0x36, - 0x9c, 0x69, 0x9b, 0xf9, 0xd0, 0x89, 0x87, 0x3e, 0xfb, 0xb5, 0x32, 0xe1, - 0xc8, 0xf3, 0x2d, 0x60, 0xd1, 0x77, 0x40, 0x33, 0x5f, 0x8e, 0x77, 0x08, - 0x70, 0x5b, 0xa4, 0x51, 0x76, 0xd6, 0x69, 0xf5, 0xdb, 0x66, 0xe5, 0xa4, - 0xef, 0x67, 0xa8, 0x9d, 0xf5, 0x33, 0x76, 0x9e, 0xb1, 0x6d, 0xd2, 0xcb, - 0x8e, 0x48, 0x17, 0x52, 0x60, 0xe3, 0x24, 0x30, 0x52, 0x7c, 0xf3, 0x92, - 0xb4, 0x7b, 0x71, 0xff, 0x5b, 0x64, 0x47, 0xa6, 0x26, 0x28, 0x45, 0x45, - 0xd7, 0xa2, 0x88, 0xb6, 0x6e, 0xcf, 0xf4, 0x82, 0xd6, 0x1a, 0xd0, 0x91, - 0xd2, 0x30, 0xd2, 0xef, 0x0a, 0x80, 0x7e, 0x07, 0x10, 0x5d, 0x1d, 0xcc, - 0x9d, 0x14, 0xe2, 0x79, 0x16, 0x77, 0x0e, 0xcf, 0x08, 0x33, 0xb4, 0xb5, - 0x3d, 0x56, 0xff, 0xa3, 0x0c, 0x0e, 0x8d, 0x7d, 0xe4, 0xc5, 0xb9, 0x75, - 0xa6, 0x68, 0x92, 0xc6, 0xad, 0x4f, 0x8d, 0x68, 0x8a, 0x96, 0x34, 0x66, - 0xd6, 0xbd, 0x34, 0x06, 0x87, 0xf3, 0x18, 0x74, 0x6d, 0xbf, 0x87, 0x19, - 0xd6, 0x20, 0xa3, 0x4c, 0x97, 0x18, 0xcf, 0xad, 0x6a, 0xf3, 0x08, 0x41, - 0x64, 0xee, 0xc3, 0x03, 0xc0, 0xdd, 0x52, 0x55, 0xee, 0xe4, 0x11, 0xe4, - 0x58, 0x80, 0x3e, 0xc1, 0xfa, 0xbe, 0xf7, 0x8f, 0xca, 0x5b, 0xe1, 0x5e, - 0x24, 0x94, 0x6b, 0xcb, 0xc1, 0xe9, 0x12, 0x78, 0xc9, 0xee, 0x6b, 0x63, - 0x88, 0x1e, 0x54, 0x22, 0xdd, 0xeb, 0x3e, 0xff, 0xc2, 0xda, 0x58, 0x81, - 0xda, 0x43, 0xcd, 0x27, 0x58, 0x7d, 0x5a, 0xdf, 0x25, 0xc9, 0x97, 0xc6, - 0x8e, 0xae, 0x09, 0x8a, 0xbc, 0x6b, 0xaa, 0x0f, 0xe0, 0x54, 0x35, 0x83, - 0xf9, 0xd4, 0x27, 0x64, 0x02, 0xe0, 0x3d, 0xad, 0xcb, 0x6b, 0x2e, 0xbd, - 0x66, 0x2b, 0x2d, 0xcc, 0xcb, 0x60, 0x3e, 0x8d, 0x3a, 0xb4, 0x4d, 0x76, - 0xd1, 0x10, 0x12, 0x29, 0x8d, 0x23, 0xa1, 0xe4, 0xc8, 0x7c, 0x72, 0x38, - 0x7b, 0xa6, 0x36, 0x94, 0x2b, 0xc6, 0x35, 0x7b, 0x89, 0x9c, 0x30, 0x15, - 0x5d, 0xb6, 0xe2, 0x7d, 0x39, 0xba, 0xe5, 0x47, 0x3b, 0xbb, 0xa8, 0xad, - 0x76, 0xf6, 0xd8, 0x74, 0xce, 0x07, 0x4a, 0x6d, 0x91, 0x62, 0xa1, 0x5a, - 0xac, 0xd3, 0x54, 0x0f, 0x65, 0x8e, 0x25, 0xf9, 0x23, 0x89, 0x11, 0xbd, - 0x66, 0x1d, 0x37, 0xa3, 0x6d, 0xb7, 0x1a, 0x29, 0x31, 0x7b, 0x35, 0x07, - 0xb9, 0xbe, 0x59, 0x92, 0x8d, 0x46, 0x3c, 0x9c, 0x84, 0x66, 0x2d, 0xb8, - 0xca, 0x2a, 0x86, 0x79, 0xc6, 0x72, 0xd4, 0x91, 0x6d, 0x77, 0x6a, 0x6e, - 0x34, 0x55, 0xf7, 0x4a, 0xcf, 0x51, 0xcc, 0xe7, 0xfa, 0xe9, 0x77, 0x28, - 0x4a, 0x87, 0xf8, 0x21, 0x1a, 0x37, 0xfb, 0x1d, 0xee, 0x9c, 0xcd, 0xef, - 0x6d, 0x67, 0x1b, 0xcc, 0x0e, 0x44, 0xaf, 0x0d, 0x54, 0x33, 0xe8, 0xae, - 0x95, 0x68, 0x2c, 0x9f, 0xe1, 0x23, 0x22, 0x4c, 0xa7, 0xe0, 0x69, 0xe7, - 0xc3, 0x4d, 0x71, 0xc2, 0xda, 0xcb, 0xf6, 0xcc, 0x8f, 0x9a, 0xa4, 0x57, - 0xaf, 0x82, 0x0e, 0x39, 0xe1, 0xa2, 0x75, 0x74, 0xcb, 0x88, 0x6d, 0x47, - 0x34, 0xe2, 0x2c, 0x1a, 0xb5, 0xe2, 0x9c, 0xd4, 0xdf, 0x28, 0xa8, 0x68, - 0x1d, 0xdd, 0xa5, 0xc2, 0x15, 0xea, 0xec, 0x8a, 0x4a, 0x03, 0x0a, 0x80, - 0x55, 0xfe, 0xa3, 0x00, 0x28, 0x2a, 0x00, 0x0a, 0x80, 0xa2, 0x02, 0xa0, - 0x00, 0x28, 0x2a, 0x00, 0x0a, 0x80, 0xa2, 0x78, 0x26, 0x7c, 0x65, 0xd2, - 0xf6, 0xac, 0x1d, 0x51, 0x13, 0xba, 0x17, 0xe3, 0xed, 0x7b, 0x66, 0x02, - 0xb1, 0x5d, 0x9d, 0xf9, 0xdc, 0x34, 0x26, 0xfd, 0xdb, 0xcc, 0x63, 0x10, - 0x2e, 0xed, 0x03, 0x00, 0xc9, 0x9e, 0x6e, 0x82, 0xb6, 0xab, 0x4a, 0x3f, - 0x62, 0x56, 0xf6, 0x5b, 0x46, 0xff, 0x55, 0x57, 0x01, 0x50, 0x51, 0xd0, - 0x7a, 0x67, 0xea, 0x6d, 0x37, 0xb2, 0x09, 0xdc, 0x69, 0xe2, 0x4a, 0x03, - 0x2a, 0x11, 0x2b, 0x13, 0xf4, 0xf2, 0x91, 0x0c, 0xe4, 0x84, 0xb5, 0x49, - 0xf9, 0x99, 0xf9, 0x40, 0x69, 0x40, 0x99, 0xa0, 0x35, 0x1a, 0x03, 0x66, - 0xc2, 0xd3, 0xb3, 0xe1, 0x4b, 0x6b, 0x00, 0x00, 0xc2, 0xf4, 0x83, 0x00, - 0x2f, 0x59, 0x0b, 0xea, 0xd7, 0xc0, 0x22, 0x07, 0x48, 0x1d, 0xb2, 0x3a, - 0xba, 0x4c, 0xd1, 0xb8, 0x83, 0x2f, 0x00, 0x92, 0x80, 0xa8, 0xa5, 0x89, - 0x15, 0x05, 0x15, 0x15, 0x00, 0x05, 0x40, 0x51, 0x01, 0x70, 0x15, 0xf2, - 0x1e, 0x5a, 0x4d, 0x8f, 0xa1, 0x79, 0x95, 0xa4, 0x6c, 0xe9, 0x7f, 0xbc, - 0x88, 0xfe, 0x3f, 0xdf, 0x02, 0xe0, 0x60, 0x10, 0xac, 0x4d, 0xd3, 0x91, - 0x3e, 0xaf, 0x0c, 0xc0, 0x1f, 0x1f, 0xd0, 0xfe, 0x89, 0x99, 0x44, 0x47, - 0x6d, 0xdd, 0xbc, 0xb4, 0x13, 0x96, 0x40, 0x28, 0xe6, 0x1f, 0x18, 0x05, - 0x51, 0x10, 0x8a, 0xf9, 0xf3, 0x48, 0xac, 0x05, 0xfd, 0x30, 0xfc, 0xd1, - 0x7d, 0x7e, 0x69, 0x5a, 0xb5, 0x71, 0xfa, 0x1f, 0xcc, 0xd3, 0x69, 0xcc, - 0x40, 0x9f, 0x7b, 0x52, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, - 0xae, 0x42, 0x60, 0x82 -}; -unsigned int atlas_png_len = 1696; diff --git a/src/COMMON.h b/src/COMMON.h index f22337c..db49492 100644 --- a/src/COMMON.h +++ b/src/COMMON.h @@ -55,6 +55,16 @@ using namespace glm; #define INDEX_NONE -1 #define TIME_NONE -1.0f +#if defined(_WIN32) + #define POPEN _popen + #define PCLOSE _pclose + #define PWRITE_MODE "wb" +#else + #define POPEN popen + #define PCLOSE pclose + #define PWRITE_MODE "w" +#endif + #define UV_VERTICES(uvMin, uvMax) \ { \ 0, 0, uvMin.x, uvMin.y, \ @@ -120,6 +130,41 @@ static inline void working_directory_from_file_set(const std::string& path) std::filesystem::current_path(parentPath); }; +static inline std::string path_extension_change(const std::string& path, const std::string& extension) +{ + std::filesystem::path filePath(path); + filePath.replace_extension(extension); + return filePath.string(); +} + +static inline bool path_exists(const std::filesystem::path& pathCheck) +{ + std::error_code errorCode; + return std::filesystem::exists(pathCheck, errorCode) && ((void)std::filesystem::status(pathCheck, errorCode), !errorCode); +} + +static inline bool path_valid(const std::filesystem::path& pathCheck) +{ + namespace fs = std::filesystem; + std::error_code ec; + + if (fs::is_directory(pathCheck, ec)) return false; + if (fs::exists(pathCheck, ec) && !fs::is_regular_file(pathCheck, ec)) return false; + + fs::path parentDir = pathCheck.has_parent_path() ? pathCheck.parent_path() : fs::path("."); + if (!fs::is_directory(parentDir, ec)) return false; + + bool existedBefore = fs::exists(pathCheck, ec); + std::ofstream testStream(pathCheck, std::ios::app | std::ios::binary); + bool isValid = testStream.is_open(); + testStream.close(); + + if (!existedBefore && isValid) + fs::remove(pathCheck, ec); // cleanup if we created it + + return isValid; +} + static inline const char* enum_to_string(const char* array[], s32 count, s32 index) { return (index >= 0 && index < count) ? array[index] : ""; diff --git a/src/PACKED.h b/src/PACKED.h index e74980b..b826eb1 100644 --- a/src/PACKED.h +++ b/src/PACKED.h @@ -4,271 +4,209 @@ #include "COMMON.h" -const u32 TEXTURE_ATLAS_LENGTH = 1698; const u8 TEXTURE_ATLAS[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x68, - 0x08, 0x06, 0x00, 0x00, 0x00, 0x0e, 0xcb, 0xf5, 0x55, 0x00, 0x00, 0x00, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x78, + 0x04, 0x03, 0x00, 0x00, 0x00, 0xff, 0x33, 0xea, 0xfd, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, - 0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x06, 0x54, 0x49, 0x44, - 0x41, 0x54, 0x78, 0xda, 0xed, 0x5d, 0x8b, 0x4e, 0xeb, 0x30, 0x0c, 0x65, - 0xd5, 0x3e, 0x14, 0xbe, 0x0c, 0xfe, 0x74, 0x97, 0x48, 0x04, 0x05, 0x5f, - 0x3f, 0x8e, 0x1d, 0xa7, 0xed, 0x56, 0x5b, 0x42, 0x6c, 0xb4, 0x69, 0x52, - 0x1f, 0xbf, 0xf3, 0xe0, 0xed, 0xad, 0xe8, 0x9c, 0xf4, 0x20, 0xf4, 0xcc, - 0xef, 0x10, 0x69, 0xfb, 0xfe, 0xfe, 0xfe, 0xfb, 0xee, 0xed, 0xf3, 0xca, - 0xbe, 0x54, 0xc6, 0x3f, 0x23, 0x10, 0x19, 0x63, 0xf7, 0xb6, 0x1d, 0xc1, - 0xea, 0xe0, 0x49, 0xc0, 0x89, 0x80, 0x6a, 0x1d, 0x6a, 0xd7, 0x46, 0x69, - 0x91, 0xe8, 0x67, 0x60, 0x53, 0x92, 0x68, 0x31, 0xf5, 0x01, 0xd2, 0x0a, - 0x00, 0x3a, 0xe3, 0x2d, 0x5e, 0xf5, 0xeb, 0x6e, 0x15, 0xca, 0x78, 0xf1, - 0x06, 0x40, 0xfb, 0x99, 0x61, 0x04, 0x37, 0x8e, 0x47, 0x90, 0x56, 0x99, - 0x20, 0x4e, 0xf8, 0xe8, 0x33, 0x5d, 0x00, 0x64, 0x49, 0x1e, 0x95, 0x66, - 0x54, 0xfa, 0x67, 0x41, 0x8a, 0x6a, 0x42, 0x44, 0x50, 0xd0, 0xf1, 0xf4, - 0x76, 0xb7, 0x51, 0x25, 0x6e, 0xdf, 0xa4, 0xa9, 0x4b, 0xbf, 0x4e, 0xef, - 0x8f, 0xfa, 0x06, 0xae, 0x3f, 0xae, 0x6f, 0xeb, 0x3e, 0x55, 0xb5, 0x03, - 0xfd, 0x46, 0xfa, 0x1f, 0xef, 0x45, 0xc6, 0xd1, 0x9f, 0xa9, 0x02, 0xc0, - 0x31, 0x7f, 0x05, 0x00, 0x56, 0xff, 0x16, 0x03, 0xa8, 0x89, 0xf8, 0xfc, - 0xfc, 0x64, 0xef, 0xfb, 0xf8, 0xf8, 0xf8, 0xf3, 0xfd, 0xeb, 0xeb, 0xeb, - 0x76, 0x04, 0x00, 0x6d, 0x1c, 0xbd, 0xef, 0x0d, 0x91, 0x26, 0x54, 0x62, - 0x66, 0x69, 0x64, 0x64, 0xff, 0x4c, 0x99, 0x86, 0x50, 0x6b, 0x33, 0xb6, - 0xa3, 0xdf, 0xbd, 0xa6, 0x0f, 0xf5, 0x03, 0x74, 0xdc, 0x12, 0xdf, 0x46, - 0xe0, 0x4d, 0x93, 0xa2, 0x99, 0xa5, 0x2c, 0x0d, 0x68, 0x83, 0xee, 0x52, - 0x6b, 0x69, 0x85, 0x47, 0x13, 0x24, 0xd2, 0x24, 0x5f, 0x1b, 0xcb, 0x28, - 0xb9, 0xa8, 0xb6, 0x8c, 0xcf, 0xe3, 0xda, 0x6f, 0xb4, 0x23, 0x2f, 0xf3, - 0xbd, 0x92, 0xe9, 0x65, 0x88, 0x87, 0xf9, 0xd6, 0x73, 0xc6, 0xeb, 0x54, - 0xdb, 0x3a, 0x51, 0xe6, 0x8f, 0x9f, 0xdb, 0x35, 0x4f, 0x64, 0xd4, 0xfb, - 0xec, 0xa4, 0x8e, 0x0f, 0x8d, 0x10, 0x66, 0xc3, 0x50, 0xe9, 0x19, 0x5c, - 0xbc, 0xef, 0x55, 0x7b, 0xee, 0xf7, 0x18, 0x9f, 0xd3, 0xdf, 0xd1, 0x77, - 0xd7, 0x78, 0x90, 0x96, 0x41, 0x1e, 0x91, 0x88, 0x65, 0x64, 0xdd, 0x1a, - 0x18, 0x92, 0x99, 0x3a, 0x0d, 0x00, 0x67, 0x28, 0x45, 0x64, 0xf4, 0x83, - 0x30, 0x3d, 0x92, 0x74, 0x69, 0xf7, 0xa5, 0xf3, 0xe7, 0x15, 0x8a, 0x71, - 0x1e, 0xc7, 0x5c, 0x54, 0x54, 0x94, 0x6d, 0x0e, 0x91, 0xf6, 0xdb, 0x2a, - 0xb5, 0x8f, 0x46, 0x34, 0x67, 0xe9, 0x9f, 0x26, 0x62, 0x11, 0xe6, 0xcf, - 0xb4, 0xdf, 0xdd, 0x89, 0x23, 0x91, 0x94, 0xc6, 0xcc, 0xb1, 0x0e, 0x0f, - 0x44, 0x63, 0x8f, 0xc8, 0x3b, 0xcc, 0xf2, 0x60, 0x57, 0xe6, 0x7b, 0xae, - 0x79, 0xd2, 0x7d, 0xa9, 0x42, 0x6a, 0x55, 0x5a, 0x8f, 0xd0, 0xc6, 0x30, - 0xe3, 0x23, 0x2a, 0x4c, 0x25, 0x8c, 0xfe, 0x58, 0xd2, 0xe0, 0x95, 0x30, - 0xad, 0xff, 0xd9, 0xa8, 0x2e, 0xcb, 0x84, 0xba, 0x01, 0x40, 0x55, 0xd8, - 0x8a, 0x8f, 0x2d, 0xe6, 0x4b, 0x71, 0x74, 0x14, 0x00, 0x75, 0xa2, 0x43, - 0x30, 0x09, 0x52, 0xff, 0xdc, 0x74, 0x22, 0xfd, 0x1b, 0x2a, 0x40, 0x88, - 0xb0, 0xb1, 0xe5, 0x5f, 0xa9, 0x66, 0xc3, 0xd5, 0x49, 0xac, 0x76, 0x63, - 0x69, 0xb8, 0x5f, 0xe7, 0x9e, 0xd3, 0x9e, 0xe1, 0xa9, 0xd3, 0x6b, 0xe5, - 0x71, 0xab, 0xaa, 0x2b, 0x15, 0x13, 0x7b, 0x29, 0x99, 0x2b, 0x9a, 0xf5, - 0xa2, 0xda, 0x58, 0x6e, 0xd6, 0x0a, 0x87, 0x5a, 0x11, 0xee, 0xbf, 0xfb, - 0x47, 0x84, 0xc7, 0xcf, 0x74, 0x26, 0x4b, 0x9a, 0x70, 0x96, 0xa4, 0x9f, - 0x73, 0x7e, 0x92, 0xb4, 0xce, 0x68, 0x80, 0xd7, 0xef, 0x48, 0xb3, 0x57, - 0x5c, 0xf4, 0xc2, 0x45, 0x33, 0x8f, 0x44, 0x62, 0x6d, 0x27, 0xed, 0x88, - 0x0e, 0x8c, 0x03, 0x67, 0x54, 0x61, 0x8d, 0xf9, 0x92, 0xbd, 0xf6, 0x00, - 0x80, 0x94, 0x01, 0x10, 0x87, 0x7c, 0x0a, 0x00, 0x90, 0x09, 0x08, 0xeb, - 0x3a, 0x65, 0x28, 0x5a, 0xb8, 0x8b, 0x6a, 0x80, 0x65, 0x6b, 0x91, 0x88, - 0x4b, 0x62, 0xb4, 0xe5, 0xe7, 0xac, 0xf6, 0x53, 0x75, 0x23, 0xe9, 0x25, - 0xac, 0xa4, 0x42, 0x73, 0xb4, 0x92, 0x59, 0xf2, 0x3a, 0x61, 0x2d, 0x8a, - 0x91, 0xfa, 0xd7, 0xf2, 0x84, 0xb3, 0x38, 0xe1, 0x8d, 0x4e, 0x98, 0xf4, - 0x8e, 0x6e, 0x84, 0xfa, 0x20, 0x38, 0x47, 0xcb, 0x4d, 0x34, 0x58, 0x53, - 0x80, 0x9e, 0x49, 0x18, 0xda, 0x6f, 0x1f, 0xa7, 0xf6, 0x2c, 0xea, 0x10, - 0xad, 0x3e, 0xfa, 0xfd, 0xed, 0x59, 0xed, 0xf9, 0xe3, 0xe4, 0x4b, 0xfb, - 0x3c, 0x3a, 0x52, 0xce, 0xd9, 0x7b, 0x26, 0xa8, 0xd4, 0x7b, 0xb5, 0x50, - 0xd4, 0x93, 0x41, 0x6a, 0x0e, 0xd9, 0x93, 0x88, 0x71, 0xa6, 0x8d, 0x33, - 0x8b, 0x52, 0x1f, 0x88, 0x4f, 0x3a, 0x73, 0x69, 0xfd, 0xb0, 0x52, 0x04, - 0xf5, 0x31, 0x9a, 0x4f, 0xf2, 0x94, 0x22, 0x10, 0xad, 0x78, 0xda, 0x52, - 0xc4, 0xca, 0x62, 0x5c, 0x46, 0x26, 0xeb, 0x91, 0xfc, 0x59, 0xe6, 0xbd, - 0xca, 0x7c, 0xca, 0xcb, 0x97, 0xa3, 0x8b, 0xce, 0x48, 0x51, 0x13, 0xc2, - 0x25, 0x38, 0xda, 0xe7, 0xec, 0xf6, 0xab, 0x6b, 0xef, 0x19, 0xcf, 0xa6, - 0x66, 0xf0, 0xe6, 0xed, 0x44, 0xaa, 0xb7, 0xcc, 0xac, 0x9e, 0x9b, 0x6d, - 0x8f, 0xd4, 0x84, 0x32, 0x01, 0x88, 0x3e, 0x9f, 0x0a, 0x71, 0x0b, 0x6b, - 0x37, 0x2f, 0xc2, 0x59, 0xd1, 0xc0, 0xac, 0x34, 0x65, 0x66, 0xd2, 0xab, - 0x35, 0xa1, 0x5b, 0x10, 0xd7, 0xc2, 0x2c, 0x69, 0xe5, 0x58, 0x46, 0x48, - 0x96, 0x0d, 0x80, 0xa7, 0xf6, 0x82, 0x2e, 0x3b, 0xc9, 0xdc, 0xe8, 0xc1, - 0xd5, 0xcb, 0x42, 0x21, 0x93, 0xa7, 0x3c, 0xe1, 0x01, 0x2f, 0x23, 0xd2, - 0x98, 0xdd, 0x1b, 0xb0, 0x62, 0x8f, 0x01, 0xb7, 0x27, 0x82, 0x15, 0x80, - 0x68, 0xb6, 0x8b, 0x30, 0x10, 0xd1, 0x80, 0x8c, 0x49, 0xef, 0x23, 0x00, - 0x88, 0x30, 0x5f, 0xdd, 0x1d, 0xe3, 0xdd, 0x8d, 0xe2, 0xb9, 0x97, 0xaa, - 0xe1, 0x0a, 0x1f, 0xe0, 0x4d, 0xd2, 0xa4, 0x6a, 0xee, 0xec, 0xbb, 0xbb, - 0x98, 0x8f, 0xd4, 0xce, 0x23, 0x1a, 0xa0, 0x4d, 0x86, 0xac, 0x0a, 0x1d, - 0xa3, 0x5b, 0x8f, 0x32, 0xb7, 0x2c, 0xb9, 0x99, 0x6f, 0x99, 0x20, 0x6d, - 0xef, 0x13, 0xa2, 0xbe, 0xa8, 0x09, 0xf1, 0x32, 0xd8, 0xb5, 0x03, 0x31, - 0x11, 0x00, 0x6f, 0x0e, 0x05, 0xed, 0x73, 0xd3, 0xaa, 0x95, 0x48, 0x34, - 0x11, 0xb5, 0x91, 0x47, 0xa5, 0xf6, 0x51, 0x00, 0x50, 0x80, 0x5c, 0xcc, - 0x47, 0x9c, 0x65, 0x74, 0x97, 0x64, 0x56, 0x5c, 0x9d, 0x59, 0x5d, 0x9c, - 0xf1, 0x01, 0x1e, 0xff, 0x80, 0x32, 0xff, 0xa6, 0x31, 0x42, 0xda, 0x70, - 0xa6, 0x6d, 0xe6, 0x43, 0x27, 0x1e, 0xc6, 0xec, 0xd7, 0xca, 0x84, 0x23, - 0xcf, 0xb7, 0x80, 0x45, 0xdf, 0x01, 0xcd, 0x7c, 0x39, 0xde, 0x21, 0xc0, - 0x6d, 0x91, 0x46, 0xd9, 0x59, 0xa7, 0xd5, 0x6f, 0x9f, 0x95, 0x93, 0xbe, - 0x9f, 0xa1, 0x76, 0x36, 0xce, 0xd8, 0x79, 0xc6, 0xb6, 0x49, 0x2f, 0x3b, - 0x23, 0x5d, 0x48, 0x81, 0x8d, 0x93, 0xc0, 0x48, 0xf1, 0xcd, 0x4b, 0xd2, - 0xee, 0xc5, 0xf6, 0xb7, 0xc8, 0x8e, 0x4c, 0x4d, 0x50, 0x8a, 0x8a, 0xae, - 0x45, 0x11, 0x6d, 0xdd, 0x9e, 0xe9, 0x05, 0xad, 0x35, 0xa0, 0x33, 0xa5, - 0x61, 0xa4, 0xdf, 0x23, 0x00, 0xfa, 0x1d, 0x40, 0x74, 0x75, 0x30, 0x77, - 0x52, 0x88, 0xe7, 0x59, 0xdc, 0x39, 0x3c, 0x33, 0xcc, 0xd0, 0xd6, 0xf6, - 0x58, 0xfd, 0xcf, 0x32, 0x38, 0x34, 0xf6, 0x99, 0x17, 0xe7, 0xd6, 0x99, - 0xa2, 0x49, 0x1a, 0xb7, 0x3e, 0x35, 0xa2, 0x29, 0x5a, 0xd2, 0x98, 0x59, - 0xf7, 0xd2, 0x18, 0x1c, 0xce, 0x63, 0xd0, 0xb5, 0xfd, 0x1e, 0x66, 0x58, - 0x83, 0x8c, 0x32, 0x5d, 0x62, 0x3c, 0xb7, 0xaa, 0xcd, 0x23, 0x04, 0x91, - 0xb9, 0x0f, 0x0f, 0x00, 0x77, 0x4b, 0x55, 0xb9, 0x93, 0x47, 0x90, 0x63, - 0x01, 0xc6, 0x04, 0xeb, 0xfb, 0xde, 0x3f, 0x2a, 0x6f, 0x85, 0x7b, 0x91, - 0x50, 0xae, 0x2f, 0x07, 0xa7, 0x4b, 0xe0, 0x25, 0xbb, 0xaf, 0x8d, 0x21, - 0x7a, 0x50, 0x89, 0x74, 0xaf, 0xfb, 0xfc, 0x0b, 0x6b, 0x63, 0x05, 0x6a, - 0x0f, 0x35, 0x9f, 0x60, 0xf5, 0x69, 0x7d, 0x97, 0x24, 0x5f, 0x1a, 0x3b, - 0xba, 0x26, 0x28, 0xf2, 0xae, 0xa9, 0x3e, 0x80, 0x53, 0xd5, 0x0c, 0xe6, - 0x53, 0x9f, 0x90, 0x09, 0x80, 0xf7, 0xb4, 0x2e, 0xaf, 0xb9, 0xf4, 0x9a, - 0xad, 0xb4, 0x30, 0x2f, 0x83, 0xf9, 0x34, 0xea, 0xd0, 0x36, 0xd9, 0x45, - 0x43, 0x48, 0xa4, 0x34, 0x8e, 0x84, 0x92, 0x33, 0xf3, 0xc9, 0xe1, 0xec, - 0x99, 0xda, 0x50, 0xae, 0x18, 0xd7, 0xed, 0x25, 0x72, 0xc2, 0x54, 0x74, - 0xd9, 0x8a, 0xf7, 0xe5, 0xe8, 0x96, 0x1f, 0xed, 0xec, 0xa2, 0xbe, 0xda, - 0xd9, 0x63, 0xd3, 0x39, 0x1f, 0x28, 0xb5, 0x45, 0x8a, 0x85, 0x6a, 0xb1, - 0x4e, 0x53, 0x3d, 0x94, 0x39, 0x96, 0xe4, 0xcf, 0x24, 0x46, 0xf4, 0x9a, - 0x75, 0xdc, 0x8c, 0xb6, 0xdd, 0x6a, 0xa6, 0xc4, 0xec, 0xd5, 0x1c, 0xe4, - 0xfa, 0x66, 0x49, 0x36, 0x1a, 0xf1, 0x70, 0x12, 0x9a, 0xb5, 0xe0, 0x2a, - 0xab, 0x18, 0xe6, 0x19, 0xcb, 0x5e, 0x47, 0xb6, 0xdd, 0xa9, 0xb9, 0xd1, - 0x54, 0xdd, 0x2b, 0x3d, 0x7b, 0x31, 0x9f, 0xeb, 0x67, 0xdc, 0xa1, 0x28, - 0x1d, 0xe2, 0x87, 0x68, 0xdc, 0xea, 0x77, 0xb8, 0x73, 0x36, 0x7f, 0xb4, - 0x9d, 0x7d, 0x30, 0x0d, 0x88, 0x51, 0x1b, 0xa8, 0x66, 0xd0, 0x5d, 0x2b, - 0xd1, 0x58, 0x3e, 0xc3, 0x47, 0x44, 0x98, 0x4e, 0xc1, 0xd3, 0xce, 0x87, - 0x5b, 0xe2, 0x84, 0xb5, 0x97, 0x1d, 0x99, 0x1f, 0x35, 0x49, 0xaf, 0x5e, - 0x05, 0x9d, 0x72, 0xc2, 0x45, 0xc7, 0xd1, 0xed, 0x0c, 0x27, 0x4a, 0x9d, - 0x41, 0xa3, 0x8e, 0x38, 0x27, 0x55, 0xad, 0x05, 0xed, 0xc1, 0xc0, 0x3a, - 0x4e, 0xec, 0x07, 0x80, 0xa8, 0xc3, 0x9a, 0x9d, 0x43, 0x2d, 0x7a, 0xb2, - 0x19, 0xb1, 0x02, 0xe0, 0x45, 0xed, 0x7f, 0x69, 0x40, 0x01, 0x50, 0x54, - 0x00, 0x14, 0x00, 0x45, 0x05, 0x40, 0x01, 0x50, 0x54, 0x00, 0x5c, 0x31, - 0x13, 0xbe, 0x32, 0x69, 0x7b, 0xd6, 0xf6, 0xa8, 0x09, 0xdd, 0x8b, 0xf1, - 0xf6, 0x3d, 0x2b, 0x81, 0xd8, 0xae, 0xce, 0x7c, 0x6e, 0x1a, 0x93, 0xfe, - 0x6d, 0xe5, 0x31, 0x08, 0x97, 0xf6, 0x01, 0x80, 0x64, 0x2f, 0x37, 0x41, - 0xdb, 0x55, 0xa5, 0x1f, 0x31, 0x2b, 0xed, 0x96, 0xd9, 0x7f, 0xd5, 0x55, - 0x00, 0x54, 0x14, 0x74, 0xbc, 0x33, 0xf5, 0xb6, 0x9b, 0xd9, 0x04, 0xee, - 0x34, 0x71, 0xa5, 0x01, 0x95, 0x88, 0x95, 0x09, 0x7a, 0xf9, 0x48, 0x06, - 0x72, 0xc2, 0xda, 0xa4, 0xfc, 0xca, 0x7c, 0xa0, 0x34, 0xa0, 0x4c, 0xd0, - 0x31, 0x1a, 0x03, 0x66, 0xc2, 0xcb, 0xb3, 0xe1, 0x4b, 0x6b, 0x00, 0x00, - 0xc2, 0xf2, 0x65, 0x33, 0x97, 0xac, 0x05, 0x8d, 0x6b, 0x60, 0x91, 0x03, - 0xa4, 0x76, 0x59, 0x1d, 0x5d, 0xa6, 0x68, 0xde, 0xc1, 0x17, 0x00, 0x49, - 0x40, 0xec, 0xb9, 0x34, 0xb1, 0xa2, 0xa0, 0x8a, 0x82, 0x0a, 0x80, 0xa2, - 0x02, 0xa0, 0x00, 0x28, 0x3a, 0x0a, 0x80, 0xfe, 0x5f, 0x83, 0xbc, 0xb4, - 0xd7, 0x1e, 0xaa, 0x4b, 0x68, 0x80, 0x17, 0x84, 0x62, 0xfe, 0x02, 0x13, - 0x84, 0x82, 0x90, 0xcd, 0xfc, 0xab, 0xef, 0x92, 0xf9, 0xe3, 0x03, 0x2c, - 0x10, 0x4a, 0xf2, 0x77, 0x70, 0xc2, 0x12, 0x08, 0xc5, 0xfc, 0x1d, 0xa3, - 0x20, 0x0a, 0x42, 0x31, 0x7f, 0x1d, 0x89, 0xb5, 0xa0, 0x1f, 0x86, 0x3f, - 0x86, 0xcf, 0x2f, 0x6d, 0xc7, 0x8f, 0xda, 0x38, 0xfd, 0x0f, 0xc3, 0x64, - 0xcf, 0x81, 0x94, 0xa2, 0x56, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, - 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x0f, 0x50, 0x4c, + 0x54, 0x45, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x60, 0x60, 0x60, 0xff, + 0xff, 0xff, 0x60, 0x60, 0x60, 0x15, 0x68, 0x14, 0xc2, 0x00, 0x00, 0x00, + 0x03, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x00, 0x00, 0xfa, 0x76, 0xc4, 0xde, + 0x00, 0x00, 0x03, 0xf4, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0x98, + 0x6d, 0x6e, 0xde, 0x38, 0x0c, 0x84, 0x27, 0x20, 0x0f, 0xb0, 0xc1, 0x5e, + 0x60, 0x81, 0x5c, 0x80, 0x9b, 0xe1, 0x01, 0x08, 0x88, 0xf7, 0x3f, 0xd3, + 0x42, 0x94, 0x04, 0xa9, 0xad, 0x83, 0xd8, 0x0b, 0x34, 0xed, 0x8f, 0x4e, + 0x90, 0xc8, 0xb4, 0xf9, 0x84, 0x5f, 0xd2, 0xeb, 0x20, 0xf8, 0x3f, 0x22, + 0x71, 0x29, 0x31, 0x94, 0x9a, 0x97, 0xd7, 0xe1, 0x4f, 0xd6, 0x12, 0x42, + 0xc6, 0xe1, 0x4f, 0xda, 0xf1, 0x0b, 0x99, 0x0e, 0x68, 0xdd, 0x07, 0x68, + 0x90, 0x22, 0x87, 0x4b, 0x23, 0x09, 0x29, 0x73, 0x03, 0x29, 0x04, 0x64, + 0x86, 0x22, 0xeb, 0x72, 0x7b, 0x90, 0xc2, 0x92, 0xed, 0x94, 0x84, 0xae, + 0x1c, 0x80, 0x90, 0x38, 0x1c, 0xd4, 0x80, 0xd3, 0x16, 0x9b, 0x00, 0xc9, + 0x61, 0xd1, 0xc4, 0xa4, 0xb2, 0xd7, 0xed, 0x30, 0x53, 0xba, 0x02, 0x84, + 0x10, 0x13, 0x94, 0xac, 0xdb, 0x15, 0x26, 0x1b, 0xe9, 0x19, 0xdf, 0x02, + 0x5e, 0x16, 0xed, 0x04, 0x1c, 0x2d, 0x0a, 0xc8, 0xe6, 0xd9, 0x01, 0x1d, + 0xbd, 0x63, 0x0b, 0xd2, 0x3a, 0x20, 0xc4, 0x01, 0x28, 0x41, 0x60, 0x10, + 0xe5, 0x8f, 0x66, 0xe2, 0x1d, 0x58, 0xd5, 0x17, 0x46, 0x2c, 0x00, 0x0b, + 0x88, 0xee, 0x1f, 0xa1, 0x64, 0xcd, 0x08, 0x3c, 0xe7, 0x7c, 0x02, 0x8d, + 0x5e, 0x01, 0x54, 0x35, 0x55, 0x21, 0x95, 0x06, 0x6d, 0x02, 0x7b, 0x70, + 0xab, 0x4b, 0xf5, 0xb0, 0x14, 0x5d, 0x17, 0xc0, 0xdc, 0x1a, 0xca, 0x52, + 0xa0, 0x9e, 0xcc, 0x18, 0x00, 0x94, 0x31, 0x7e, 0xf0, 0xf3, 0xcd, 0x87, + 0xc0, 0x2f, 0x96, 0x92, 0x71, 0x65, 0x8b, 0x61, 0xd9, 0xd8, 0xda, 0xe7, + 0xa2, 0x71, 0x6c, 0x81, 0xec, 0x6b, 0x1e, 0x00, 0xb9, 0x89, 0xa3, 0xbd, + 0x70, 0x74, 0xaa, 0x83, 0x40, 0x07, 0x85, 0x7c, 0x07, 0x80, 0x37, 0x66, + 0xd0, 0x8e, 0xd0, 0xcc, 0x4c, 0x12, 0xb0, 0xa2, 0x01, 0xc6, 0xe8, 0x9f, + 0x8b, 0xb5, 0x0a, 0xa0, 0x91, 0xe4, 0xf0, 0xef, 0x84, 0x32, 0xb3, 0x91, + 0xb1, 0x00, 0x25, 0x20, 0x65, 0x8b, 0xc9, 0x04, 0xa4, 0x00, 0xf1, 0xcc, + 0x66, 0xb5, 0xd0, 0x9b, 0x2d, 0x60, 0x9d, 0x13, 0x96, 0x80, 0x56, 0xcf, + 0xc5, 0xa0, 0xde, 0x9a, 0x7b, 0x0b, 0xf1, 0x6c, 0xcc, 0x13, 0x80, 0x10, + 0x07, 0x50, 0xcf, 0xc5, 0xc0, 0x10, 0x31, 0x53, 0x36, 0x4b, 0x7a, 0x8a, + 0x0f, 0x40, 0xb1, 0xce, 0xc9, 0x4a, 0x49, 0x4c, 0xe9, 0xdd, 0x56, 0x93, + 0xe8, 0xdf, 0xe2, 0x42, 0x60, 0x45, 0xd8, 0xe7, 0x64, 0x15, 0xdd, 0x9f, + 0x67, 0xb7, 0x21, 0x20, 0x61, 0x50, 0xd2, 0x33, 0x67, 0xd1, 0x64, 0xb7, + 0x0d, 0xc9, 0xa8, 0xb6, 0x92, 0x00, 0xe9, 0x91, 0xd5, 0x25, 0x47, 0x1d, + 0x4a, 0x56, 0x5f, 0xd1, 0x01, 0x69, 0x6e, 0x05, 0x75, 0x00, 0x62, 0xd3, + 0x8e, 0xb2, 0x6b, 0xb4, 0x5e, 0x83, 0xcb, 0x9c, 0x83, 0xab, 0x2c, 0x1a, + 0x91, 0xf4, 0xec, 0x40, 0xd9, 0xc2, 0x08, 0xba, 0x5e, 0x6d, 0x8d, 0xe8, + 0x55, 0x21, 0xcb, 0x0e, 0xe0, 0xf5, 0x9f, 0xb2, 0x31, 0xec, 0xeb, 0xcd, + 0xb7, 0x26, 0x9a, 0x79, 0xd8, 0x58, 0xf6, 0x73, 0x89, 0xed, 0xf5, 0x96, + 0xc8, 0xbd, 0xee, 0xd4, 0xc4, 0x28, 0xc6, 0xbd, 0x96, 0x32, 0xf6, 0x7b, + 0xa0, 0xd6, 0x5d, 0xbc, 0xac, 0xf0, 0x38, 0xa4, 0x05, 0x9c, 0xa9, 0xfd, + 0x05, 0xfc, 0x4d, 0x76, 0x52, 0xc6, 0x6f, 0xb0, 0x09, 0x18, 0x5e, 0x01, + 0x89, 0x8c, 0xb3, 0x3b, 0x52, 0x77, 0xc9, 0x58, 0x87, 0xb1, 0x03, 0x98, + 0xc0, 0xcb, 0x2b, 0xe0, 0x54, 0x00, 0xd6, 0x42, 0x5d, 0x00, 0xeb, 0x80, + 0x60, 0x7d, 0x70, 0x49, 0x8d, 0xc4, 0xce, 0x94, 0xa4, 0x8d, 0xc1, 0x3b, + 0xd0, 0xc4, 0xc4, 0xd0, 0x1c, 0x62, 0x52, 0xe1, 0x06, 0x50, 0x29, 0xed, + 0x08, 0x4e, 0x37, 0xa0, 0xdf, 0x33, 0x11, 0x2e, 0x09, 0x51, 0x40, 0x75, + 0xa1, 0xed, 0x94, 0xf0, 0x2a, 0x8d, 0x0d, 0xd7, 0x80, 0x81, 0x26, 0x45, + 0x9d, 0x29, 0x55, 0x80, 0xeb, 0x94, 0x28, 0x34, 0x61, 0x55, 0x6e, 0x05, + 0x88, 0x19, 0x50, 0x01, 0x7e, 0x2c, 0x5a, 0x69, 0x20, 0x19, 0x73, 0x2a, + 0xb6, 0xfa, 0x07, 0x91, 0x0a, 0x70, 0xd5, 0x56, 0x23, 0xb9, 0xc7, 0xb9, + 0x46, 0x4a, 0xab, 0x00, 0x57, 0x83, 0x33, 0xd2, 0x16, 0x60, 0x1b, 0x20, + 0x4a, 0x17, 0x5b, 0x63, 0x47, 0x38, 0x52, 0xd2, 0x66, 0x57, 0x9b, 0x6f, + 0x5d, 0xd0, 0x3a, 0x40, 0x31, 0x80, 0x52, 0xab, 0xc6, 0xe5, 0xf6, 0xfe, + 0x1a, 0xd9, 0x11, 0x1b, 0x43, 0x4a, 0x4c, 0xc5, 0xb0, 0xc7, 0x22, 0xd1, + 0x7c, 0x27, 0x76, 0x24, 0xc9, 0x5c, 0x40, 0x58, 0x2d, 0xd3, 0x56, 0x27, + 0x01, 0x9e, 0x00, 0x01, 0x88, 0x33, 0x46, 0x18, 0x9f, 0x0f, 0xb5, 0x4d, + 0xa7, 0x56, 0xed, 0xec, 0x8a, 0xf5, 0x1e, 0x36, 0xb0, 0xf9, 0x4c, 0xeb, + 0xfd, 0x2d, 0x86, 0x63, 0x92, 0x3e, 0x32, 0xa6, 0x83, 0x43, 0xc0, 0xba, + 0x60, 0xa0, 0xd4, 0xf2, 0xfd, 0x2d, 0x19, 0x23, 0x00, 0x73, 0x54, 0x2b, + 0x01, 0xf9, 0x16, 0x30, 0x24, 0xfb, 0x17, 0x94, 0x49, 0x66, 0xc1, 0x41, + 0x7a, 0x54, 0x00, 0xa8, 0x03, 0xb4, 0xfd, 0x17, 0x8c, 0x10, 0x03, 0x98, + 0xa9, 0xd6, 0xb4, 0x95, 0xb2, 0x02, 0x84, 0xb5, 0xd9, 0x19, 0xb1, 0xb9, + 0xcc, 0x46, 0x2a, 0x04, 0x1d, 0x18, 0x95, 0xda, 0x0a, 0x20, 0xe8, 0x3a, + 0x01, 0x00, 0x59, 0x2a, 0xc0, 0xd7, 0x3b, 0x51, 0x57, 0x00, 0x94, 0x26, + 0xb0, 0x47, 0xa5, 0x50, 0x08, 0x99, 0x05, 0x60, 0x34, 0x11, 0xc7, 0x69, + 0xdc, 0x35, 0x9c, 0x80, 0x49, 0xfa, 0xda, 0xd5, 0x18, 0x80, 0x61, 0x48, + 0x56, 0x97, 0x6c, 0x03, 0x75, 0xbb, 0x0d, 0x0f, 0x7a, 0x2a, 0x02, 0x8d, + 0xb8, 0x04, 0xb2, 0x04, 0x40, 0x17, 0xa0, 0x19, 0x11, 0x38, 0x24, 0x6b, + 0xd2, 0x86, 0x2f, 0x95, 0x1c, 0xf1, 0xd4, 0x6e, 0x01, 0x1b, 0x62, 0x00, + 0x2f, 0x9c, 0x86, 0x30, 0x84, 0x31, 0xba, 0xf1, 0x01, 0x20, 0x44, 0x07, + 0x68, 0x9f, 0x01, 0xfb, 0x73, 0x65, 0x00, 0xb4, 0x7b, 0x80, 0x10, 0x13, + 0xa0, 0x5d, 0x03, 0x27, 0x54, 0xf7, 0x63, 0x01, 0xb4, 0x0d, 0x94, 0xed, + 0x6b, 0x3d, 0x6a, 0x50, 0x92, 0x5c, 0x00, 0xe3, 0x63, 0xe0, 0xdc, 0x39, + 0xbe, 0x00, 0xff, 0x10, 0x38, 0x95, 0xb4, 0x09, 0x78, 0xec, 0x94, 0x32, + 0xe9, 0x99, 0x40, 0x96, 0xf6, 0x07, 0xf2, 0x6e, 0x6b, 0xf9, 0x7f, 0x54, + 0x74, 0x01, 0x67, 0x5b, 0x81, 0xf2, 0xbf, 0x05, 0x28, 0xb1, 0x9a, 0x75, + 0x0f, 0x90, 0xe1, 0x98, 0x81, 0xb5, 0xdb, 0x75, 0x5c, 0x67, 0x5e, 0x01, + 0x37, 0xb5, 0x8b, 0x7e, 0xac, 0xfc, 0x4e, 0x81, 0xef, 0x44, 0xbb, 0x06, + 0x56, 0x05, 0x9f, 0x02, 0x8d, 0x25, 0xff, 0x3a, 0x00, 0x7f, 0x80, 0xdf, + 0x12, 0x20, 0x69, 0x4f, 0x00, 0x76, 0xd9, 0x7d, 0x40, 0x08, 0x9a, 0xf0, + 0x01, 0x60, 0xa0, 0xbd, 0x3c, 0x00, 0x58, 0x45, 0x8b, 0xfd, 0x0c, 0x80, + 0x3f, 0xea, 0xdf, 0x2f, 0x05, 0xbe, 0xbe, 0xe8, 0xe7, 0x73, 0x78, 0x3e, + 0xe9, 0xe7, 0x7b, 0x69, 0x13, 0xf6, 0xe7, 0x4c, 0x3f, 0x06, 0x94, 0xa5, + 0xb8, 0x05, 0xec, 0x10, 0x8e, 0xfb, 0x80, 0x56, 0x00, 0xdc, 0x7e, 0x3f, + 0x54, 0x08, 0xc7, 0x13, 0x40, 0xc9, 0x78, 0x04, 0xa0, 0x39, 0x9e, 0x01, + 0xe5, 0x94, 0x53, 0x9f, 0xfd, 0x33, 0xf0, 0x3f, 0x53, 0x26, 0x87, 0x23, + 0x59, 0xac, 0x2b, 0x06, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, + 0xae, 0x42, 0x60, 0x82 }; -enum TextureType +const u32 TEXTURE_ATLAS_LENGTH = (u32)std::size(TEXTURE_ATLAS); +const vec2 TEXTURE_ATLAS_SIZE = {96, 120}; + +enum AtlasType { - TEXTURE_NONE, - TEXTURE_RECORD, - TEXTURE_ROOT, - TEXTURE_LAYER, - TEXTURE_NULL, - TEXTURE_TRIGGERS, - TEXTURE_VISIBLE, - TEXTURE_INVISIBLE, - TEXTURE_SHOW_RECT, - TEXTURE_HIDE_RECT, - TEXTURE_PAN, - TEXTURE_MOVE, - TEXTURE_ROTATE, - TEXTURE_SCALE, - TEXTURE_CROP, - TEXTURE_UNDO, - TEXTURE_REDO, - TEXTURE_DRAW, - TEXTURE_ERASE, - TEXTURE_COLOR_PICKER, - TEXTURE_ANIMATION, - TEXTURE_SPRITESHEET, - TEXTURE_EVENT, - TEXTURE_TRIGGER, - TEXTURE_PIVOT, - TEXTURE_SQUARE, - TEXTURE_CIRCLE, - TEXTURE_PICKER, - TEXTURE_FRAME_ALT, - TEXTURE_FRAME, - TEXTURE_TARGET, - TEXTURE_COUNT + ATLAS_NONE, + ATLAS_FOLDER, + ATLAS_ROOT, + ATLAS_LAYER, + ATLAS_NULL, + ATLAS_TRIGGERS, + ATLAS_VISIBLE, + ATLAS_INVISIBLE, + ATLAS_SHOW_RECT, + ATLAS_HIDE_RECT, + ATLAS_SHOW_TARGETS, + ATLAS_HIDE_TARGETS, + ATLAS_PAN, + ATLAS_MOVE, + ATLAS_ROTATE, + ATLAS_SCALE, + ATLAS_CROP, + ATLAS_DRAW, + ATLAS_ERASE, + ATLAS_COLOR_PICKER, + ATLAS_UNDO, + ATLAS_REDO, + ATLAS_ANIMATION, + ATLAS_SPRITESHEET, + ATLAS_EVENT, + ATLAS_PLAY, + ATLAS_PAUSE, + ATLAS_ADD, + ATLAS_REMOVE, + ATLAS_TRIGGER, + ATLAS_PIVOT, + ATLAS_SQUARE, + ATLAS_CIRCLE, + ATLAS_PICKER, + ATLAS_FRAME, + ATLAS_FRAME_ALT, + ATLAS_TARGET, + ATLAS_COUNT }; -const vec2 ATLAS_SIZE = {96, 104}; -const vec2 TEXTURE_SIZE_SMALL = {8, 8}; -const vec2 TEXTURE_SIZE = {16, 16}; -const vec2 TEXTURE_SIZE_OBLONG = {16, 40}; -const vec2 TEXTURE_SIZE_BIG = {40, 40}; - -#define ATLAS_UV(x,y){(f32)x / ATLAS_SIZE[0], (f32) y / ATLAS_SIZE[1]} -const vec2 ATLAS_UVS[TEXTURE_COUNT][2] = +struct AtlasEntry { - { ATLAS_UV( 0, 0), ATLAS_UV( 16, 16) }, /* 16 x 16 v */ - { ATLAS_UV( 16, 0), ATLAS_UV( 32, 16) }, - { ATLAS_UV( 32, 0), ATLAS_UV( 48, 16) }, - { ATLAS_UV( 48, 0), ATLAS_UV( 64, 16) }, - { ATLAS_UV( 64, 0), ATLAS_UV( 80, 16) }, - { ATLAS_UV( 80, 0), ATLAS_UV( 96, 16) }, - { ATLAS_UV( 0, 16), ATLAS_UV( 16, 32) }, - { ATLAS_UV( 16, 16), ATLAS_UV( 32, 32) }, - { ATLAS_UV( 32, 16), ATLAS_UV( 48, 32) }, - { ATLAS_UV( 48, 16), ATLAS_UV( 64, 32) }, - { ATLAS_UV( 64, 16), ATLAS_UV( 80, 32) }, - { ATLAS_UV( 80, 16), ATLAS_UV( 96, 32) }, - { ATLAS_UV( 0, 32), ATLAS_UV( 16, 48) }, - { ATLAS_UV( 16, 32), ATLAS_UV( 32, 48) }, - { ATLAS_UV( 32, 32), ATLAS_UV( 48, 48) }, - { ATLAS_UV( 48, 32), ATLAS_UV( 64, 48) }, - { ATLAS_UV( 64, 32), ATLAS_UV( 80, 48) }, - { ATLAS_UV( 80, 32), ATLAS_UV( 96, 48) }, - { ATLAS_UV( 0, 48), ATLAS_UV( 16, 64) }, - { ATLAS_UV( 16, 48), ATLAS_UV( 32, 64) }, - { ATLAS_UV( 32, 48), ATLAS_UV( 48, 64) }, - { ATLAS_UV( 48, 48), ATLAS_UV( 64, 64) }, - { ATLAS_UV( 64, 48), ATLAS_UV( 80, 64) }, - { ATLAS_UV( 80, 48), ATLAS_UV( 88, 56) }, /* 8 x 8 v */ - { ATLAS_UV( 88, 48), ATLAS_UV( 96, 56) }, - { ATLAS_UV( 80, 56), ATLAS_UV( 88, 64) }, - { ATLAS_UV( 88, 56), ATLAS_UV( 96, 64) }, - { ATLAS_UV( 0, 64), ATLAS_UV( 16,104) }, /* 16 x 40 */ - { ATLAS_UV( 16, 64), ATLAS_UV( 32,104) }, - { ATLAS_UV( 32, 64), ATLAS_UV( 48,104) }, - { ATLAS_UV( 48, 64), ATLAS_UV( 88,104) } /* 40 x 40 */ + vec2 position; + vec2 size; }; -#define ATLAS_UV_ARGS(type) ATLAS_UVS[type][0], ATLAS_UVS[type][1] +const vec2 ATLAS_SIZE_SMALL = {8, 8}; +const vec2 ATLAS_SIZE_NORMAL = {16, 16}; +const vec2 ATLAS_SIZE_OBLONG = {16, 40}; +const vec2 ATLAS_SIZE_BIG = {40, 40}; -const vec2 ATLAS_SIZES[TEXTURE_COUNT] = +const inline AtlasEntry ATLAS_ENTRIES[ATLAS_COUNT] = { - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE, - TEXTURE_SIZE_SMALL, - TEXTURE_SIZE_SMALL, - TEXTURE_SIZE_SMALL, - TEXTURE_SIZE_SMALL, - TEXTURE_SIZE_OBLONG, - TEXTURE_SIZE_OBLONG, - TEXTURE_SIZE_OBLONG, - TEXTURE_SIZE_BIG + {{ 0, 0}, ATLAS_SIZE_NORMAL}, + {{ 16, 0}, ATLAS_SIZE_NORMAL}, + {{ 32, 0}, ATLAS_SIZE_NORMAL}, + {{ 48, 0}, ATLAS_SIZE_NORMAL}, + {{ 64, 0}, ATLAS_SIZE_NORMAL}, + {{ 80, 0}, ATLAS_SIZE_NORMAL}, + {{ 0, 16}, ATLAS_SIZE_NORMAL}, + {{ 16, 16}, ATLAS_SIZE_NORMAL}, + {{ 32, 16}, ATLAS_SIZE_NORMAL}, + {{ 48, 16}, ATLAS_SIZE_NORMAL}, + {{ 64, 16}, ATLAS_SIZE_NORMAL}, + {{ 80, 16}, ATLAS_SIZE_NORMAL}, + {{ 0, 32}, ATLAS_SIZE_NORMAL}, + {{ 16, 32}, ATLAS_SIZE_NORMAL}, + {{ 32, 32}, ATLAS_SIZE_NORMAL}, + {{ 48, 32}, ATLAS_SIZE_NORMAL}, + {{ 64, 32}, ATLAS_SIZE_NORMAL}, + {{ 80, 32}, ATLAS_SIZE_NORMAL}, + {{ 0, 48}, ATLAS_SIZE_NORMAL}, + {{ 16, 48}, ATLAS_SIZE_NORMAL}, + {{ 32, 48}, ATLAS_SIZE_NORMAL}, + {{ 48, 48}, ATLAS_SIZE_NORMAL}, + {{ 64, 48}, ATLAS_SIZE_NORMAL}, + {{ 80, 48}, ATLAS_SIZE_NORMAL}, + {{ 0, 64}, ATLAS_SIZE_NORMAL}, + {{ 16, 64}, ATLAS_SIZE_NORMAL}, + {{ 32, 64}, ATLAS_SIZE_NORMAL}, + {{ 48, 64}, ATLAS_SIZE_NORMAL}, + {{ 64, 64}, ATLAS_SIZE_NORMAL}, + {{ 80, 64}, ATLAS_SIZE_SMALL }, + {{ 88, 64}, ATLAS_SIZE_SMALL }, + {{ 80, 72}, ATLAS_SIZE_SMALL }, + {{ 88, 72}, ATLAS_SIZE_SMALL }, + {{ 0, 80}, ATLAS_SIZE_OBLONG}, + {{16, 80}, ATLAS_SIZE_OBLONG}, + {{32, 80}, ATLAS_SIZE_OBLONG}, + {{48, 80}, ATLAS_SIZE_BIG} }; -#define ATLAS_UV_VERTICES(type) UV_VERTICES(ATLAS_UVS[type][0], ATLAS_UVS[type][1]) +#define ATLAS_POSITION(type) ATLAS_ENTRIES[type].position +#define ATLAS_SIZE(type) ATLAS_ENTRIES[type].size +#define ATLAS_UV_MIN(type) (ATLAS_POSITION(type) / TEXTURE_ATLAS_SIZE) +#define ATLAS_UV_MAX(type) ((ATLAS_POSITION(type) + ATLAS_SIZE(type)) / TEXTURE_ATLAS_SIZE) +#define ATLAS_UV_ARGS(type) ATLAS_UV_MIN(type), ATLAS_UV_MAX(type) +#define ATLAS_UV_VERTICES(type) UV_VERTICES(ATLAS_UV_MIN(type), ATLAS_UV_MAX(type)) -/* Shaders */ struct ShaderData { std::string vertex; @@ -331,4 +269,4 @@ const ShaderData SHADER_DATA[SHADER_COUNT] = { {SHADER_VERTEX, SHADER_FRAGMENT}, {SHADER_VERTEX, SHADER_TEXTURE_FRAGMENT} -}; +}; \ No newline at end of file diff --git a/src/canvas.cpp b/src/canvas.cpp index 6225dc3..9d7fe2e 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -228,21 +228,6 @@ void canvas_rect_draw(Canvas* self, const GLuint& shader, const mat4& transform, glUseProgram(0); } -void canvas_rect_dotted_draw(Canvas* self, const GLuint& shader, const mat4& transform, const vec4& color) -{ - glUseProgram(shader); - - glBindVertexArray(self->rectVAO); - - glUniformMatrix4fv(glGetUniformLocation(shader, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(transform)); - glUniform4fv(glGetUniformLocation(shader, SHADER_UNIFORM_COLOR), 1, value_ptr(color)); - - glDrawArrays(GL_LINE_LOOP, 0, 4); - - glBindVertexArray(0); - glUseProgram(0); -} - void canvas_axes_draw(Canvas* self, GLuint& shader, mat4& transform, vec4& color) { glUseProgram(shader); diff --git a/src/dialog.cpp b/src/dialog.cpp index 52a32c2..7c66ad8 100644 --- a/src/dialog.cpp +++ b/src/dialog.cpp @@ -2,8 +2,6 @@ #include "dialog.h" -static void _dialog_callback(void* userdata, const char* const* filelist, s32 filter); - static void _dialog_callback(void* userdata, const char* const* filelist, s32 filter) { Dialog* self; @@ -23,91 +21,59 @@ static void _dialog_callback(void* userdata, const char* const* filelist, s32 fi } } -void dialog_init(Dialog* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, SDL_Window* window) +void dialog_init(Dialog* self, SDL_Window* window) { - self->anm2 = anm2; - self->reference = reference; - self->resources = resources; self->window = window; } void dialog_anm2_open(Dialog* self) { - SDL_ShowOpenFileDialog(_dialog_callback, self, nullptr, DIALOG_FILE_FILTER_ANM2, 1, nullptr, false); + SDL_ShowOpenFileDialog(_dialog_callback, self, self->window, DIALOG_FILE_FILTER_ANM2, 1, nullptr, false); self->type = DIALOG_ANM2_OPEN; } void dialog_anm2_save(Dialog* self) { - SDL_ShowSaveFileDialog(_dialog_callback, self, nullptr, DIALOG_FILE_FILTER_ANM2, 1, nullptr); + SDL_ShowSaveFileDialog(_dialog_callback, self, self->window, DIALOG_FILE_FILTER_ANM2, 1, nullptr); self->type = DIALOG_ANM2_SAVE; } -void dialog_png_open(Dialog* self) +void dialog_spritesheet_add(Dialog* self) { - SDL_ShowOpenFileDialog(_dialog_callback, self, nullptr, DIALOG_FILE_FILTER_PNG, 1, nullptr, false); - self->type = DIALOG_PNG_OPEN; + SDL_ShowOpenFileDialog(_dialog_callback, self, self->window, DIALOG_FILE_FILTER_PNG, 1, nullptr, false); + self->type = DIALOG_SPRITESHEET_ADD; } -void dialog_png_replace(Dialog* self) +void dialog_spritesheet_replace(Dialog* self, s32 id) { - SDL_ShowOpenFileDialog(_dialog_callback, self, nullptr, DIALOG_FILE_FILTER_PNG, 1, nullptr, false); - self->type = DIALOG_PNG_REPLACE; + SDL_ShowOpenFileDialog(_dialog_callback, self, self->window, DIALOG_FILE_FILTER_PNG, 1, nullptr, false); + self->replaceID = id; + self->type = DIALOG_SPRITESHEET_REPLACE; } -void dialog_update(Dialog* self) +void dialog_render_path_set(Dialog* self) { - self->isJustSelected = false; + SDL_ShowSaveFileDialog(_dialog_callback, self, self->window, DIALOG_FILE_FILTER_RENDER, 2, nullptr); + self->type = DIALOG_RENDER_PATH_SET; +} - if (self->isSelected) - { - Texture texture; - s32 id; - - switch (self->type) - { - case DIALOG_ANM2_OPEN: - *self->reference = Anm2Reference{}; - resources_textures_free(self->resources); - anm2_deserialize(self->anm2, self->resources, self->path); - window_title_from_path_set(self->window, self->path); - break; - case DIALOG_ANM2_SAVE: - anm2_serialize(self->anm2, self->path); - window_title_from_path_set(self->window, self->path); - break; - case DIALOG_PNG_OPEN: - id = map_next_id_get(self->resources->textures); - self->anm2->spritesheets[id] = Anm2Spritesheet{}; - self->anm2->spritesheets[id].path = self->path; - resources_texture_init(self->resources, self->path, id); - break; - case DIALOG_PNG_REPLACE: - self->anm2->spritesheets[self->replaceID].path = self->path; - resources_texture_init(self->resources, self->path, self->replaceID); - self->replaceID = -1; - break; - default: - break; - } +void dialog_render_directory_set(Dialog* self) +{ + SDL_ShowOpenFolderDialog(_dialog_callback, self, self->window, nullptr, false); + self->type = DIALOG_RENDER_DIRECTORY_SET; +} - self->lastType = self->type; - self->lastPath = self->path; - self->type = DIALOG_NONE; - self->path.clear(); - - self->isJustSelected = true; - self->isSelected = false; - } +void dialog_ffmpeg_path_set(Dialog* self) +{ + SDL_ShowOpenFileDialog(_dialog_callback, self, self->window, DIALOG_FILE_FILTER_FFMPEG, 1, nullptr, false); + self->type = DIALOG_FFMPEG_PATH_SET; } void dialog_reset(Dialog* self) { - self->lastType = DIALOG_NONE; + self->replaceID = ID_NONE; self->type = DIALOG_NONE; - self->lastPath.clear(); self->path.clear(); - self->isJustSelected = false; self->isSelected = false; } \ No newline at end of file diff --git a/src/dialog.h b/src/dialog.h index bdfcdc4..1fb15df 100644 --- a/src/dialog.h +++ b/src/dialog.h @@ -1,17 +1,26 @@ #pragma once -#include "anm2.h" -#include "resources.h" #include "window.h" const SDL_DialogFileFilter DIALOG_FILE_FILTER_ANM2[] = { - {"Anm2", "anm2;xml"} + {"Anm2 file", "anm2;xml"} }; const SDL_DialogFileFilter DIALOG_FILE_FILTER_PNG[] = { - {"png", "png"} + {"PNG image", "png"} +}; + +const SDL_DialogFileFilter DIALOG_FILE_FILTER_RENDER[] = +{ + {"GIF image", "gif"}, + {"WebM video", "webm"} +}; + +const SDL_DialogFileFilter DIALOG_FILE_FILTER_FFMPEG[] = +{ + {"Executable", ""} }; enum DialogType @@ -19,32 +28,29 @@ enum DialogType DIALOG_NONE, DIALOG_ANM2_OPEN, DIALOG_ANM2_SAVE, - DIALOG_PNG_OPEN, - DIALOG_PNG_REPLACE, - DIALOG_FRAME_DIRECTORY_OPEN, + DIALOG_SPRITESHEET_ADD, + DIALOG_SPRITESHEET_REPLACE, + DIALOG_RENDER_PATH_SET, + DIALOG_RENDER_DIRECTORY_SET, + DIALOG_FFMPEG_PATH_SET }; struct Dialog { - Anm2* anm2 = nullptr; - Anm2Reference* reference = nullptr; - Resources* resources = nullptr; SDL_Window* window = nullptr; + s32 selectedFilter = ID_NONE; std::string path{}; - std::string lastPath{}; s32 replaceID = ID_NONE; - s32 selectedFilter{}; DialogType type = DIALOG_NONE; - DialogType lastType = DIALOG_NONE; bool isSelected = false; - bool isJustSelected = false; }; -void dialog_init(Dialog* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, SDL_Window* window); +void dialog_init(Dialog* self, SDL_Window* window); void dialog_anm2_open(Dialog* self); -void dialog_png_open(Dialog* self); -void dialog_png_replace(Dialog* self); +void dialog_spritesheet_add(Dialog* self); +void dialog_spritesheet_replace(Dialog* self, s32 id); void dialog_anm2_save(Dialog* self); -void dialog_frame_directory_open(Dialog* self); -void dialog_update(Dialog* self); +void dialog_render_path_set(Dialog* self); +void dialog_render_directory_set(Dialog* self); +void dialog_ffmpeg_path_set(Dialog* self); void dialog_reset(Dialog* self); \ No newline at end of file diff --git a/src/editor.cpp b/src/editor.cpp index 293fb4d..cedd464 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -44,7 +44,7 @@ void editor_draw(Editor* self) canvas_rect_draw(&self->canvas, shaderLine, mvp, EDITOR_FRAME_COLOR); mvp = canvas_mvp_get(transform, CANVAS_PIVOT_SIZE, frame->crop + frame->pivot, CANVAS_PIVOT_SIZE * 0.5f); - f32 vertices[] = ATLAS_UV_VERTICES(TEXTURE_PIVOT); + f32 vertices[] = ATLAS_UV_VERTICES(ATLAS_PIVOT); canvas_texture_draw(&self->canvas, shaderTexture, self->resources->atlas.id, mvp, vertices, EDITOR_PIVOT_COLOR); } } diff --git a/src/ffmpeg.cpp b/src/ffmpeg.cpp new file mode 100644 index 0000000..281bab9 --- /dev/null +++ b/src/ffmpeg.cpp @@ -0,0 +1,60 @@ +#include "ffmpeg.h" + +bool +ffmpeg_render +( + const std::string& ffmpegPath, + const std::string& outputPath, + const std::vector& frames, + ivec2 size, + s32 fps, + enum RenderType type +) +{ + if (frames.empty() || size.x <= 0 || size.y <= 0 || fps <= 0 || ffmpegPath.empty() || outputPath.empty()) return false; + + std::string command{}; + + switch (type) + { + case RENDER_GIF: + command = std::format(FFMPEG_GIF_FORMAT, ffmpegPath, size.x, size.y, fps, outputPath); + break; + case RENDER_WEBM: + command = std::format(FFMPEG_WEBM_FORMAT, ffmpegPath, size.x, size.y, fps, outputPath); + break; + default: + return false; + } + + FILE* fp = POPEN(command.c_str(), PWRITE_MODE); + + if (!fp) + { + log_info(std::format(FFMPEG_POPEN_ERROR, strerror(errno))); + return false; + } + + size_t frameBytes = size.x * size.y * TEXTURE_CHANNELS; + + for (const auto& frame : frames) + { + std::vector rgba = texture_download(&frame); + + if (rgba.size() != frameBytes) + { + PCLOSE(fp); + return false; + } + + if (fwrite(rgba.data(), 1, frameBytes, fp) != frameBytes) + { + PCLOSE(fp); + return false; + } + } + + const int code = PCLOSE(fp); + + return (code == 0); +} \ No newline at end of file diff --git a/src/ffmpeg.h b/src/ffmpeg.h new file mode 100644 index 0000000..031ff27 --- /dev/null +++ b/src/ffmpeg.h @@ -0,0 +1,32 @@ +#pragma once + +#include "render.h" +#include "texture.h" + +#define FFMPEG_POPEN_ERROR "popen() (for FFmpeg) failed!\n{}" + +static constexpr const char* FFMPEG_GIF_FORMAT = +"\"{0}\" -y " +"-f rawvideo -pix_fmt rgba -s {1}x{2} -r {3} -i pipe:0 " +"-lavfi \"split[s0][s1];" +"[s0]palettegen=stats_mode=full[p];" +"[s1][p]paletteuse=dither=floyd_steinberg\" " +"-loop 0 \"{4}\""; + +static constexpr const char* FFMPEG_WEBM_FORMAT = +"\"{0}\" -y " +"-f rawvideo -pix_fmt rgba -s {1}x{2} -r {3} -i pipe:0 " +"-c:v libvpx-vp9 -crf 30 -b:v 0 -pix_fmt yuva420p -row-mt 1 -threads 0 -speed 2 " +"-auto-alt-ref 0 -an \"{4}\""; + + +bool +ffmpeg_render +( + const std::string& ffmpegPath, + const std::string& outputPath, + const std::vector& frames, + ivec2 size, + s32 fps, + enum RenderType type +); \ No newline at end of file diff --git a/src/imgui.cpp b/src/imgui.cpp index e1bbf3b..e06aed6 100644 --- a/src/imgui.cpp +++ b/src/imgui.cpp @@ -35,9 +35,9 @@ static void _imgui_clipboard_hovered_item_set(Imgui* self, const T& data) self->clipboard->hoveredItem = ClipboardItem(data); } -static void _imgui_atlas_image(Imgui* self, TextureType type) +static void _imgui_atlas_image(Imgui* self, AtlasType type) { - ImGui::Image(self->resources->atlas.id, ATLAS_SIZES[type], ATLAS_UV_ARGS(type)); + ImGui::Image(self->resources->atlas.id, ATLAS_SIZE(type), ATLAS_UV_ARGS(type)); } static void _imgui_item_text(const ImguiItem& item) @@ -83,7 +83,7 @@ static void _imgui_item(Imgui* self, const ImguiItem& item, bool* isActivated) } } - if (isActivated && self->isHotkeysEnabled && (item.is_chord() && ImGui::IsKeyChordPressed(item.chord))) + if (isActivated && self->isContextualActionsEnabled && (item.is_chord() && ImGui::IsKeyChordPressed(item.chord))) if (item.is_focus_window() && (imgui_nav_window_root_get() == item.focusWindow)) *isActivated = true; @@ -97,25 +97,43 @@ static void _imgui_item(Imgui* self, const ImguiItem& item, bool* isActivated) if (item.is_popup()) { - ImGui::OpenPopup(item.popup.c_str()); - - switch (item.popupType) - { - case IMGUI_POPUP_CENTER_SCREEN: - ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); - break; - case IMGUI_POPUP_BY_ITEM: - default: - ImGui::SetNextWindowPos(ImVec2(ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y + ImGui::GetItemRectSize().y)); - break; - } + self->pendingPopup = item.popup; + self->pendingPopupType = item.popupType; + self->pendingPopupPosition = ImVec2(ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y + ImGui::GetItemRectSize().y); } } } -static bool _imgui_item_combo(Imgui* self, const ImguiItem& item, s32* current, const char* const items[], s32 count) +static void _imgui_pending_popup_process(Imgui* self) { - bool isActivated = ImGui::Combo(item.label.c_str(), current, items, count); + if (self->pendingPopup.empty()) return; + + switch (self->pendingPopupType) + { + case IMGUI_POPUP_CENTER_SCREEN: + ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + break; + case IMGUI_POPUP_BY_ITEM: + default: + ImGui::SetNextWindowPos(self->pendingPopupPosition); + break; + } + + ImGui::OpenPopup(self->pendingPopup.c_str()); + + self->pendingPopup.clear(); + self->pendingPopupType = IMGUI_POPUP_NONE; + self->pendingPopupPosition = ImVec2(); +} + +static bool _imgui_item_combo(Imgui* self, const ImguiItem& item, s32* current) +{ + std::vector cStrings; + cStrings.reserve(item.items.size()); + for (auto& string : item.items) + cStrings.push_back(string.c_str()); + + bool isActivated = ImGui::Combo(item.label.c_str(), current, cStrings.data(), (s32)item.items.size()); _imgui_item(self, item, &isActivated); return isActivated; } @@ -125,14 +143,15 @@ static bool _imgui_item_selectable(Imgui* self, const ImguiItem& item) const char* label = item.label.c_str(); s32 flags = item.flags; - if (item.isInactive || item.color.is_normal()) + if (item.isInactive) { - vec4 color = item.isInactive ? IMGUI_INACTIVE_COLOR : item.color.normal; - ImGui::PushStyleColor(ImGuiCol_Text, color); - flags |= ImGuiSelectableFlags_Disabled; - } + ImGui::PushStyleColor(ImGuiCol_Text, IMGUI_INACTIVE_COLOR); + flags |= ImGuiSelectableFlags_Disabled; + } + else if (item.color.is_normal()) + ImGui::PushStyleColor(ImGuiCol_Text, item.color.normal); - ImVec2 size = item.is_size() ? item.size : item.isSizeToText ? ImGui::CalcTextSize(label) :ImVec2(0, 0); + ImVec2 size = item.is_size() ? item.size : item.isSizeToText ? ImGui::CalcTextSize(label) : ImVec2(); bool isActivated = ImGui::Selectable(label, item.isSelected, flags, size); _imgui_item(self, item, &isActivated); @@ -173,14 +192,19 @@ static bool _imgui_item_inputint2(Imgui* self, const ImguiItem& item, ivec2& val static bool _imgui_item_inputtext(Imgui* self, const ImguiItem& item, std::string& buffer) { - if ((s32)buffer.size() < item.max) buffer.resize(item.max); + if ((s32)buffer.size() < (s32)item.max) buffer.resize(item.max); ImVec2 size = item.is_size() ? item.size : ImVec2(-FLT_MIN, 0); - + + if (item.isSizeToChild) + { + size.x = (ImGui::GetWindowSize().x - ImGui::GetStyle().ItemSpacing.x * (item.childRowItemCount + 1)) / item.childRowItemCount; + size.x -= ImGui::CalcTextSize(item.label.c_str()).x * 2; + } + ImGui::SetNextItemWidth(size.x); - ImGui::InputText(item.label.c_str(), &buffer[0], item.max, item.flags); - bool isActivated = ImGui::IsItemActivated(); + bool isActivated = ImGui::InputText(item.label.c_str(), &buffer[0], item.max, item.flags); _imgui_item(self, item, &isActivated); return isActivated; @@ -292,7 +316,7 @@ static bool _imgui_item_selectable_inputtext(Imgui* self, const ImguiItem& item, renameID = ID_NONE; itemID = ID_NONE; self->isRename = false; - + self->isContextualActionsEnabled = true; } ImGui::PopID(); @@ -307,6 +331,7 @@ static bool _imgui_item_selectable_inputtext(Imgui* self, const ImguiItem& item, renameID = id; itemID = item.id; ImGui::SetKeyboardFocusHere(-1); + self->isContextualActionsEnabled = false; } } @@ -340,6 +365,7 @@ static bool _imgui_item_selectable_inputint(Imgui* self, const ImguiItem& item, itemID = ID_NONE; changeID = ID_NONE; self->isChangeValue = false; + self->isContextualActionsEnabled = true; } ImGui::PopID(); @@ -353,6 +379,7 @@ static bool _imgui_item_selectable_inputint(Imgui* self, const ImguiItem& item, itemID = item.id; changeID = id; ImGui::SetKeyboardFocusHere(-1); + self->isContextualActionsEnabled = false; } } @@ -361,16 +388,9 @@ static bool _imgui_item_selectable_inputint(Imgui* self, const ImguiItem& item, return isActivated; } -static void _imgui_item_atlas_image_text(Imgui* self, const ImguiItem& item) -{ - _imgui_atlas_image(self, item.texture); - ImGui::SameLine(); - ImGui::Text(item.label.c_str()); -} - static bool _imgui_item_atlas_image_selectable(Imgui* self, const ImguiItem& item) { - _imgui_atlas_image(self, item.texture); + _imgui_atlas_image(self, item.atlas); ImGui::SameLine(); return _imgui_item_selectable(self, item); } @@ -388,14 +408,14 @@ static bool _imgui_item_text_inputtext(Imgui* self, const ImguiItem& item, std:: static bool _imgui_item_atlas_image_selectable_inputtext(Imgui* self, ImguiItem& item, std::string& string, s32 id) { - _imgui_atlas_image(self, item.texture); + _imgui_atlas_image(self, item.atlas); ImGui::SameLine(); return _imgui_item_selectable_inputtext(self, item, string, id); } static bool _imgui_item_atlas_image_selectable_inputint(Imgui* self, ImguiItem& item, s32& value, s32 id) { - _imgui_atlas_image(self, item.texture); + _imgui_atlas_image(self, item.atlas); ImGui::SameLine(); return _imgui_item_selectable_inputint(self, item, value, id); } @@ -407,7 +427,7 @@ static bool _imgui_item_atlas_image_checkbox_selectable(Imgui* self, const Imgui _imgui_item_checkbox(self, checkboxItem, value); ImGui::SameLine(); - _imgui_atlas_image(self, item.texture); + _imgui_atlas_image(self, item.atlas); ImGui::SameLine(); return _imgui_item_selectable(self, item); } @@ -415,7 +435,7 @@ static bool _imgui_item_atlas_image_checkbox_selectable(Imgui* self, const Imgui static bool _imgui_item_atlas_image_button(Imgui* self, const ImguiItem& item) { bool isActivated = false; - ImVec2 imageSize = (ATLAS_SIZES[item.texture]); + ImVec2 imageSize = (ATLAS_SIZE(item.atlas)); ImVec2 buttonSize = item.is_size() ? item.size : imageSize; if (item.color.is_normal()) ImGui::PushStyleColor(ImGuiCol_Button, item.color.normal); @@ -432,10 +452,10 @@ static bool _imgui_item_atlas_image_button(Imgui* self, const ImguiItem& item) ImVec2 imageMin = pos + item.contentOffset; ImVec2 imageMax = imageMin + imageSize; - ImGui::GetWindowDrawList()->AddImage(self->resources->atlas.id, imageMin, imageMax, ATLAS_UV_ARGS(item.texture)); + ImGui::GetWindowDrawList()->AddImage(self->resources->atlas.id, imageMin, imageMax, ATLAS_UV_ARGS(item.atlas)); } else - isActivated = ImGui::ImageButton(item.label.c_str(), self->resources->atlas.id, buttonSize, ATLAS_UV_ARGS(item.texture)); + isActivated = ImGui::ImageButton(item.label.c_str(), self->resources->atlas.id, buttonSize, ATLAS_UV_ARGS(item.atlas)); _imgui_item(self, item, &isActivated); if (item.color.is_normal()) ImGui::PopStyleColor(); @@ -481,26 +501,32 @@ static void _imgui_keyboard_navigation_set(bool value) if (!value) ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NavEnableKeyboard; } -static bool _imgui_item_yes_no_popup(Imgui* self, const ImguiItem& item) +static bool _imgui_item_option_popup(Imgui* self, const ImguiItem& item) { ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); if (ImGui::BeginPopupModal(item.popup.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { + self->isContextualActionsEnabled = false; + ImGui::Text(item.label.c_str()); ImGui::Separator(); - if (_imgui_item_button(self, IMGUI_POPUP_YES_BUTTON)) + if (_imgui_item_button(self, IMGUI_POPUP_CONFIRM_BUTTON)) { ImGui::CloseCurrentPopup(); ImGui::EndPopup(); + self->isContextualActionsEnabled = true; return true; } ImGui::SameLine(); - if (_imgui_item_button(self, IMGUI_POPUP_NO_BUTTON)) + if (_imgui_item_button(self, IMGUI_POPUP_CANCEL_BUTTON)) + { ImGui::CloseCurrentPopup(); + self->isContextualActionsEnabled = true; + } ImGui::EndPopup(); } @@ -639,7 +665,7 @@ static void _imgui_timeline(Imgui* self) drawList->AddText(textPosition, textColor, buffer.c_str()); } - drawList->AddImage(self->resources->atlas.id, positionStart, positionEnd, ATLAS_UV_ARGS(TEXTURE_FRAME)); + drawList->AddImage(self->resources->atlas.id, positionStart, positionEnd, ATLAS_UV_ARGS(ATLAS_FRAME_ALT)); } _imgui_item_end_child(); // IMGUI_TIMELINE_HEADER @@ -656,7 +682,7 @@ static void _imgui_timeline(Imgui* self) drawList = ImGui::GetWindowDrawList(); drawList->PushClipRect(clipRectMin, clipRectMax, true); - drawList->AddImage(self->resources->atlas.id, pos, ImVec2(pos.x + frameSize.x, pos.y + frameSize.y), ATLAS_UV_ARGS(TEXTURE_PICKER)); + drawList->AddImage(self->resources->atlas.id, pos, ImVec2(pos.x + frameSize.x, pos.y + frameSize.y), ATLAS_UV_ARGS(ATLAS_PICKER)); drawList->AddRectFilled(lineStart, lineEnd, IMGUI_PICKER_LINE_COLOR); drawList->PopClipRect(); @@ -669,7 +695,7 @@ static void _imgui_timeline(Imgui* self) if (!item) return; - ImVec2 buttonSize = ImVec2(TEXTURE_SIZE) + (defaultFramePadding * ImVec2(2, 2)); + ImVec2 buttonSize = ImVec2(ATLAS_SIZE_NORMAL) + (defaultFramePadding * ImVec2(2, 2)); Anm2Type& type = reference.itemType; Anm2Layer* layer = nullptr; @@ -749,14 +775,14 @@ static void _imgui_timeline(Imgui* self) if (type == ANM2_NULL) { - ImguiItem rectItem = null->isShowRect ? IMGUI_TIMELINE_ITEM_SHOW_RECT : IMGUI_TIMELINE_ITEM_HIDE_RECT; + const ImguiItem& rectItem = null->isShowRect ? IMGUI_TIMELINE_ITEM_SHOW_RECT : IMGUI_TIMELINE_ITEM_HIDE_RECT; if (_imgui_item_atlas_image_button(self, rectItem)) null->isShowRect = !null->isShowRect; ImGui::SameLine(0.0f, defaultItemSpacing.x); } - ImguiItem visibleItem = item->isVisible ? IMGUI_TIMELINE_ITEM_VISIBLE : IMGUI_TIMELINE_ITEM_INVISIBLE; + const ImguiItem& visibleItem = item->isVisible ? IMGUI_TIMELINE_ITEM_VISIBLE : IMGUI_TIMELINE_ITEM_INVISIBLE; if (_imgui_item_atlas_image_button(self, visibleItem)) item->isVisible = !item->isVisible; @@ -875,7 +901,7 @@ static void _imgui_timeline(Imgui* self) ImVec2 endPosition(endX, cursorPos.y + frameSize.y); drawList->AddRectFilled(startPosition, endPosition, bgColor); - drawList->AddImage(self->resources->atlas.id, startPosition, endPosition, ATLAS_UV_ARGS(TEXTURE_FRAME_ALT)); + drawList->AddImage(self->resources->atlas.id, startPosition, endPosition, ATLAS_UV_ARGS(ATLAS_FRAME)); } ImGui::SetCursorPos(startPos); @@ -886,14 +912,14 @@ static void _imgui_timeline(Imgui* self) reference.frameIndex = i; ImguiItem frameButton = *IMGUI_TIMELINE_FRAMES[type]; ImVec2 framePos = ImGui::GetCursorPos(); - frameButton.texture = frame.isInterpolated ? TEXTURE_CIRCLE : TEXTURE_SQUARE; + frameButton.atlas = frame.isInterpolated ? ATLAS_CIRCLE : ATLAS_SQUARE; frameButton.size = {frameSize.x * frame.delay, frameSize.y}; frameButton.isSelected = reference == *self->reference; if (type == ANM2_TRIGGERS) { framePos.x = startPos.x + (frameSize.x * frame.atFrame); - frameButton.texture = TEXTURE_TRIGGER; + frameButton.atlas = ATLAS_TRIGGER; } ImGui::SetCursorPos(framePos); @@ -1017,21 +1043,7 @@ static void _imgui_timeline(Imgui* self) Anm2Frame* frame = anm2_frame_from_reference(self->anm2, self->reference); _imgui_item_begin_child(IMGUI_TIMELINE_FOOTER_ITEM_CHILD); - - if(_imgui_item_button(self, IMGUI_TIMELINE_ADD_ITEM)) - ImGui::OpenPopup(IMGUI_TIMELINE_ADD_ITEM.popup.c_str()); - - if (ImGui::BeginPopup(IMGUI_TIMELINE_ADD_ITEM.popup.c_str())) - { - if (_imgui_item_selectable(self, IMGUI_TIMELINE_ADD_ITEM_LAYER)) - anm2_layer_add(self->anm2); - - if (_imgui_item_selectable(self, IMGUI_TIMELINE_ADD_ITEM_NULL)) - anm2_null_add(self->anm2); - - ImGui::EndPopup(); - } - + _imgui_item_button(self, IMGUI_TIMELINE_ADD_ITEM); ImGui::SameLine(); if (_imgui_item_button(self, IMGUI_TIMELINE_REMOVE_ITEM)) @@ -1059,7 +1071,7 @@ static void _imgui_timeline(Imgui* self) _imgui_item_begin_child(IMGUI_TIMELINE_FOOTER_OPTIONS_CHILD); - ImguiItem playPauseItem = self->preview->isPlaying ? IMGUI_TIMELINE_PAUSE : IMGUI_TIMELINE_PLAY; + const ImguiItem& playPauseItem = self->preview->isPlaying ? IMGUI_TIMELINE_PAUSE : IMGUI_TIMELINE_PLAY; if (_imgui_item_button(self, playPauseItem)) self->preview->isPlaying = !self->preview->isPlaying; @@ -1082,12 +1094,35 @@ static void _imgui_timeline(Imgui* self) ImGui::SameLine(); - if (_imgui_item_button(self, IMGUI_TIMELINE_BAKE)) + _imgui_item_button(self, IMGUI_TIMELINE_BAKE); + + ImGui::SameLine(); + + if (_imgui_item_button(self, IMGUI_TIMELINE_FIT_ANIMATION_LENGTH)) + anm2_animation_length_set(animation); + + ImGui::SameLine(); + _imgui_item_inputint(self, IMGUI_TIMELINE_ANIMATION_LENGTH, animation->frameNum); + ImGui::SameLine(); + _imgui_item_inputint(self, IMGUI_TIMELINE_FPS, self->anm2->fps); + ImGui::SameLine(); + _imgui_item_checkbox(self, IMGUI_TIMELINE_LOOP, animation->isLoop); + ImGui::SameLine(); + _imgui_item_text_inputtext(self, IMGUI_TIMELINE_CREATED_BY, self->anm2->createdBy); + + _imgui_item_end_child(); //IMGUI_TIMELINE_FOOTER_OPTIONS_CHILD + + _imgui_pending_popup_process(self); + + if (ImGui::BeginPopup(IMGUI_TIMELINE_ADD_ITEM.popup.c_str())) { - if (frame) - ImGui::OpenPopup(IMGUI_TIMELINE_BAKE.popup.c_str()); - else - ImGui::CloseCurrentPopup(); + if (_imgui_item_selectable(self, IMGUI_TIMELINE_ADD_ITEM_LAYER)) + anm2_layer_add(self->anm2); + + if (_imgui_item_selectable(self, IMGUI_TIMELINE_ADD_ITEM_NULL)) + anm2_null_add(self->anm2); + + ImGui::EndPopup(); } if (ImGui::BeginPopupModal(IMGUI_TIMELINE_BAKE.popup.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) @@ -1129,22 +1164,6 @@ static void _imgui_timeline(Imgui* self) ImGui::EndPopup(); } } - - ImGui::SameLine(); - - if (_imgui_item_button(self, IMGUI_TIMELINE_FIT_ANIMATION_LENGTH)) - anm2_animation_length_set(animation); - - ImGui::SameLine(); - _imgui_item_inputint(self, IMGUI_TIMELINE_ANIMATION_LENGTH, animation->frameNum); - ImGui::SameLine(); - _imgui_item_inputint(self, IMGUI_TIMELINE_FPS, self->anm2->fps); - ImGui::SameLine(); - _imgui_item_checkbox(self, IMGUI_TIMELINE_LOOP, animation->isLoop); - ImGui::SameLine(); - _imgui_item_text_inputtext(self, IMGUI_TIMELINE_CREATED_BY, self->anm2->createdBy); - - _imgui_item_end_child(); //IMGUI_TIMELINE_FOOTER_OPTIONS_CHILD _imgui_item_end(); // IMGUI_TIMELINE @@ -1159,37 +1178,237 @@ static void _imgui_taskbar(Imgui* self) ImGui::SetNextWindowPos(viewport->Pos); _imgui_item_begin(taskbarItem); + Anm2Animation* animation = anm2_animation_from_reference(self->anm2, self->reference); + _imgui_item_selectable(self, IMGUI_TASKBAR_FILE); + ImGui::SameLine(); + _imgui_item_selectable(self, IMGUI_TASKBAR_WIZARD); + ImGui::SameLine(); + _imgui_item_selectable(self, IMGUI_TASKBAR_PLAYBACK); + _imgui_pending_popup_process(self); if (ImGui::BeginPopup(IMGUI_TASKBAR_FILE.popup.c_str())) { - _imgui_item_selectable(self, IMGUI_FILE_NEW); - _imgui_item_selectable(self, IMGUI_FILE_OPEN); - _imgui_item_selectable(self, IMGUI_FILE_SAVE); - _imgui_item_selectable(self, IMGUI_FILE_SAVE_AS); + _imgui_item_selectable(self, IMGUI_FILE_NEW); // imgui_file_new + _imgui_item_selectable(self, IMGUI_FILE_OPEN); // imgui_file_open + _imgui_item_selectable(self, IMGUI_FILE_SAVE); // imgui_file_save + _imgui_item_selectable(self, IMGUI_FILE_SAVE_AS); // imgui_file_save_as + ImGui::EndPopup(); } - ImGui::SameLine(); - - _imgui_item_selectable(self, IMGUI_TASKBAR_WIZARD); - if (ImGui::BeginPopup(IMGUI_TASKBAR_WIZARD.popup.c_str())) { _imgui_item_selectable(self, IMGUI_TASKBAR_WIZARD_GENERATE_ANIMATION_FROM_GRID); - _imgui_item_selectable(self, IMGUI_TASKBAR_WIZARD_RECORD_GIF_ANIMATION); + ImGui::Separator(); + _imgui_item_selectable(self, IMGUI_TASKBAR_WIZARD_RENDER_ANIMATION); + ImGui::EndPopup(); } - + + _imgui_pending_popup_process(self); + + if (ImGui::BeginPopupModal(IMGUI_TASKBAR_WIZARD_RENDER_ANIMATION.popup.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) + { + if (animation) + { + RenderType& type = self->settings->renderType; + std::string& path = self->settings->renderPath; + std::string& format = self->settings->renderFormat; + std::string& ffmpegPath = self->settings->ffmpegPath; + + self->isContextualActionsEnabled = false; + + _imgui_item_begin_child(IMGUI_RENDER_ANIMATION_CHILD); + + if (_imgui_item_atlas_image_button(self, IMGUI_RENDER_ANIMATION_BROWSE)) + { + switch (self->settings->renderType) + { + case RENDER_PNG: + dialog_render_directory_set(self->dialog); + break; + default: + dialog_render_path_set(self->dialog); + break; + } + } + + if (self->dialog->isSelected && self->dialog->type == DIALOG_RENDER_PATH_SET) + { + path = self->dialog->path; + dialog_reset(self->dialog); + } + + ImGui::SameLine(); + _imgui_item_inputtext(self, IMGUI_RENDER_ANIMATION_LOCATION, path); + + if (_imgui_item_atlas_image_button(self, IMGUI_RENDER_ANIMATION_FFMPEG_BROWSE)) + dialog_ffmpeg_path_set(self->dialog); + + if (self->dialog->isSelected && self->dialog->type == DIALOG_FFMPEG_PATH_SET) + { + ffmpegPath = self->dialog->path; + dialog_reset(self->dialog); + } + + ImGui::SameLine(); + _imgui_item_inputtext(self, IMGUI_RENDER_ANIMATION_FFMPEG_PATH, ffmpegPath); + + _imgui_item_combo(self, IMGUI_RENDER_ANIMATION_OUTPUT, (s32*)&type); + + _imgui_item_inputtext(self, IMGUI_RENDER_ANIMATION_FORMAT, format); + + ImGui::Separator(); + + if (_imgui_item_button(self, IMGUI_RENDER_ANIMATION_CONFIRM)) + { + bool isRenderStart = true; + + switch (type) + { + case RENDER_PNG: + if (!std::filesystem::is_directory(path)) + { + imgui_message_queue_push(self, IMGUI_MESSAGE_RENDER_ANIMATION_DIRECTORY_ERROR); + isRenderStart = false; + } + break; + case RENDER_GIF: + case RENDER_WEBM: + if (!path_valid(path)) + { + imgui_message_queue_push(self, IMGUI_MESSAGE_RENDER_ANIMATION_PATH_ERROR); + isRenderStart = false; + } + default: + break; + } + + if (isRenderStart) + preview_render_start(self->preview); + else + self->preview->isRenderCancelled = true; + + ImGui::CloseCurrentPopup(); + } + + ImGui::SameLine(); + + if (_imgui_item_button(self, IMGUI_RENDER_ANIMATION_CANCEL)) + ImGui::CloseCurrentPopup(); + + _imgui_item_end_child(); // IMGUI_RENDER_ANIMATION_CHILD + ImGui::EndPopup(); + } + else + { + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + imgui_message_queue_push(self, IMGUI_MESSAGE_RENDER_ANIMATION_NO_SELECTED_ANIMATION_ERROR); + } + } + + _imgui_pending_popup_process(self); + + if (ImGui::BeginPopupModal(IMGUI_RENDER_ANIMATION_CONFIRM.popup.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) + { + auto rendering_end = [&]() + { + preview_render_end(self->preview); + self->isContextualActionsEnabled = true; + ImGui::CloseCurrentPopup(); + }; + + RenderType& type = self->settings->renderType; + std::string& format = self->settings->renderFormat; + std::vector& frames = self->preview->renderFrames; + std::string path = std::string(self->settings->renderPath.c_str()); + + if (self->preview->isRenderCancelled) + { + rendering_end(); + self->preview->isRenderCancelled = false; + } + + if (!animation) + { + imgui_message_queue_push(self, IMGUI_MESSAGE_RENDER_ANIMATION_NO_ANIMATION_ERROR); + rendering_end(); + } + + _imgui_item_begin_child(IMGUI_RENDERING_ANIMATION_CHILD); + + f32 progress = self->preview->time / (animation->frameNum - 1); + ImGui::ProgressBar(progress); + + if (_imgui_item_button(self, IMGUI_RENDERING_ANIMATION_CANCEL)) + self->preview->isRenderCancelled = true; + + _imgui_item_end_child(); // IMGUI_RENDERING_ANIMATION_CHILD + + if (self->preview->isRenderFinished && frames.empty()) + { + imgui_message_queue_push(self, IMGUI_MESSAGE_RENDER_ANIMATION_NO_FRAMES_ERROR); + rendering_end(); + } + + if (self->preview->isRenderFinished) + { + switch (type) + { + case RENDER_PNG: + { + std::filesystem::path workingPath = std::filesystem::current_path(); + std::filesystem::current_path(path); + + for (auto [i, frame] : std::views::enumerate(frames)) + { + std::string framePath = std::vformat(format, std::make_format_args(i)); + framePath = path_extension_change(framePath, RENDER_EXTENSIONS[type]); + if (!frame.isInvalid) + texture_from_gl_write(&frame, framePath); + } + + std::filesystem::current_path(workingPath); + imgui_message_queue_push(self, std::format(IMGUI_MESSAGE_RENDER_ANIMATION_FRAMES_SAVE_FORMAT, path)); + break; + } + case RENDER_GIF: + case RENDER_WEBM: + { + std::string ffmpegPath = std::string(self->settings->ffmpegPath.c_str()); + path = path_extension_change(path, RENDER_EXTENSIONS[type]); + + if (ffmpeg_render(ffmpegPath, path, frames, self->preview->canvas.size, self->anm2->fps, type)) + { + std::string message = std::format(IMGUI_MESSAGE_RENDER_ANIMATION_SAVE_FORMAT, path); + imgui_message_queue_push(self, message); + log_info(message); + } + else + { + std::string message = std::format(IMGUI_MESSAGE_RENDER_ANIMATION_FFMPEG_ERROR, path); + imgui_message_queue_push(self, message); + log_error(message); + } + break; + } + default: + break; + } + + rendering_end(); + } + + ImGui::EndPopup(); + } + if (ImGui::BeginPopupModal(IMGUI_TASKBAR_WIZARD_GENERATE_ANIMATION_FROM_GRID.popup.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::EndPopup(); } - ImGui::SameLine(); - - _imgui_item_selectable(self, IMGUI_TASKBAR_PLAYBACK); - if (ImGui::BeginPopup(IMGUI_TASKBAR_PLAYBACK.popup.c_str())) { _imgui_item_checkbox(self, IMGUI_PLAYBACK_ALWAYS_LOOP, self->settings->playbackIsLoop); @@ -1197,6 +1416,30 @@ static void _imgui_taskbar(Imgui* self) } _imgui_item_end(); + + if (self->dialog->isSelected) + { + switch (self->dialog->type) + { + case DIALOG_ANM2_OPEN: + *self->reference = Anm2Reference{}; + resources_textures_free(self->resources); + anm2_deserialize(self->anm2, self->resources, self->dialog->path); + window_title_from_path_set(self->window, self->dialog->path); + snapshots_reset(self->snapshots); + imgui_message_queue_push(self, std::format(IMGUI_MESSAGE_FILE_OPEN_FORMAT, self->dialog->path)); + break; + case DIALOG_ANM2_SAVE: + anm2_serialize(self->anm2, self->dialog->path); + window_title_from_path_set(self->window, self->dialog->path); + imgui_message_queue_push(self, std::format(IMGUI_MESSAGE_FILE_SAVE_FORMAT, self->dialog->path)); + break; + default: + break; + } + + dialog_reset(self->dialog); + } } static void _imgui_tools(Imgui* self) @@ -1345,8 +1588,21 @@ static void _imgui_animations(Imgui* self) } ImGui::SameLine(); - _imgui_item_button(self, IMGUI_ANIMATIONS_MERGE); + ImGui::SameLine(); + + if (_imgui_item_button(self, IMGUI_ANIMATION_REMOVE) && animation) + { + anm2_animation_remove(self->anm2, self->reference->animationID); + anm2_reference_clear(self->reference); + } + + ImGui::SameLine(); + + if (_imgui_item_button(self, IMGUI_ANIMATION_DEFAULT) && animation) + self->anm2->defaultAnimationID = self->reference->animationID; + + _imgui_pending_popup_process(self); if (ImGui::BeginPopupModal(IMGUI_ANIMATIONS_MERGE.popup.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { @@ -1462,18 +1718,9 @@ static void _imgui_animations(Imgui* self) ImGui::EndPopup(); } - ImGui::SameLine(); - - if (_imgui_item_button(self, IMGUI_ANIMATION_REMOVE) && animation) - { - anm2_animation_remove(self->anm2, self->reference->animationID); - anm2_reference_clear(self->reference); - } - - ImGui::SameLine(); - - if (_imgui_item_button(self, IMGUI_ANIMATION_DEFAULT) && animation) - self->anm2->defaultAnimationID = self->reference->animationID; + + + _imgui_item_end_child(); // IMGUI_ANIMATIONS_OPTIONS_CHILD) _imgui_item_end(); @@ -1598,7 +1845,7 @@ static void _imgui_spritesheets(Imgui* self) spritesheetPreviewSize.y = IMGUI_SPRITESHEET_PREVIEW_SIZE.x / spritesheetAspect; if (texture->isInvalid) - _imgui_atlas_image(self, TEXTURE_NONE); + _imgui_atlas_image(self, ATLAS_NONE); else ImGui::Image(texture->id, spritesheetPreviewSize); @@ -1614,8 +1861,9 @@ static void _imgui_spritesheets(Imgui* self) _imgui_item_begin_child(IMGUI_SPRITESHEETS_OPTIONS_CHILD); - _imgui_item_button(self, IMGUI_SPRITESHEETS_ADD); - + if (_imgui_item_button(self, IMGUI_SPRITESHEETS_ADD)) + dialog_spritesheet_add(self->dialog); + ImGui::SameLine(); if (_imgui_item_button(self, IMGUI_SPRITESHEETS_RELOAD)) @@ -1634,13 +1882,30 @@ static void _imgui_spritesheets(Imgui* self) ImGui::SameLine(); - if (_imgui_item_button(self, IMGUI_SPRITESHEETS_REPLACE)) + if (_imgui_item_button(self, IMGUI_SPRITESHEETS_REPLACE) && highlightedID != ID_NONE) + dialog_spritesheet_replace(self->dialog, highlightedID); + + if (self->dialog->isSelected) { - if (highlightedID != ID_NONE) + switch (self->dialog->type) { - self->dialog->replaceID = highlightedID; - dialog_png_replace(self->dialog); + case DIALOG_SPRITESHEET_ADD: + { + s32 id = map_next_id_get(self->resources->textures); + self->anm2->spritesheets[id] = Anm2Spritesheet{}; + self->anm2->spritesheets[id].path = self->dialog->path; + resources_texture_init(self->resources, self->dialog->path, id); + break; + } + case DIALOG_SPRITESHEET_REPLACE: + self->anm2->spritesheets[self->dialog->replaceID].path = self->dialog->path; + resources_texture_init(self->resources, self->dialog->path, self->dialog->replaceID); + break; + default: + break; } + + dialog_reset(self->dialog); } ImGui::SameLine(); @@ -1688,7 +1953,7 @@ static void _imgui_spritesheets(Imgui* self) Anm2Spritesheet* spritesheet = &self->anm2->spritesheets[id]; Texture* texture = &self->resources->textures[id]; texture_from_gl_write(texture, spritesheet->path); - imgui_message_queue_push(self, std::format(IMGUI_ACTION_SPRITESHEET_SAVE_FORMAT, id, spritesheet->path)); + imgui_message_queue_push(self, std::format(IMGUI_MESSAGE_SPRITESHEET_SAVE_FORMAT, id, spritesheet->path)); std::filesystem::current_path(workingPath); } } @@ -1736,29 +2001,25 @@ static void _imgui_animation_preview(Imgui* self) _imgui_item_begin_child(IMGUI_ANIMATION_PREVIEW_BACKGROUND_SETTINGS); _imgui_item_coloredit4(self, IMGUI_ANIMATION_PREVIEW_BACKGROUND_COLOR, self->settings->previewBackgroundColor); - std::vector animationStrings; - std::vector animationLabels; std::vector animationIDs; + ImguiItem animationOverlayItem = IMGUI_ANIMATION_PREVIEW_OVERLAY; + s32 animationOverlayCount = self->anm2->animations.size() + 1; - animationStrings.reserve(self->anm2->animations.size() + 1); - animationIDs.reserve(self->anm2->animations.size() + 1); - animationLabels.reserve(self->anm2->animations.size() + 1); - + animationIDs.reserve(animationOverlayCount); + animationOverlayItem.items.reserve(animationOverlayCount); animationIDs.push_back(ID_NONE); - animationStrings.push_back(IMGUI_EVENT_NONE); - animationLabels.push_back(animationStrings.back().c_str()); - + animationOverlayItem.items.push_back(IMGUI_ANIMATION_NONE); + for (auto & [id, animation] : self->anm2->animations) { animationIDs.push_back(id); - animationStrings.push_back(animation.name); - animationLabels.push_back(animationStrings.back().c_str()); + animationOverlayItem.items.push_back(animation.name); } - s32 selectedAnimationID = std::find(animationIDs.begin(), animationIDs.end(), self->preview->animationOverlayID) - animationIDs.begin(); + s32 animationIndex = std::find(animationIDs.begin(), animationIDs.end(), self->preview->animationOverlayID) - animationIDs.begin(); - if (_imgui_item_combo(self, IMGUI_ANIMATION_PREVIEW_OVERLAY, &selectedAnimationID, animationLabels.data(), (s32)animationLabels.size())) - self->preview->animationOverlayID = animationIDs[selectedAnimationID]; + if (_imgui_item_combo(self, animationOverlayItem, &animationIndex)) + self->preview->animationOverlayID = animationIDs[animationIndex]; _imgui_item_dragfloat(self, IMGUI_ANIMATION_PREVIEW_OVERLAY_TRANSPARENCY, self->settings->previewOverlayTransparency); _imgui_item_end_child(); @@ -1770,7 +2031,9 @@ static void _imgui_animation_preview(Imgui* self) ImGui::SameLine(); _imgui_item_coloredit4(self, IMGUI_ANIMATION_PREVIEW_AXIS_COLOR, self->settings->previewAxisColor); _imgui_item_checkbox(self, IMGUI_ANIMATION_PREVIEW_ROOT_TRANSFORM, self->settings->previewIsRootTransform); - _imgui_item_checkbox(self, IMGUI_ANIMATION_PREVIEW_SHOW_PIVOT, self->settings->previewIsShowPivot); + _imgui_item_checkbox(self, IMGUI_ANIMATION_PREVIEW_PIVOTS, self->settings->previewIsPivots); + ImGui::SameLine(); + _imgui_item_checkbox(self, IMGUI_ANIMATION_PREVIEW_TARGETS, self->settings->previewIsTargets); ImGui::SameLine(); _imgui_item_checkbox(self, IMGUI_ANIMATION_PREVIEW_BORDER, self->settings->previewIsBorder); _imgui_item_end_child(); @@ -1995,6 +2258,8 @@ static void _imgui_spritesheet_editor(Imgui* self) } _imgui_item_end(); + + } static void _imgui_frame_properties(Imgui* self) @@ -2045,29 +2310,25 @@ static void _imgui_frame_properties(Imgui* self) } else if (type == ANM2_TRIGGERS) { - std::vector eventStrings; - std::vector eventLabels; std::vector eventIDs; + ImguiItem framePropertiesEventItem = IMGUI_FRAME_PROPERTIES_EVENT; + s32 eventComboCount = self->anm2->events.size() + 1; - eventStrings.reserve(self->anm2->events.size() + 1); - eventIDs.reserve(self->anm2->events.size() + 1); - eventLabels.reserve(self->anm2->events.size() + 1); - + framePropertiesEventItem.items.reserve(eventComboCount); + eventIDs.reserve(eventComboCount); + framePropertiesEventItem.items.push_back(IMGUI_EVENT_NONE); eventIDs.push_back(ID_NONE); - eventStrings.push_back(IMGUI_EVENT_NONE); - eventLabels.push_back(eventStrings.back().c_str()); for (auto & [id, event] : self->anm2->events) { eventIDs.push_back(id); - eventStrings.push_back(event.name); - eventLabels.push_back(eventStrings.back().c_str()); + framePropertiesEventItem.items.push_back(event.name); } - s32 selectedEventIndex = std::find(eventIDs.begin(), eventIDs.end(), frame->eventID) - eventIDs.begin(); - - if (_imgui_item_combo(self, IMGUI_FRAME_PROPERTIES_EVENT, &selectedEventIndex, eventLabels.data(), (s32)eventLabels.size())) - frame->eventID = eventIDs[selectedEventIndex]; + s32 eventIndex = std::find(eventIDs.begin(), eventIDs.end(), frame->eventID) - eventIDs.begin(); + + if (_imgui_item_combo(self, framePropertiesEventItem, &eventIndex)) + frame->eventID = eventIDs[eventIndex]; _imgui_item_inputint(self, IMGUI_FRAME_PROPERTIES_AT_FRAME, frame->atFrame); frame->atFrame = std::clamp(frame->atFrame, 0, animation->frameNum - 1); @@ -2109,7 +2370,7 @@ static void _imgui_messages(Imgui* self) self->messageQueue.erase(self->messageQueue.begin() + i); continue; } - + ImGui::SetNextWindowPos(position, ImGuiCond_Always, {1.0f, 1.0f}); ImGui::PushStyleColor(ImGuiCol_Border, borderColor); ImGui::PushStyleColor(ImGuiCol_Text, textColor); @@ -2124,36 +2385,11 @@ static void _imgui_messages(Imgui* self) position.y -= windowSize.y + IMGUI_MESSAGE_PADDING; } - - if (self->dialog->isJustSelected) - { - switch (self->dialog->lastType) - { - case DIALOG_ANM2_OPEN: - imgui_message_queue_push(self, std::format(IMGUI_ACTION_FILE_OPEN_FORMAT, self->dialog->lastPath)); - break; - case DIALOG_ANM2_SAVE: - imgui_message_queue_push(self, std::format(IMGUI_ACTION_FILE_SAVE_FORMAT, self->dialog->lastPath)); - break; - default: - break; - } - - dialog_reset(self->dialog); - } } static void _imgui_persistent(Imgui* self) { - if (self->preview->isRecording) - { - ImVec2 mousePos = ImGui::GetMousePos(); - - ImGui::SetNextWindowPos(ImVec2(mousePos.x + IMGUI_TOOLTIP_OFFSET.x, mousePos.y + IMGUI_TOOLTIP_OFFSET.y)); - ImGui::BeginTooltip(); - _imgui_item_atlas_image_text(self, IMGUI_RECORDING); - ImGui::EndTooltip(); - } + if (!self->isContextualActionsEnabled) return; if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) ImGui::OpenPopup(IMGUI_CONTEXT_MENU.popup.c_str()); @@ -2251,9 +2487,7 @@ void imgui_update(Imgui* self) _imgui_messages(self); _imgui_persistent(self); - self->isHotkeysEnabled = !self->isRename && !self->isChangeValue; - - if (self->isHotkeysEnabled) + if (self->isContextualActionsEnabled) { for (const auto& hotkey : imgui_hotkey_registry()) { @@ -2286,7 +2520,7 @@ void imgui_update(Imgui* self) } } - if (_imgui_item_yes_no_popup(self, IMGUI_EXIT_CONFIRMATION)) + if (_imgui_item_option_popup(self, IMGUI_EXIT_CONFIRMATION)) self->isQuit = true; } diff --git a/src/imgui.h b/src/imgui.h index b5d200d..332b073 100644 --- a/src/imgui.h +++ b/src/imgui.h @@ -10,6 +10,8 @@ #include "tool.h" #include "window.h" +#include "ffmpeg.h" + #define IMGUI_IMPL_OPENGL_LOADER_CUSTOM #define IMGUI_ENABLE_DOCKING #define IM_VEC2_CLASS_EXTRA \ @@ -35,56 +37,69 @@ #include #include -#define IMGUI_ANIMATION_DEFAULT_FORMAT "(*) {}" -#define IMGUI_CHORD_NONE (ImGuiMod_None) -#define IMGUI_EVENT_NONE "None" -#define IMGUI_FRAME_BORDER 2.0f -#define IMGUI_FRAME_PROPERTIES_NO_FRAME "Select a frame to show properties..." -#define IMGUI_ITEM_SELECTABLE_EDITABLE_LABEL "## Editing" -#define IMGUI_OPENGL_VERSION "#version 330" -#define IMGUI_PICKER_LINE_COLOR IM_COL32(255, 255, 255, 255) -#define IMGUI_POSITION_FORMAT "Position: {{{:6}, {:6}}}" -#define IMGUI_SPRITESHEET_FORMAT "#{} {}" -#define IMGUI_TIMELINE_CHILD_ID_LABEL "#{} {}" -#define IMGUI_TIMELINE_FOOTER_HEIGHT 40 #define IMGUI_ANIMATIONS_FOOTER_HEIGHT 40 -#define IMGUI_EVENTS_FOOTER_HEIGHT 40 -#define IMGUI_SPRITESHEETS_FOOTER_HEIGHT 65 -#define IMGUI_TIMELINE_FRAME_BORDER 2 -#define IMGUI_TIMELINE_FRAME_LABEL_FORMAT "## {}" -#define IMGUI_TIMELINE_FRAME_MULTIPLE 5 -#define IMGUI_TIMELINE_MERGE -#define IMGUI_TIMELINE_NO_ANIMATION "Select an animation to show timeline..." -#define IMGUI_TIMELINE_PICKER_LINE_WIDTH 2.0f -#define IMGUI_TIMELINE_SPRITESHEET_ID_FORMAT "#{}" - -#define IMGUI_INVISIBLE_LABEL_MARKER "##" #define IMGUI_ANIMATIONS_OPTIONS_ROW_ITEM_COUNT 5 +#define IMGUI_CHORD_NONE (ImGuiMod_None) +#define IMGUI_EVENTS_FOOTER_HEIGHT 40 #define IMGUI_EVENTS_OPTIONS_ROW_ITEM_COUNT 2 -#define IMGUI_SPRITESHEETS_OPTIONS_FIRST_ROW_ITEM_COUNT 4 -#define IMGUI_SPRITESHEETS_OPTIONS_SECOND_ROW_ITEM_COUNT 3 -#define IMGUI_TIMELINE_FOOTER_ITEM_CHILD_ITEM_COUNT 2 -#define IMGUI_TIMELINE_BAKE_OPTIONS_CHILD_ROW_ITEM_COUNT 2 -#define IMGUI_TIMELINE_MERGE_OPTIONS_ROW_ITEM_COUNT 2 +#define IMGUI_FRAME_BORDER 2.0f #define IMGUI_MESSAGE_DURATION 3.0f #define IMGUI_MESSAGE_PADDING 10.0f -#define IMGUI_MESSAGE_FORMAT "## Message {}" -#define IMGUI_MESSAGE_UNDO_FORMAT "Undo: {}" -#define IMGUI_MESSAGE_REDO_FORMAT "Redo: {}" +#define IMGUI_PICKER_LINE_COLOR IM_COL32(255, 255, 255, 255) +#define IMGUI_POPUP_OPTION_CHILD_ROW_ITEM_COUNT 2 +#define IMGUI_RENDER_ANIMATION_OPTIONS_ROW_ITEM_COUNT 2 +#define IMGUI_SPRITESHEETS_FOOTER_HEIGHT 65 +#define IMGUI_SPRITESHEETS_OPTIONS_FIRST_ROW_ITEM_COUNT 4 +#define IMGUI_SPRITESHEETS_OPTIONS_SECOND_ROW_ITEM_COUNT 3 +#define IMGUI_TIMELINE_BAKE_OPTIONS_CHILD_ROW_ITEM_COUNT 2 +#define IMGUI_TIMELINE_FOOTER_HEIGHT 40 +#define IMGUI_TIMELINE_FOOTER_ITEM_CHILD_ITEM_COUNT 2 +#define IMGUI_TIMELINE_FRAME_BORDER 2 +#define IMGUI_TIMELINE_FRAME_MULTIPLE 5 +#define IMGUI_TIMELINE_MERGE +#define IMGUI_TIMELINE_MERGE_OPTIONS_ROW_ITEM_COUNT 2 +#define IMGUI_TIMELINE_PICKER_LINE_WIDTH 2.0f -#define IMGUI_ACTION_FILE_SAVE_FORMAT "Saved anm2 to: {}" -#define IMGUI_ACTION_FILE_OPEN_FORMAT "Opened anm2: {}" -#define IMGUI_ACTION_SPRITESHEET_SAVE_FORMAT "Saved spritesheet #{} to: {}" -#define IMGUI_ACTION_TRIGGER_MOVE "Trigger AtFrame" -#define IMGUI_ACTION_FRAME_SWAP "Frame Swap" -#define IMGUI_ACTION_ANIMATION_SWAP "Animation Swap" -#define IMGUI_ACTION_FRAME_TRANSFORM "Frame Transform" #define IMGUI_ACTION_FRAME_CROP "Frame Crop" +#define IMGUI_ACTION_FRAME_SWAP "Frame Swap" +#define IMGUI_ACTION_FRAME_TRANSFORM "Frame Transform" +#define IMGUI_ACTION_ANIMATION_SWAP "Animation Swap" +#define IMGUI_ACTION_TRIGGER_MOVE "Trigger AtFrame" + +#define IMGUI_MESSAGE_FILE_OPEN_FORMAT "Opened anm2: {}" +#define IMGUI_MESSAGE_FILE_SAVE_FORMAT "Saved anm2 to: {}" +#define IMGUI_MESSAGE_RENDER_ANIMATION_FRAMES_SAVE_FORMAT "Saved rendered frames to: {}" +#define IMGUI_MESSAGE_RENDER_ANIMATION_SAVE_FORMAT "Saved rendered animation to: {}" +#define IMGUI_MESSAGE_RENDER_ANIMATION_NO_SELECTED_ANIMATION_ERROR "Select an animation first to render!" +#define IMGUI_MESSAGE_RENDER_ANIMATION_NO_ANIMATION_ERROR "No animation selected; rendering cancelled." +#define IMGUI_MESSAGE_RENDER_ANIMATION_NO_FRAMES_ERROR "No frames to render; rendering cancelled." +#define IMGUI_MESSAGE_RENDER_ANIMATION_DIRECTORY_ERROR "Invalid directory! Make sure it's valid and you have write permissions." +#define IMGUI_MESSAGE_RENDER_ANIMATION_PATH_ERROR "Invalid path! Make sure it's valid and you have write permissions." +#define IMGUI_MESSAGE_RENDER_ANIMATION_FFMPEG_PATH_ERROR "Invalid FFmpeg path! Make sure you have it installed and the path is correct." +#define IMGUI_MESSAGE_RENDER_ANIMATION_FFMPEG_ERROR "FFmpeg could not render animation! Check paths or your FFmpeg installation." +#define IMGUI_MESSAGE_SPRITESHEET_SAVE_FORMAT "Saved spritesheet #{} to: {}" +#define IMGUI_ANIMATION_DEFAULT_FORMAT "(*) {}" +#define IMGUI_ANIMATION_NONE "None" +#define IMGUI_BUFFER_MAX 255 +#define IMGUI_EVENT_NONE "None" +#define IMGUI_FRAME_PROPERTIES_NO_FRAME "Select a frame to show properties..." +#define IMGUI_INVISIBLE_LABEL_MARKER "##" +#define IMGUI_ITEM_SELECTABLE_EDITABLE_LABEL "## Editing" +#define IMGUI_MESSAGE_FORMAT "## Message {}" +#define IMGUI_MESSAGE_REDO_FORMAT "Redo: {}" +#define IMGUI_MESSAGE_UNDO_FORMAT "Undo: {}" +#define IMGUI_OPENGL_VERSION "#version 330" +#define IMGUI_POSITION_FORMAT "Position: ({:8}, {:8})" +#define IMGUI_SPRITESHEET_FORMAT "#{} {}" +#define IMGUI_TIMELINE_CHILD_ID_LABEL "#{} {}" +#define IMGUI_TIMELINE_FRAME_LABEL_FORMAT "## {}" +#define IMGUI_TIMELINE_NO_ANIMATION "Select an animation to show timeline..." +#define IMGUI_TIMELINE_SPRITESHEET_ID_FORMAT "#{}" #define IMGUI_SPACING 4 const ImVec2 IMGUI_TIMELINE_FRAME_SIZE = {16, 40}; -const ImVec2 IMGUI_TIMELINE_FRAME_CONTENT_OFFSET = {TEXTURE_SIZE_SMALL.x * 0.25f, (IMGUI_TIMELINE_FRAME_SIZE.y * 0.5f) - (TEXTURE_SIZE_SMALL.y * 0.5f)}; +const ImVec2 IMGUI_TIMELINE_FRAME_CONTENT_OFFSET = {ATLAS_SIZE_SMALL.x * 0.25f, (IMGUI_TIMELINE_FRAME_SIZE.y * 0.5f) - (ATLAS_SIZE_SMALL.y * 0.5f)}; const ImVec2 IMGUI_TIMELINE_ITEM_SELECTABLE_SIZE = {150, 0}; const ImVec2 IMGUI_TIMELINE_ITEM_SIZE = {300, 40}; @@ -102,7 +117,7 @@ const ImVec2 IMGUI_FRAME_PROPERTIES_FLIP_BUTTON_SIZE = {100, 0}; const ImVec2 IMGUI_SPRITESHEET_PREVIEW_SIZE = {125.0, 125.0}; const ImVec2 IMGUI_TOOLTIP_OFFSET = {16, 8}; const vec2 IMGUI_SPRITESHEET_EDITOR_CROP_FORGIVENESS = {1, 1}; -const ImVec2 IMGUI_CANVAS_CHILD_SIZE = {200, 85}; +const ImVec2 IMGUI_CANVAS_CHILD_SIZE = {230, 85}; const ImGuiKey IMGUI_INPUT_DELETE = ImGuiKey_Delete; const ImGuiKey IMGUI_INPUT_LEFT = ImGuiKey_LeftArrow; @@ -136,6 +151,13 @@ struct ImguiMessage f32 timeRemaining; }; +enum ImguiPopupType +{ + IMGUI_POPUP_NONE, + IMGUI_POPUP_BY_ITEM, + IMGUI_POPUP_CENTER_SCREEN +}; + struct Imgui { Dialog* dialog = nullptr; @@ -149,8 +171,11 @@ struct Imgui Clipboard* clipboard = nullptr; SDL_Window* window = nullptr; SDL_GLContext* glContext = nullptr; + std::string pendingPopup{}; + ImguiPopupType pendingPopupType = IMGUI_POPUP_NONE; + ImVec2 pendingPopupPosition{}; std::vector messageQueue; - bool isHotkeysEnabled = true; + bool isContextualActionsEnabled = true; bool isRename = false; bool isChangeValue = false; bool isQuit = false; @@ -173,12 +198,6 @@ static std::vector& imgui_hotkey_registry() return registry; } -enum PopupType -{ - IMGUI_POPUP_BY_ITEM, - IMGUI_POPUP_CENTER_SCREEN -}; - struct ImguiColorSet { ImVec4 normal{}; @@ -199,20 +218,21 @@ struct ImguiItemBuilder std::string dragDrop{}; std::string format = "%.1f"; std::string focusWindow{}; + std::vector items{}; ImguiFunction function = nullptr; ImGuiKeyChord chord = IMGUI_CHORD_NONE; - TextureType texture = TEXTURE_NONE; - PopupType popupType = IMGUI_POPUP_BY_ITEM; + AtlasType atlas = ATLAS_NONE; + ImguiPopupType popupType = IMGUI_POPUP_BY_ITEM; bool isUndoable = false; bool isSizeToText = true; bool isSizeToChild = false; ImguiColorSet color{}; ImVec2 size{}; ImVec2 contentOffset{}; - s32 childRowItemCount{}; + s32 childRowItemCount = 1; f64 speed{}; f64 min{}; - f64 max{}; + f64 max = IMGUI_BUFFER_MAX; s32 border{}; s32 step = 1; s32 stepFast = 1; @@ -231,10 +251,11 @@ struct ImguiItem std::string dragDrop{}; std::string format = "%.1f"; std::string focusWindow{}; + std::vector items{}; ImguiFunction function = nullptr; ImGuiKeyChord chord = IMGUI_CHORD_NONE; - TextureType texture = TEXTURE_NONE; - PopupType popupType = IMGUI_POPUP_BY_ITEM; + AtlasType atlas = ATLAS_NONE; + ImguiPopupType popupType = IMGUI_POPUP_BY_ITEM; bool isUndoable = false; bool isInactive = false; bool isSizeToText = true; @@ -242,7 +263,7 @@ struct ImguiItem bool isSelected = false; f64 speed{}; f64 min{}; - f64 max{}; + f64 max = IMGUI_BUFFER_MAX; s32 border{}; s32 childRowItemCount = 1; s32 step = 1; @@ -276,10 +297,11 @@ struct ImguiItem dragDrop = builder.dragDrop; format = builder.format; focusWindow = builder.focusWindow; + items = builder.items; function = builder.function; chord = builder.chord; popupType = builder.popupType; - texture = builder.texture; + atlas = builder.atlas; isUndoable = builder.isUndoable; isSizeToText = builder.isSizeToText; isSizeToChild = builder.isSizeToChild; @@ -363,7 +385,7 @@ static inline void imgui_file_save(Imgui* self) else { anm2_serialize(self->anm2, self->anm2->path); - imgui_message_queue_push(self, std::format(IMGUI_ACTION_FILE_SAVE_FORMAT, self->anm2->path)); + imgui_message_queue_push(self, std::format(IMGUI_MESSAGE_FILE_SAVE_FORMAT, self->anm2->path)); } } @@ -372,20 +394,6 @@ static inline void imgui_file_save_as(Imgui* self) dialog_anm2_save(self->dialog); } -static inline void imgui_png_open(Imgui* self) -{ - dialog_png_open(self->dialog); -} - -static inline void imgui_generate_gif_animation(Imgui* self) -{ - if (anm2_animation_from_reference(self->anm2, self->reference)) - { - self->preview->isRecording = true; - self->preview->time = 0; - } -} - static inline void imgui_undo_stack_push(Imgui* self, const std::string& action = SNAPSHOT_ACTION) { Snapshot snapshot = {*self->anm2, *self->reference, self->preview->time, action}; @@ -549,11 +557,90 @@ const inline ImguiItem IMGUI_TASKBAR_WIZARD_GENERATE_ANIMATION_FROM_GRID = Imgui .popupType = IMGUI_POPUP_CENTER_SCREEN }); -const inline ImguiItem IMGUI_TASKBAR_WIZARD_RECORD_GIF_ANIMATION = ImguiItem +const inline ImguiItem IMGUI_TASKBAR_WIZARD_RENDER_ANIMATION = ImguiItem ({ - .label = "G&enerate GIF Animation", - .tooltip = "Generates a GIF animation from the current animation.", - .function = imgui_generate_gif_animation + .label = "&Render Animation", + .tooltip = "Renders the current animation preview; output options can be customized.", + .popup = "Render Animation", + .popupType = IMGUI_POPUP_CENTER_SCREEN +}); + +const inline ImguiItem IMGUI_RENDER_ANIMATION_CHILD = ImguiItem +({ + .label = "## Render Animation Child", + .size = {600, 125} +}); + +const inline ImguiItem IMGUI_RENDER_ANIMATION_LOCATION = ImguiItem +({ + .label = "Location", + .tooltip = "Set the rendered animation's output location.", + .isSizeToChild = true +}); + +const inline ImguiItem IMGUI_RENDER_ANIMATION_BROWSE = ImguiItem +({ + .label = "## Location Browse", + .atlas = ATLAS_FOLDER +}); + +const inline ImguiItem IMGUI_RENDER_ANIMATION_OUTPUT = ImguiItem +({ + .label = "Output", + .tooltip = "Select the rendered animation output.\nIt can either be one animated image or a sequence of frames.", + .items = {std::begin(RENDER_TYPE_STRINGS), std::end(RENDER_TYPE_STRINGS)}, + .isSizeToChild = true +}); + +const inline ImguiItem IMGUI_RENDER_ANIMATION_FORMAT = ImguiItem +({ + .label = "Format", + .tooltip = "(PNG images only).\nSet the format of each output frame; i.e., its filename.\nThe format will only take one argument; that being the frame's index.\nFor example, a format like \"{}.png\" will export a frame of index 0 as \"0.png\".", + .isSizeToChild = true +}); + +const inline ImguiItem IMGUI_RENDER_ANIMATION_FFMPEG_PATH = ImguiItem +({ + .label = "FFmpeg Path", + .tooltip = "Sets the path FFmpeg currently resides in.\nFFmpeg is required for rendering animations.\nDownload it from https://ffmpeg.org/, your package manager, or wherever else.", + .isSizeToChild = true +}); + +const inline ImguiItem IMGUI_RENDER_ANIMATION_FFMPEG_BROWSE = ImguiItem +({ + .label = "## FFMpeg Browse", + .atlas = ATLAS_FOLDER +}); + +const inline ImguiItem IMGUI_RENDER_ANIMATION_CONFIRM = ImguiItem +({ + .label = "Render", + .tooltip = "Render the animation with the chosen options.", + .popup = "Rendering Animation...", + .popupType = IMGUI_POPUP_CENTER_SCREEN, + .isSizeToChild = true, + .childRowItemCount = IMGUI_RENDER_ANIMATION_OPTIONS_ROW_ITEM_COUNT +}); + +const inline ImguiItem IMGUI_RENDER_ANIMATION_CANCEL = ImguiItem +({ + .label = "Cancel", + .tooltip = "Cancel rendering animation.", + .isSizeToChild = true, + .childRowItemCount = IMGUI_RENDER_ANIMATION_OPTIONS_ROW_ITEM_COUNT +}); + +const inline ImguiItem IMGUI_RENDERING_ANIMATION_CHILD = ImguiItem +({ + .label = "## Render Animation Child", + .size = {300, 60}, + .flags = true +}); + +const inline ImguiItem IMGUI_RENDERING_ANIMATION_CANCEL = ImguiItem +({ + .label = "Cancel", + .isSizeToChild = true }); const inline ImguiItem IMGUI_TASKBAR_PLAYBACK = ImguiItem @@ -583,7 +670,7 @@ const inline ImguiItem IMGUI_ANIMATION = ImguiItem .label = "## Animation Item", .action = "Select Animation", .dragDrop = "## Animation Drag Drop", - .texture = TEXTURE_ANIMATION, + .atlas = ATLAS_ANIMATION, .isUndoable = true, .isSizeToText = false }); @@ -731,7 +818,7 @@ const inline ImguiItem IMGUI_EVENTS_CHILD = ImguiItem const inline ImguiItem IMGUI_EVENT = ImguiItem ({ .label = "## Event Item", - .texture = TEXTURE_EVENT, + .atlas = ATLAS_EVENT, .isUndoable = true, .isSizeToText = false }); @@ -781,7 +868,7 @@ const inline ImguiItem IMGUI_SPRITESHEET = ImguiItem ({ .label = "## Spritesheet", .dragDrop = "## Spritesheet Drag Drop", - .texture = TEXTURE_SPRITESHEET, + .atlas = ATLAS_SPRITESHEET, .flags = true }); @@ -795,7 +882,6 @@ const inline ImguiItem IMGUI_SPRITESHEETS_ADD = ImguiItem ({ .label = "Add", .tooltip = "Select an image to add as a spritesheet.", - .function = imgui_png_open, .isSizeToChild = true, .childRowItemCount = IMGUI_SPRITESHEETS_OPTIONS_FIRST_ROW_ITEM_COUNT }); @@ -967,10 +1053,16 @@ const inline ImguiItem IMGUI_ANIMATION_PREVIEW_ROOT_TRANSFORM = ImguiItem .tooltip = "Toggles the root frames's attributes transforming the other items in an animation." }); -const inline ImguiItem IMGUI_ANIMATION_PREVIEW_SHOW_PIVOT = ImguiItem +const inline ImguiItem IMGUI_ANIMATION_PREVIEW_PIVOTS = ImguiItem ({ - .label = "Show Pivot", - .tooltip = "Toggles the appearance of an icon for each animation item's pivot." + .label = "Pivots", + .tooltip = "Toggles drawing each layer's pivot." +}); + +const inline ImguiItem IMGUI_ANIMATION_PREVIEW_TARGETS = ImguiItem +({ + .label = "Targets", + .tooltip = "Toggles drawing the targets (i.e., the colored root/null icons)." }); const inline ImguiItem IMGUI_ANIMATION_PREVIEW_BORDER = ImguiItem @@ -1078,6 +1170,8 @@ const inline ImguiItem IMGUI_FRAME_PROPERTIES_POSITION = ImguiItem .format = "%.0f", .isUndoable = true, .speed = 0.25f, + .min = 0, + .max = 0 }); const inline ImguiItem IMGUI_FRAME_PROPERTIES_CROP = ImguiItem @@ -1088,6 +1182,8 @@ const inline ImguiItem IMGUI_FRAME_PROPERTIES_CROP = ImguiItem .format = "%.0f", .isUndoable = true, .speed = 0.25f, + .min = 0, + .max = 0 }); const inline ImguiItem IMGUI_FRAME_PROPERTIES_SIZE = ImguiItem @@ -1097,7 +1193,9 @@ const inline ImguiItem IMGUI_FRAME_PROPERTIES_SIZE = ImguiItem .action = "Frame Size", .format = "%.0f", .isUndoable = true, - .speed = 0.25f + .speed = 0.25f, + .min = 0, + .max = 0 }); const inline ImguiItem IMGUI_FRAME_PROPERTIES_PIVOT = ImguiItem @@ -1107,7 +1205,9 @@ const inline ImguiItem IMGUI_FRAME_PROPERTIES_PIVOT = ImguiItem .action = "Frame Pivot", .format = "%.0f", .isUndoable = true, - .speed = 0.25f + .speed = 0.25f, + .min = 0, + .max = 0 }); const inline ImguiItem IMGUI_FRAME_PROPERTIES_SCALE = ImguiItem @@ -1116,7 +1216,9 @@ const inline ImguiItem IMGUI_FRAME_PROPERTIES_SCALE = ImguiItem .tooltip = "Change the scale of the selected frame.", .action = "Frame Scale", .isUndoable = true, - .speed = 0.25f + .speed = 0.25f, + .min = 0, + .max = 0 }); const inline ImguiItem IMGUI_FRAME_PROPERTIES_ROTATION = ImguiItem @@ -1125,7 +1227,9 @@ const inline ImguiItem IMGUI_FRAME_PROPERTIES_ROTATION = ImguiItem .tooltip = "Change the rotation of the selected frame.", .action = "Frame Rotation", .isUndoable = true, - .speed = 0.25f + .speed = 0.25f, + .min = 0, + .max = 0 }); const inline ImguiItem IMGUI_FRAME_PROPERTIES_DURATION = ImguiItem @@ -1191,7 +1295,7 @@ const inline ImguiItem IMGUI_FRAME_PROPERTIES_FLIP_Y = ImguiItem const inline ImguiItem IMGUI_FRAME_PROPERTIES_EVENT = ImguiItem ({ .label = "Event", - .tooltip = "Change the event the trigger uses.\nNOTE: This sets the event ID, not the event. If the events change IDs, then this will need to be changed.", + .tooltip = "Change the event the trigger uses.\n", .action = "Trigger Event", .isUndoable = true }); @@ -1212,7 +1316,7 @@ const inline ImguiItem IMGUI_TOOL_PAN = ImguiItem .tooltip = "Use the pan tool.\nWill shift the view as the cursor is dragged.\nYou can also use the middle mouse button to pan at any time.", .function = imgui_tool_pan_set, .chord = ImGuiKey_P, - .texture = TEXTURE_PAN, + .atlas = ATLAS_PAN, }); const inline ImguiItem IMGUI_TOOL_MOVE = ImguiItem @@ -1221,7 +1325,7 @@ const inline ImguiItem IMGUI_TOOL_MOVE = ImguiItem .tooltip = "Use the move tool.\nWill move the selected item as the cursor is dragged, or directional keys are pressed.\n(Animation Preview only.)", .function = imgui_tool_move_set, .chord = ImGuiKey_M, - .texture = TEXTURE_MOVE, + .atlas = ATLAS_MOVE, }); const inline ImguiItem IMGUI_TOOL_ROTATE = ImguiItem @@ -1230,7 +1334,7 @@ const inline ImguiItem IMGUI_TOOL_ROTATE = ImguiItem .tooltip = "Use the rotate tool.\nWill rotate the selected item as the cursor is dragged, or directional keys are pressed.\n(Animation Preview only.)", .function = imgui_tool_rotate_set, .chord = ImGuiKey_R, - .texture = TEXTURE_ROTATE, + .atlas = ATLAS_ROTATE, }); const inline ImguiItem IMGUI_TOOL_SCALE = ImguiItem @@ -1239,7 +1343,7 @@ const inline ImguiItem IMGUI_TOOL_SCALE = ImguiItem .tooltip = "Use the scale tool.\nWill scale the selected item as the cursor is dragged, or directional keys are pressed.\n(Animation Preview only.)", .function = imgui_tool_scale_set, .chord = ImGuiKey_S, - .texture = TEXTURE_SCALE, + .atlas = ATLAS_SCALE, }); const inline ImguiItem IMGUI_TOOL_CROP = ImguiItem @@ -1248,7 +1352,7 @@ const inline ImguiItem IMGUI_TOOL_CROP = ImguiItem .tooltip = "Use the crop tool.\nWill produce a crop rectangle based on how the cursor is dragged.\n(Spritesheet Editor only.)", .function = imgui_tool_crop_set, .chord = ImGuiKey_C, - .texture = TEXTURE_CROP, + .atlas = ATLAS_CROP, }); const inline ImguiItem IMGUI_TOOL_DRAW = ImguiItem @@ -1257,7 +1361,7 @@ const inline ImguiItem IMGUI_TOOL_DRAW = ImguiItem .tooltip = "Draws pixels onto the selected spritesheet, with the current color.\n(Spritesheet Editor only.)", .function = imgui_tool_draw_set, .chord = ImGuiKey_B, - .texture = TEXTURE_DRAW, + .atlas = ATLAS_DRAW, }); const inline ImguiItem IMGUI_TOOL_ERASE = ImguiItem @@ -1266,7 +1370,7 @@ const inline ImguiItem IMGUI_TOOL_ERASE = ImguiItem .tooltip = "Erases pixels from the selected spritesheet.\n(Spritesheet Editor only.)", .function = imgui_tool_erase_set, .chord = ImGuiKey_E, - .texture = TEXTURE_ERASE, + .atlas = ATLAS_ERASE, }); const inline ImguiItem IMGUI_TOOL_COLOR_PICKER = ImguiItem @@ -1275,7 +1379,7 @@ const inline ImguiItem IMGUI_TOOL_COLOR_PICKER = ImguiItem .tooltip = "Selects a color from anywhere on the screen, to be used for drawing.", .function = imgui_tool_color_picker_set, .chord = ImGuiKey_W, - .texture = TEXTURE_COLOR_PICKER, + .atlas = ATLAS_COLOR_PICKER, }); const inline ImguiItem IMGUI_TOOL_UNDO = ImguiItem @@ -1284,7 +1388,7 @@ const inline ImguiItem IMGUI_TOOL_UNDO = ImguiItem .tooltip = "Undoes the last action.", .function = imgui_undo, .chord = ImGuiKey_Z, - .texture = TEXTURE_UNDO + .atlas = ATLAS_UNDO }); const inline ImguiItem IMGUI_TOOL_REDO = ImguiItem @@ -1293,7 +1397,7 @@ const inline ImguiItem IMGUI_TOOL_REDO = ImguiItem .tooltip = "Redoes the last action.", .function = imgui_redo, .chord = ImGuiMod_Shift + ImGuiKey_Z, - .texture = TEXTURE_REDO + .atlas = ATLAS_REDO }); const inline ImguiItem IMGUI_TOOL_COLOR = ImguiItem @@ -1423,7 +1527,7 @@ const inline ImguiItem IMGUI_TIMELINE_ITEM_ROOT_SELECTABLE = ImguiItem .label = "Root", .tooltip = "The root item of an animation.\nChanging its properties will transform the rest of the animation.", .action = "Root Item Select", - .texture = TEXTURE_ROOT, + .atlas = ATLAS_ROOT, .isUndoable = true, .size = IMGUI_TIMELINE_ITEM_SELECTABLE_SIZE }); @@ -1434,7 +1538,7 @@ const inline ImguiItem IMGUI_TIMELINE_ITEM_LAYER_SELECTABLE = ImguiItem .tooltip = "A layer item.\nA graphical item within the animation.", .action = "Layer Item Select", .dragDrop = "## Layer Drag Drop", - .texture = TEXTURE_LAYER, + .atlas = ATLAS_LAYER, .isUndoable = true, .size = IMGUI_TIMELINE_ITEM_SELECTABLE_SIZE }); @@ -1445,7 +1549,7 @@ const inline ImguiItem IMGUI_TIMELINE_ITEM_NULL_SELECTABLE = ImguiItem .tooltip = "A null item.\nAn invisible item within the animation that is accessible via a game engine.", .action = "Null Item Select", .dragDrop = "## Null Drag Drop", - .texture = TEXTURE_NULL, + .atlas = ATLAS_NULL, .isUndoable = true, .size = IMGUI_TIMELINE_ITEM_SELECTABLE_SIZE }); @@ -1455,7 +1559,7 @@ const inline ImguiItem IMGUI_TIMELINE_ITEM_TRIGGERS_SELECTABLE = ImguiItem .label = "Triggers", .tooltip = "The animation's triggers.\nWill fire based on an event.", .action = "Triggers Item Select", - .texture = TEXTURE_TRIGGERS, + .atlas = ATLAS_TRIGGERS, .isUndoable = true, .size = IMGUI_TIMELINE_ITEM_SELECTABLE_SIZE }); @@ -1473,7 +1577,7 @@ const inline ImguiItem IMGUI_TIMELINE_ITEM_VISIBLE = ImguiItem ({ .label = "## Visible", .tooltip = "The item is visible.\nPress to set to invisible.", - .texture = TEXTURE_VISIBLE, + .atlas = ATLAS_VISIBLE, .isUndoable = true }); @@ -1481,7 +1585,7 @@ const inline ImguiItem IMGUI_TIMELINE_ITEM_INVISIBLE = ImguiItem ({ .label = "## Invisible", .tooltip = "The item is invisible.\nPress to set to visible.", - .texture = TEXTURE_INVISIBLE, + .atlas = ATLAS_INVISIBLE, .isUndoable = true }); @@ -1489,7 +1593,7 @@ const inline ImguiItem IMGUI_TIMELINE_ITEM_SHOW_RECT = ImguiItem ({ .label = "## Show Rect", .tooltip = "The rect is shown.\nPress to hide rect.", - .texture = TEXTURE_SHOW_RECT, + .atlas = ATLAS_SHOW_RECT, .isUndoable = true }); @@ -1497,7 +1601,7 @@ const inline ImguiItem IMGUI_TIMELINE_ITEM_HIDE_RECT = ImguiItem ({ .label = "## Hide Rect", .tooltip = "The rect is hidden.\nPress to show rect.", - .texture = TEXTURE_HIDE_RECT, + .atlas = ATLAS_HIDE_RECT, .isUndoable = true }); @@ -1505,7 +1609,7 @@ const inline ImguiItem IMGUI_TIMELINE_SPRITESHEET_ID = ImguiItem ({ .label = "## Spritesheet ID", .tooltip = "Change the spritesheet ID this item uses.", - .texture = TEXTURE_SPRITESHEET, + .atlas = ATLAS_SPRITESHEET, .isUndoable = true, .size = {32, 0}, }); @@ -1631,6 +1735,7 @@ const inline ImguiItem IMGUI_TIMELINE_PLAY = ImguiItem ({ .label = "|> Play", .tooltip = "Play the current animation, if paused.", + .focusWindow = IMGUI_TIMELINE.label, .chord = ImGuiKey_Space }); @@ -1638,6 +1743,7 @@ const inline ImguiItem IMGUI_TIMELINE_PAUSE = ImguiItem ({ .label = "|| Pause", .tooltip = "Pause the current animation, if playing.", + .focusWindow = IMGUI_TIMELINE.label, .chord = ImGuiKey_Space }); @@ -1760,12 +1866,6 @@ const inline ImguiItem IMGUI_TIMELINE_CREATED_BY = ImguiItem const inline ImguiItem IMGUI_TIMELINE_CREATED_ON = ImguiItem({"Created on: "}); const inline ImguiItem IMGUI_TIMELINE_VERSION = ImguiItem({"Version: "}); -const inline ImguiItem IMGUI_RECORDING = ImguiItem -({ - .label = "Recording...", - .texture = TEXTURE_RECORD -}); - const inline ImguiItem IMGUI_CONTEXT_MENU = ImguiItem ({ .label = "## Context Menu", @@ -1794,8 +1894,8 @@ const inline ImguiItem IMGUI_COPY = ImguiItem const inline ImguiItem IMGUI_PASTE = ImguiItem ({ - .label = "Paste", - .tooltip = "Pastes the currently selection contextual element from the clipboard.", + .label = "Paste", + .tooltip = "Pastes the currently selection contextual element from the clipboard.", .action = "Paste", .function = imgui_paste, .chord = ImGuiMod_Ctrl | ImGuiKey_V, @@ -1808,7 +1908,7 @@ const inline ImguiItem IMGUI_RENAMABLE = ImguiItem .tooltip = "Rename the selected item.", .action = "Rename", .isUndoable = true, - .max = 255, + .max = IMGUI_BUFFER_MAX, .flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue }); @@ -1827,16 +1927,24 @@ const inline ImguiItem IMGUI_EXIT_CONFIRMATION = ImguiItem .popup = "Exit Confirmation" }); -const inline ImguiItem IMGUI_POPUP_YES_BUTTON = ImguiItem +const inline ImguiItem IMGUI_POPUP_OK_BUTTON = ImguiItem ({ - .label = "Yes", - .size = {120, 0} + .label = "OK", + .isSizeToChild = true }); -const inline ImguiItem IMGUI_POPUP_NO_BUTTON = ImguiItem +const inline ImguiItem IMGUI_POPUP_CONFIRM_BUTTON = ImguiItem ({ - .label = "No", - .size = {120, 0} + .label = "OK", + .isSizeToChild = true, + .childRowItemCount = IMGUI_POPUP_OPTION_CHILD_ROW_ITEM_COUNT +}); + +const inline ImguiItem IMGUI_POPUP_CANCEL_BUTTON = ImguiItem +({ + .label = "Cancel", + .isSizeToChild = true, + .childRowItemCount = IMGUI_POPUP_OPTION_CHILD_ROW_ITEM_COUNT }); void imgui_init diff --git a/src/preview.cpp b/src/preview.cpp index aae1095..575fcee 100644 --- a/src/preview.cpp +++ b/src/preview.cpp @@ -1,7 +1,15 @@ -// Handles the rendering of the animation preview +// Handles the render of the animation preview #include "preview.h" +static void _preview_render_textures_free(Preview* self) +{ + for (auto& texture : self->renderFrames) + texture_free(&texture); + + self->renderFrames.clear(); +} + void preview_init(Preview* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, Settings* settings) { self->anm2 = anm2; @@ -20,19 +28,45 @@ void preview_tick(Preview* self) { if (self->isPlaying) { + if (self->isRender) + { + vec2& size = self->canvas.size; + u32 framebufferPixelCount = size.x * size.y * TEXTURE_CHANNELS; + std::vector framebufferPixels(framebufferPixelCount); + Texture frameTexture; + + glBindFramebuffer(GL_READ_FRAMEBUFFER, self->canvas.fbo); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(0, 0, size.x, size.y, GL_RGBA, GL_UNSIGNED_BYTE, framebufferPixels.data()); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + texture_from_rgba_init(&frameTexture, size, TEXTURE_CHANNELS, framebufferPixels.data()); + self->renderFrames.push_back(frameTexture); + } + self->time += (f32)self->anm2->fps / TICK_RATE; if (self->time >= (f32)animation->frameNum - 1) { - if (self->settings->playbackIsLoop && !self->isRecording) + if (self->isRender) + { + self->isRender = false; + self->isRenderFinished = true; self->time = 0.0f; - else self->isPlaying = false; + } + else + { + if (self->settings->playbackIsLoop) + self->time = 0.0f; + else + self->isPlaying = false; + } } } - - if (!self->isPlaying) - self->time = std::clamp(self->time, 0.0f, (f32)animation->frameNum - 1); + + self->time = std::clamp(self->time, 0.0f, (f32)animation->frameNum - 1); } } @@ -72,11 +106,11 @@ void preview_draw(Preview* self) rootModel = quad_parent_model_get(root.position, vec2(0.0f), root.rotation, PERCENT_TO_UNIT(root.scale)); // Root - if (animation->rootAnimation.isVisible && root.isVisible) + if (self->settings->previewIsTargets && animation->rootAnimation.isVisible && root.isVisible) { mat4 model = quad_model_get(PREVIEW_TARGET_SIZE, root.position, PREVIEW_TARGET_SIZE * 0.5f, root.rotation, PERCENT_TO_UNIT(root.scale)); mat4 rootTransform = transform * model; - f32 vertices[] = ATLAS_UV_VERTICES(TEXTURE_TARGET); + f32 vertices[] = ATLAS_UV_VERTICES(ATLAS_TARGET); canvas_texture_draw(&self->canvas, shaderTexture, self->resources->atlas.id, rootTransform, vertices, PREVIEW_ROOT_COLOR); } @@ -94,26 +128,26 @@ void preview_draw(Preview* self) if (!frame.isVisible) continue; - Texture texture = self->resources->textures[self->anm2->layers[id].spritesheetID]; + Texture* texture = map_find(self->resources->textures, self->anm2->layers[id].spritesheetID); - if (texture.isInvalid) + if (!texture || texture->isInvalid) continue; - vec2 uvMin = frame.crop / vec2(texture.size); - vec2 uvMax = (frame.crop + frame.size) / vec2(texture.size); + vec2 uvMin = frame.crop / vec2(texture->size); + vec2 uvMax = (frame.crop + frame.size) / vec2(texture->size); f32 vertices[] = UV_VERTICES(uvMin, uvMax); mat4 model = quad_model_get(frame.size, frame.position, frame.pivot, frame.rotation, PERCENT_TO_UNIT(frame.scale)); mat4 layerTransform = transform * (rootModel * model); - canvas_texture_draw(&self->canvas, shaderTexture, texture.id, layerTransform, vertices, frame.tintRGBA, frame.offsetRGB); + canvas_texture_draw(&self->canvas, shaderTexture, texture->id, layerTransform, vertices, frame.tintRGBA, frame.offsetRGB); if (self->settings->previewIsBorder) canvas_rect_draw(&self->canvas, shaderLine, layerTransform, PREVIEW_BORDER_COLOR); - if (self->settings->previewIsShowPivot) + if (self->settings->previewIsPivots) { - f32 vertices[] = ATLAS_UV_VERTICES(TEXTURE_PIVOT); + f32 vertices[] = ATLAS_UV_VERTICES(ATLAS_PIVOT); mat4 pivotModel = quad_model_get(CANVAS_PIVOT_SIZE, frame.position, CANVAS_PIVOT_SIZE * 0.5f, frame.rotation, PERCENT_TO_UNIT(frame.scale)); mat4 pivotTransform = transform * (rootModel * pivotModel); canvas_texture_draw(&self->canvas, shaderTexture, self->resources->atlas.id, pivotTransform, vertices, PREVIEW_PIVOT_COLOR); @@ -121,38 +155,41 @@ void preview_draw(Preview* self) } // Nulls - for (auto& [id, nullAnimation] : animation->nullAnimations) + if (self->settings->previewIsTargets) { - if (!nullAnimation.isVisible || nullAnimation.frames.size() <= 0) - continue; - - Anm2Frame frame; - anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationID, ANM2_NULL, id}, self->time); - - if (!frame.isVisible) - continue; - - Anm2Null null = self->anm2->nulls[id]; - - vec4 color = (self->reference->itemType == ANM2_NULL && self->reference->itemID == id) ? - PREVIEW_NULL_SELECTED_COLOR : - PREVIEW_NULL_COLOR; - - vec2 size = null.isShowRect ? CANVAS_PIVOT_SIZE : PREVIEW_TARGET_SIZE; - TextureType texture = null.isShowRect ? TEXTURE_SQUARE : TEXTURE_TARGET; - - mat4 model = quad_model_get(size, frame.position, size * 0.5f, frame.rotation, PERCENT_TO_UNIT(frame.scale)); - mat4 nullTransform = transform * (rootModel * model); - - f32 vertices[] = ATLAS_UV_VERTICES(texture); - - canvas_texture_draw(&self->canvas, shaderTexture, self->resources->atlas.id, nullTransform, vertices, color); - - if (null.isShowRect) + for (auto& [id, nullAnimation] : animation->nullAnimations) { - mat4 rectModel = quad_model_get(PREVIEW_NULL_RECT_SIZE, frame.position, PREVIEW_NULL_RECT_SIZE * 0.5f, frame.rotation, PERCENT_TO_UNIT(frame.scale)); - mat4 rectTransform = transform * (rootModel * rectModel); - canvas_rect_draw(&self->canvas, shaderLine, rectTransform, color); + if (!nullAnimation.isVisible || nullAnimation.frames.size() <= 0) + continue; + + Anm2Frame frame; + anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationID, ANM2_NULL, id}, self->time); + + if (!frame.isVisible) + continue; + + Anm2Null null = self->anm2->nulls[id]; + + vec4 color = (self->reference->itemType == ANM2_NULL && self->reference->itemID == id) ? + PREVIEW_NULL_SELECTED_COLOR : + PREVIEW_NULL_COLOR; + + vec2 size = null.isShowRect ? CANVAS_PIVOT_SIZE : PREVIEW_TARGET_SIZE; + AtlasType atlas = null.isShowRect ? ATLAS_SQUARE : ATLAS_TARGET; + + mat4 model = quad_model_get(size, frame.position, size * 0.5f, frame.rotation, PERCENT_TO_UNIT(frame.scale)); + mat4 nullTransform = transform * (rootModel * model); + + f32 vertices[] = ATLAS_UV_VERTICES(atlas); + + canvas_texture_draw(&self->canvas, shaderTexture, self->resources->atlas.id, nullTransform, vertices, color); + + if (null.isShowRect) + { + mat4 rectModel = quad_model_get(PREVIEW_NULL_RECT_SIZE, frame.position, PREVIEW_NULL_RECT_SIZE * 0.5f, frame.rotation, PERCENT_TO_UNIT(frame.scale)); + mat4 rectTransform = transform * (rootModel * rectModel); + canvas_rect_draw(&self->canvas, shaderLine, rectTransform, color); + } } } } @@ -173,7 +210,7 @@ void preview_draw(Preview* self) for (auto [i, id] : self->anm2->layerMap) { Anm2Frame frame; - Anm2Item& layerAnimation = animation->layerAnimations[id]; + Anm2Item& layerAnimation = animationOverlay->layerAnimations[id]; if (!layerAnimation.isVisible || layerAnimation.frames.size() <= 0) continue; @@ -183,13 +220,13 @@ void preview_draw(Preview* self) if (!frame.isVisible) continue; - Texture texture = self->resources->textures[self->anm2->layers[id].spritesheetID]; - - if (texture.isInvalid) + Texture* texture = map_find(self->resources->textures, self->anm2->layers[id].spritesheetID); + + if (!texture || texture->isInvalid) continue; - vec2 uvMin = frame.crop / vec2(texture.size); - vec2 uvMax = (frame.crop + frame.size) / vec2(texture.size); + vec2 uvMin = frame.crop / vec2(texture->size); + vec2 uvMax = (frame.crop + frame.size) / vec2(texture->size); f32 vertices[] = UV_VERTICES(uvMin, uvMax); mat4 model = quad_model_get(frame.size, frame.position, frame.pivot, frame.rotation, PERCENT_TO_UNIT(frame.scale)); @@ -198,13 +235,29 @@ void preview_draw(Preview* self) vec4 tint = frame.tintRGBA; tint.a *= U8_TO_FLOAT(self->settings->previewOverlayTransparency); - canvas_texture_draw(&self->canvas, shaderTexture, texture.id, layerTransform, vertices, tint, frame.offsetRGB); + canvas_texture_draw(&self->canvas, shaderTexture, texture->id, layerTransform, vertices, tint, frame.offsetRGB); } } canvas_unbind(); } +void preview_render_start(Preview* self) +{ + self->isRender = true; + self->isPlaying = true; + self->time = 0.0f; + _preview_render_textures_free(self); +} + +void preview_render_end(Preview* self) +{ + self->isRender = false; + self->isPlaying = false; + self->isRenderFinished = false; + _preview_render_textures_free(self); +} + void preview_free(Preview* self) { canvas_free(&self->canvas); diff --git a/src/preview.h b/src/preview.h index dfd9ca0..926e694 100644 --- a/src/preview.h +++ b/src/preview.h @@ -35,7 +35,10 @@ struct Preview s32 animationOverlayID = ID_NONE; Canvas canvas; bool isPlaying = false; - bool isRecording = false; + bool isRender = false; + bool isRenderFinished = false; + bool isRenderCancelled = false; + std::vector renderFrames; f32 time{}; }; @@ -43,4 +46,5 @@ void preview_init(Preview* self, Anm2* anm2, Anm2Reference* reference, Resources void preview_draw(Preview* self); void preview_tick(Preview* self); void preview_free(Preview* self); -void preview_record_set(Preview* self); \ No newline at end of file +void preview_render_start(Preview* self); +void preview_render_end(Preview* self); \ No newline at end of file diff --git a/src/render.h b/src/render.h new file mode 100644 index 0000000..748201c --- /dev/null +++ b/src/render.h @@ -0,0 +1,25 @@ +#pragma once + +#include "COMMON.h" + +enum RenderType +{ + RENDER_PNG, + RENDER_GIF, + RENDER_WEBM, + RENDER_COUNT +}; + +const inline std::string RENDER_TYPE_STRINGS[] = +{ + "PNG Images", + "GIF image", + "WebM video", +}; + +const inline std::string RENDER_EXTENSIONS[RENDER_COUNT] = +{ + ".png", + ".gif", + ".webm" +}; \ No newline at end of file diff --git a/src/resources.cpp b/src/resources.cpp index c9fabbf..4174111 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -1,21 +1,20 @@ #include "resources.h" -void resources_texture_init(Resources* resources, const std::string& path, s32 id) +void resources_texture_init(Resources* self, const std::string& path, s32 id) { Texture texture; - if (resources->textures.find(id) != resources->textures.end() && resources->textures[id].id != resources->textures[TEXTURE_NONE].id) - texture_free(&resources->textures[id]); + if (map_find(self->textures, id)) + texture_free(&self->textures[id]); - if (!texture_from_path_init(&texture, path)) - texture.isInvalid = true; + texture_from_path_init(&texture, path); - resources->textures[id] = texture; + self->textures[id] = texture; } void resources_init(Resources* self) { - texture_from_data_init(&self->atlas, (u8*)TEXTURE_ATLAS, TEXTURE_ATLAS_LENGTH); + texture_from_encoded_data_init(&self->atlas, TEXTURE_ATLAS_SIZE, TEXTURE_CHANNELS, (u8*)TEXTURE_ATLAS, TEXTURE_ATLAS_LENGTH); for (s32 i = 0; i < SHADER_COUNT; i++) shader_init(&self->shaders[i], SHADER_DATA[i].vertex, SHADER_DATA[i].fragment); @@ -25,14 +24,15 @@ void resources_free(Resources* self) { resources_textures_free(self); - for (s32 i = 0; i < SHADER_COUNT; i++) - shader_free(&self->shaders[i]); + for (auto& shader : self->shaders) + shader_free(&shader); + texture_free(&self->atlas); } void resources_textures_free(Resources* self) { - for (auto & [id, texture] : self->textures) + for (auto& [id, texture] : self->textures) texture_free(&self->textures[id]); log_info(RESOURCES_TEXTURES_FREE_INFO); diff --git a/src/resources.h b/src/resources.h index 94e3e3c..68ce17a 100644 --- a/src/resources.h +++ b/src/resources.h @@ -14,6 +14,6 @@ struct Resources }; void resources_init(Resources* self); -void resources_texture_init(Resources* resources, const std::string& path, s32 id); +void resources_texture_init(Resources* self, const std::string& path, s32 id); void resources_free(Resources* self); void resources_textures_free(Resources* self); diff --git a/src/settings.cpp b/src/settings.cpp index c0eac7d..f6250c5 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -6,11 +6,17 @@ static void _settings_setting_load(Settings* self, const std::string& line) { const auto& entry = SETTINGS_ENTRIES[i]; const std::string& key = entry.key; + void* target = (u8*)self + entry.offset; auto match_key = [&](const std::string& full) -> const char* { - return (line.starts_with(full) && line[full.size()] == '=') ? line.c_str() + full.size() + 1 : nullptr; + if (!line.starts_with(full)) + return nullptr; + size_t p = full.size(); + while (p < line.size() && std::isspace((u8)line[p])) ++p; + if (p < line.size() && line[p] == '=') return line.c_str() + p + 1; + return nullptr; }; auto* value = match_key(key); @@ -79,9 +85,12 @@ static void _settings_setting_write(Settings* self, std::ostream& out, SettingsE out << entry.key << "=" << value << "\n"; break; case TYPE_STRING: - value = *(std::string*)(selfPointer + entry.offset); - out << entry.key << "=" << value << "\n"; + { + const std::string data = *reinterpret_cast(selfPointer + entry.offset); + if (!data.empty()) + out << entry.key << "=" << data.c_str() << "\n"; break; + } case TYPE_IVEC2: { ivec2* data = (ivec2*)(selfPointer + entry.offset); diff --git a/src/settings.h b/src/settings.h index 46fdff7..d6cd6ec 100644 --- a/src/settings.h +++ b/src/settings.h @@ -1,5 +1,6 @@ #pragma once +#include "render.h" #include "tool.h" #define SETTINGS_BUFFER 0xFFFF @@ -24,7 +25,8 @@ struct Settings bool previewIsAxis = true; bool previewIsGrid = true; bool previewIsRootTransform = false; - bool previewIsShowPivot = false; + bool previewIsPivots = false; + bool previewIsTargets = true; bool previewIsBorder = false; f32 previewOverlayTransparency = 255.0f; f32 previewZoom = 200.0; @@ -45,6 +47,10 @@ struct Settings vec4 editorBackgroundColor = {0.113, 0.184, 0.286, 1.0}; ToolType tool = TOOL_PAN; vec4 toolColor = {1.0, 1.0, 1.0, 1.0}; + RenderType renderType = RENDER_PNG; + std::string renderPath = "."; + std::string renderFormat = "{}.png"; + std::string ffmpegPath = "/usr/bin/ffmpeg"; }; const SettingsEntry SETTINGS_ENTRIES[] = @@ -54,7 +60,8 @@ const SettingsEntry SETTINGS_ENTRIES[] = {"previewIsAxis", TYPE_BOOL, offsetof(Settings, previewIsAxis)}, {"previewIsGrid", TYPE_BOOL, offsetof(Settings, previewIsGrid)}, {"previewIsRootTransform", TYPE_BOOL, offsetof(Settings, previewIsRootTransform)}, - {"previewIsShowPivot", TYPE_BOOL, offsetof(Settings, previewIsShowPivot)}, + {"previewIsPivots", TYPE_BOOL, offsetof(Settings, previewIsPivots)}, + {"previewIsTargets", TYPE_BOOL, offsetof(Settings, previewIsTargets)}, {"previewIsBorder", TYPE_BOOL, offsetof(Settings, previewIsBorder)}, {"previewOverlayTransparency", TYPE_FLOAT, offsetof(Settings, previewOverlayTransparency)}, {"previewZoom", TYPE_FLOAT, offsetof(Settings, previewZoom)}, @@ -75,6 +82,10 @@ const SettingsEntry SETTINGS_ENTRIES[] = {"editorBackgroundColor", TYPE_VEC4, offsetof(Settings, editorBackgroundColor)}, {"tool", TYPE_INT, offsetof(Settings, tool)}, {"toolColor", TYPE_VEC4, offsetof(Settings, toolColor)}, + {"renderType", TYPE_INT, offsetof(Settings, renderType)}, + {"renderPath", TYPE_STRING, offsetof(Settings, renderPath)}, + {"renderFormat", TYPE_STRING, offsetof(Settings, renderFormat)}, + {"ffmpegPath", TYPE_STRING, offsetof(Settings, ffmpegPath)} }; constexpr s32 SETTINGS_COUNT = (s32)std::size(SETTINGS_ENTRIES); diff --git a/src/snapshots.cpp b/src/snapshots.cpp index 7453dca..679daaf 100644 --- a/src/snapshots.cpp +++ b/src/snapshots.cpp @@ -34,6 +34,13 @@ void snapshots_init(Snapshots* self, Anm2* anm2, Anm2Reference* reference, Previ self->preview = preview; } +void snapshots_reset(Snapshots* self) +{ + self->undoStack = SnapshotStack{}; + self->redoStack = SnapshotStack{}; + self->action.clear(); +} + void snapshots_undo_stack_push(Snapshots* self, const Snapshot* snapshot) { _snapshot_stack_push(&self->undoStack, snapshot); diff --git a/src/snapshots.h b/src/snapshots.h index a5d93e9..390dda6 100644 --- a/src/snapshots.h +++ b/src/snapshots.h @@ -33,4 +33,5 @@ struct Snapshots void snapshots_undo_stack_push(Snapshots* self, const Snapshot* snapshot); void snapshots_init(Snapshots* self, Anm2* anm2, Anm2Reference* reference, Preview* preview); void snapshots_undo(Snapshots* self); -void snapshots_redo(Snapshots* self); \ No newline at end of file +void snapshots_redo(Snapshots* self); +void snapshots_reset(Snapshots* self); \ No newline at end of file diff --git a/src/state.cpp b/src/state.cpp index 4c5d976..6f17f87 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -10,7 +10,6 @@ static void _update(State* self) SDL_GetWindowSize(self->window, &self->settings.windowSize.x, &self->settings.windowSize.y); imgui_update(&self->imgui); - dialog_update(&self->dialog); if (self->imgui.isQuit) self->isRunning = false; @@ -99,8 +98,8 @@ void init(State* self) glDisable(GL_LINE_SMOOTH); resources_init(&self->resources); + dialog_init(&self->dialog, self->window); clipboard_init(&self->clipboard, &self->anm2); - dialog_init(&self->dialog, &self->anm2, &self->reference, &self->resources, self->window); snapshots_init(&self->snapshots, &self->anm2, &self->reference, &self->preview); preview_init(&self->preview, &self->anm2, &self->reference, &self->resources, &self->settings); editor_init(&self->editor, &self->anm2, &self->reference, &self->resources, &self->settings); @@ -130,7 +129,6 @@ void init(State* self) anm2_new(&self->anm2); } - void loop(State* self) { self->tick = SDL_GetTicks(); diff --git a/src/texture.cpp b/src/texture.cpp index f928229..1c08084 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -8,19 +8,7 @@ #define STB_IMAGE_WRITE_IMPLEMENTATION #include - -static std::vector _texture_download(Texture* self) -{ - std::vector pixels(self->size.x * self->size.y * TEXTURE_CHANNELS); - - glBindTexture(GL_TEXTURE_2D, self->id); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); - - return pixels; -} - -void texture_gl_set(Texture* self, void* data) +static void _texture_gl_set(Texture* self, const u8* data) { glGenTextures(1, &self->id); glBindTexture(GL_TEXTURE_2D, self->id); @@ -32,35 +20,67 @@ void texture_gl_set(Texture* self, void* data) glBindTexture(GL_TEXTURE_2D, 0); } +std::vector texture_download(const Texture* self) +{ + std::vector pixels(self->size.x * self->size.y * TEXTURE_CHANNELS); + + glBindTexture(GL_TEXTURE_2D, self->id); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); + + return pixels; +} + bool texture_from_path_init(Texture* self, const std::string& path) { - void* data = stbi_load(path.c_str(), &self->size.x, &self->size.y, &self->channels, TEXTURE_CHANNELS); + *self = Texture{}; + u8* data = stbi_load(path.c_str(), &self->size.x, &self->size.y, &self->channels, TEXTURE_CHANNELS); if (!data) { log_error(std::format(TEXTURE_INIT_ERROR, path)); + self->isInvalid = true; return false; } log_info(std::format(TEXTURE_INIT_INFO, path)); - texture_gl_set(self, data); + _texture_gl_set(self, data); return true; } -bool texture_from_data_init(Texture* self, const u8* data, u32 length) +bool texture_from_encoded_data_init(Texture* self, ivec2 size, s32 channels, const u8* data, u32 length) { - void* textureData = stbi_load_from_memory(data, length, &self->size.x, &self->size.y, &self->channels, TEXTURE_CHANNELS); + *self = Texture{}; + self->size = size; + self->channels = channels; - if (!textureData) return false; + u8* textureData = stbi_load_from_memory(data, length, &self->size.x, &self->size.y, &self->channels, TEXTURE_CHANNELS); - texture_gl_set(self, textureData); + if (!textureData) + { + self->isInvalid = true; + return false; + } + + _texture_gl_set(self, textureData); return true; } -bool texture_from_data_write(const std::string& path, const u8* data, ivec2 size) +bool texture_from_rgba_init(Texture* self, ivec2 size, s32 channels, const u8* data) +{ + *self = Texture{}; + self->size = size; + self->channels = channels; + + _texture_gl_set(self, data); + + return true; +} + +bool texture_from_rgba_write(const std::string& path, const u8* data, ivec2 size) { log_info(std::format(TEXTURE_SAVE_INFO, path)); return (bool)stbi_write_png(path.c_str(), size.x, size.y, TEXTURE_CHANNELS, data, size.x * TEXTURE_CHANNELS); @@ -68,7 +88,7 @@ bool texture_from_data_write(const std::string& path, const u8* data, ivec2 size bool texture_from_gl_write(Texture* self, const std::string& path) { - return texture_from_data_write(path, _texture_download(self).data(), self->size); + return texture_from_rgba_write(path, texture_download(self).data(), self->size); } void texture_free(Texture* self) diff --git a/src/texture.h b/src/texture.h index a6a46b4..9eeb0fe 100644 --- a/src/texture.h +++ b/src/texture.h @@ -15,11 +15,11 @@ struct Texture bool isInvalid = false; }; -void texture_gl_set(Texture* self, void* data); +bool texture_from_encoded_data_init(Texture* self, ivec2 size, s32 channels, const u8* data, u32 length); +bool texture_from_gl_write(Texture* self, const std::string& path); bool texture_from_path_init(Texture* self, const std::string& path); -bool texture_from_data_init(Texture* self, const u8* data, u32 length); -void texture_free(Texture* self); -std::vector texture_download(Texture* self); -bool texture_from_data_write(const std::string& path, const u8* data, ivec2 size); +bool texture_from_rgba_init(Texture* self, ivec2 size, s32 channels, const u8* data); +bool texture_from_rgba_write(const std::string& path, const u8* data, ivec2 size); bool texture_pixel_set(Texture* self, ivec2 position, vec4 color); -bool texture_from_gl_write(Texture* self, const std::string& path); \ No newline at end of file +void texture_free(Texture* self); +std::vector texture_download(const Texture* self); \ No newline at end of file