Last active
April 2, 2023 18:38
-
-
Save pJotoro/fb2f19514f91cbcf8c390b26bf7c7d5a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kit | |
////////////////////////////////////////////////////////////////////////////// | |
// Embedded font | |
////////////////////////////////////////////////////////////////////////////// | |
@(private) | |
font_png := [?]byte{ | |
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, | |
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x00, | |
0x01, 0x03, 0x00, 0x00, 0x00, 0xdf, 0x8d, 0xeb, 0x44, 0x00, 0x00, 0x00, | |
0x06, 0x50, 0x4c, 0x54, 0x45, 0x47, 0x70, 0x4c, 0xff, 0xff, 0xff, 0x9f, | |
0x94, 0xa2, 0x43, 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, | |
0x40, 0xe6, 0xd8, 0x66, 0x00, 0x00, 0x05, 0x4d, 0x49, 0x44, 0x41, 0x54, | |
0x58, 0xc3, 0xed, 0x98, 0x3f, 0x88, 0x24, 0x45, 0x14, 0xc6, 0xdf, 0x74, | |
0x37, 0xdd, 0xd5, 0xbb, 0x75, 0xd3, 0x13, 0x4e, 0x70, 0x48, 0x7b, 0x98, | |
0x08, 0x06, 0x03, 0x06, 0x2e, 0xb8, 0x4a, 0xbb, 0xd1, 0x04, 0x07, 0x5e, | |
0x62, 0xde, 0x82, 0x5c, 0x28, 0x03, 0x82, 0x0c, 0xc7, 0xa1, 0x4f, 0x5c, | |
0xb8, 0x0b, 0x56, 0x9c, 0xf0, 0x44, 0x11, 0x03, 0x95, 0xc5, 0x4c, 0x30, | |
0x50, 0x30, 0xa8, 0x03, 0x83, 0xe3, 0x18, 0xf5, 0xc2, 0x0d, 0xd7, 0xdc, | |
0x60, 0xc2, 0x09, 0x46, 0xcf, 0xef, 0x55, 0x55, 0x77, 0x4f, 0xcf, 0x1f, | |
0x6f, 0x11, 0x5d, 0xf7, 0x8e, 0x2b, 0x8a, 0xde, 0x9e, 0xfe, 0xf5, 0xab, | |
0x7a, 0xaf, 0x5e, 0x7d, 0xd5, 0x55, 0x4b, 0xb4, 0xb5, 0x24, 0x3c, 0xae, | |
0xab, 0xfb, 0x49, 0x84, 0x7b, 0xdc, 0xb2, 0x6a, 0xaa, 0xfb, 0x49, 0xb8, | |
0x7f, 0x72, 0xc0, 0xf6, 0xc8, 0xff, 0xc7, 0x32, 0x5e, 0xf6, 0x6a, 0xa9, | |
0x92, 0x6a, 0xc5, 0xd1, 0xd4, 0x27, 0x06, 0x6c, 0x8d, 0xfc, 0xe2, 0x96, | |
0x4e, 0x9e, 0xc7, 0xa7, 0xf8, 0x9b, 0xab, 0xfa, 0x11, 0xdc, 0xd5, 0x34, | |
0xe9, 0xe4, 0xa3, 0x34, 0x1f, 0x2b, 0x2a, 0x22, 0xca, 0x5b, 0x20, 0x99, | |
0x1d, 0xa7, 0xc5, 0x54, 0x91, 0x89, 0xe9, 0xd8, 0xb7, 0x41, 0x16, 0x04, | |
0xc5, 0x69, 0x5c, 0xfc, 0x6c, 0xc1, 0x28, 0x58, 0x02, 0x04, 0x40, 0xfc, | |
0x26, 0x59, 0x0b, 0x07, 0x02, 0x07, 0xb2, 0xd3, 0x11, 0xf1, 0x2f, 0x16, | |
0xe4, 0x19, 0x13, 0xaa, 0x07, 0x11, 0xef, 0x75, 0x06, 0x53, 0x0b, 0xc8, | |
0x59, 0x44, 0xae, 0x2b, 0x01, 0xc3, 0x35, 0xa0, 0xe5, 0xe6, 0x38, 0xa8, | |
0x00, 0xae, 0xa8, 0xaa, 0x02, 0xa3, 0x60, 0x00, 0x59, 0x14, 0xd1, 0x32, | |
0xb0, 0xc5, 0xc5, 0xe5, 0x22, 0x2f, 0xb6, 0x0d, 0xd0, 0x45, 0x48, 0xde, | |
0x38, 0xa6, 0x71, 0x66, 0x74, 0x66, 0xf6, 0x32, 0xd3, 0x4c, 0x27, 0xdc, | |
0x4c, 0xbb, 0x74, 0xd4, 0xe1, 0xcb, 0x9a, 0x4a, 0x32, 0x53, 0x8d, 0xe0, | |
0xa8, 0x2f, 0x01, 0x1a, 0x9a, 0xc6, 0xa4, 0x43, 0x7a, 0x41, 0x23, 0x60, | |
0x0f, 0x06, 0x24, 0x2f, 0x59, 0x90, 0xf0, 0xd5, 0x8c, 0xe7, 0x64, 0xc6, | |
0x16, 0x94, 0x99, 0x19, 0x74, 0x58, 0x40, 0x9f, 0xcc, 0x11, 0x5e, 0xef, | |
0x30, 0x2c, 0x8c, 0x98, 0x52, 0x3f, 0x24, 0x01, 0x03, 0x32, 0x7f, 0x02, | |
0x84, 0x34, 0x4d, 0x04, 0x88, 0x85, 0x03, 0x68, 0x51, 0x3b, 0x40, 0x75, | |
0x1f, 0x16, 0xc0, 0x07, 0xad, 0x2c, 0xe8, 0x30, 0x5e, 0x11, 0xaf, 0x42, | |
0x1b, 0xc7, 0x22, 0x61, 0xf4, 0x3f, 0x0e, 0xa1, 0x15, 0xb1, 0x95, 0x12, | |
0xae, 0x07, 0x1c, 0x6d, 0x1b, 0x09, 0x75, 0x31, 0x54, 0x93, 0xf0, 0x1c, | |
0x35, 0x33, 0x88, 0x66, 0xaa, 0x49, 0xeb, 0xd2, 0x28, 0xfd, 0x01, 0xf2, | |
0xf1, 0xaa, 0xc6, 0x68, 0x17, 0x78, 0x64, 0xec, 0x55, 0xcb, 0x38, 0x5e, | |
0xbe, 0x8b, 0x61, 0x7e, 0x4d, 0x00, 0x59, 0x20, 0x57, 0x7d, 0x89, 0x4d, | |
0x77, 0xff, 0x37, 0x80, 0xcf, 0x8e, 0xda, 0x20, 0x23, 0x93, 0xdd, 0xfc, | |
0x16, 0xe0, 0xcb, 0x8f, 0xcd, 0x1c, 0x8f, 0x90, 0xa8, 0x4b, 0x66, 0x01, | |
0xd0, 0x25, 0xb3, 0xfb, 0xfb, 0x27, 0x00, 0x5f, 0x37, 0x16, 0xf6, 0x06, | |
0x16, 0xe9, 0xf4, 0x23, 0x80, 0x4f, 0x75, 0x1b, 0xa0, 0x0f, 0x75, 0x74, | |
0x0b, 0xa0, 0x68, 0xbc, 0x72, 0x6f, 0x18, 0xb8, 0xfb, 0x21, 0x00, 0xdc, | |
0x75, 0x71, 0x18, 0x1b, 0xc7, 0x58, 0x97, 0x73, 0x17, 0xc7, 0xe3, 0x51, | |
0xba, 0xc4, 0x5d, 0x2b, 0x62, 0x09, 0x22, 0xa1, 0x85, 0x44, 0x37, 0x45, | |
0x74, 0x18, 0x2e, 0x8e, 0xe9, 0x9a, 0xcc, 0x44, 0x79, 0xc4, 0x83, 0x0a, | |
0x68, 0x4d, 0x45, 0x4c, 0xb7, 0x2b, 0x40, 0x2b, 0x80, 0x3c, 0xe8, 0x36, | |
0xa0, 0xaf, 0x29, 0x77, 0x60, 0x2e, 0x63, 0xe5, 0x01, 0x34, 0x38, 0xa8, | |
0x81, 0x0c, 0x6a, 0x58, 0xf5, 0x11, 0x52, 0xa9, 0xa9, 0xd7, 0x80, 0x4e, | |
0x03, 0x4c, 0x0b, 0xa4, 0x02, 0xee, 0xe9, 0x7b, 0x0e, 0x28, 0x0f, 0x90, | |
0x06, 0xf4, 0x21, 0x29, 0x99, 0x01, 0x2c, 0x1c, 0xc8, 0x66, 0x6e, 0xe1, | |
0x6a, 0x45, 0x2e, 0xf5, 0xc2, 0x16, 0xb6, 0xfe, 0x42, 0xdd, 0x7b, 0x12, | |
0x2c, 0xf5, 0x75, 0xe5, 0x7e, 0x51, 0x81, 0xd2, 0x45, 0x54, 0x83, 0xdc, | |
0x66, 0xf0, 0x66, 0xc2, 0xb3, 0x44, 0xa6, 0x7d, 0x1f, 0x53, 0x34, 0xfb, | |
0x7e, 0x2e, 0x33, 0x51, 0x49, 0x06, 0x91, 0x89, 0xd2, 0x66, 0xac, 0x8f, | |
0x49, 0x6d, 0x13, 0x03, 0x0d, 0xfa, 0xb9, 0xec, 0x01, 0x64, 0xe0, 0x81, | |
0x97, 0x45, 0x05, 0xf4, 0x0a, 0xc0, 0xfa, 0xb5, 0xc9, 0x02, 0x7d, 0x14, | |
0x1b, 0xfa, 0x70, 0x5e, 0x95, 0x89, 0x6b, 0xca, 0x08, 0x68, 0xeb, 0x43, | |
0x02, 0xb8, 0xb3, 0x69, 0xa5, 0x12, 0x30, 0xda, 0xb8, 0x76, 0xfc, 0x47, | |
0x4b, 0xd2, 0xda, 0xa3, 0xc0, 0x6d, 0x17, 0x2b, 0x50, 0x2e, 0x2d, 0xaf, | |
0x1c, 0xfd, 0x3d, 0x98, 0x27, 0xe6, 0x24, 0xa1, 0x59, 0xad, 0x28, 0x0b, | |
0xde, 0x02, 0xc0, 0x8f, 0xb9, 0xe6, 0xb2, 0x02, 0xca, 0x82, 0x3b, 0x0e, | |
0x98, 0x2e, 0xd5, 0xa0, 0x87, 0xfd, 0x50, 0x60, 0x9b, 0x12, 0x90, 0x78, | |
0x80, 0x39, 0x9f, 0xd7, 0x7d, 0x08, 0x08, 0x9b, 0xa6, 0x8a, 0x16, 0x48, | |
0x05, 0x88, 0x3e, 0x70, 0xbf, 0xec, 0x95, 0x11, 0x7d, 0x98, 0x19, 0xf4, | |
0x91, 0x78, 0xaf, 0x24, 0x72, 0xd3, 0xd2, 0x87, 0xa9, 0x22, 0xa7, 0x36, | |
0x50, 0xe6, 0xec, 0x63, 0xf7, 0x74, 0xbf, 0xfb, 0xd8, 0xee, 0x77, 0x9f, | |
0xe6, 0xe3, 0xc2, 0x9f, 0x3f, 0xe0, 0x92, 0xf3, 0xca, 0x1f, 0x2d, 0x12, | |
0x3a, 0x21, 0x7a, 0x78, 0x4a, 0x0b, 0x59, 0x93, 0xec, 0x31, 0x63, 0x14, | |
0x32, 0xe9, 0x01, 0x2b, 0x3e, 0x09, 0x0d, 0xcb, 0x5b, 0xbc, 0xef, 0xc0, | |
0x71, 0x5c, 0x50, 0x5c, 0xb2, 0x1c, 0x12, 0x72, 0x00, 0x58, 0x1c, 0xb8, | |
0x85, 0xec, 0x8b, 0x98, 0x0e, 0xb3, 0x19, 0x3e, 0xfc, 0x94, 0x4e, 0xf8, | |
0x59, 0x98, 0xf0, 0x0f, 0xce, 0x02, 0x00, 0xdf, 0x61, 0xde, 0x25, 0xda, | |
0xb9, 0xc6, 0x57, 0x0a, 0x58, 0x7c, 0xe5, 0x9b, 0xca, 0x68, 0x81, 0x8f, | |
0x6b, 0xca, 0xb4, 0xd3, 0xe3, 0xe7, 0xb8, 0xb1, 0x18, 0x61, 0x9f, 0x0a, | |
0x0b, 0xcd, 0x62, 0xf1, 0x3c, 0x35, 0x16, 0xf8, 0xe4, 0x7f, 0x07, 0x10, | |
0xb3, 0xf4, 0x61, 0x2d, 0x3c, 0xa0, 0x38, 0xff, 0x03, 0x20, 0xb4, 0x5e, | |
0xd9, 0x3e, 0x0e, 0x3c, 0xc8, 0xcc, 0x8d, 0xbb, 0xcc, 0xd8, 0x60, 0x23, | |
0x0e, 0x78, 0x95, 0xf0, 0x7e, 0x2b, 0x1f, 0x4a, 0x7e, 0xd8, 0xc8, 0x57, | |
0x87, 0xe8, 0x7c, 0xd2, 0x50, 0x2b, 0xa6, 0xf5, 0x1d, 0x20, 0xfe, 0xe6, | |
0xf8, 0xb6, 0xdd, 0x6e, 0xdb, 0x75, 0x74, 0x12, 0xd1, 0x50, 0x4b, 0x8a, | |
0xde, 0x23, 0x7e, 0xe3, 0xe0, 0x4a, 0xe9, 0x00, 0x82, 0x9d, 0x28, 0x9a, | |
0x58, 0x70, 0xdf, 0x5a, 0x4c, 0x6a, 0x80, 0x5d, 0xd0, 0x09, 0x8c, 0xe2, | |
0xf2, 0xbe, 0xb5, 0x98, 0xa4, 0x55, 0x53, 0x18, 0x92, 0x13, 0x18, 0x59, | |
0x00, 0x8b, 0x32, 0x62, 0x6f, 0xe1, 0x4b, 0x5c, 0xde, 0xb0, 0x16, 0x38, | |
0x34, 0xae, 0x82, 0x1d, 0xe7, 0x55, 0x27, 0x17, 0x10, 0xb7, 0x41, 0x63, | |
0xa1, 0xd7, 0x2d, 0x5c, 0x1f, 0xba, 0x3e, 0xe2, 0x25, 0x0f, 0x76, 0x12, | |
0x6b, 0x91, 0x52, 0x5b, 0x1f, 0xf6, 0xd8, 0xe1, 0x22, 0xff, 0xf7, 0x8f, | |
0x1d, 0x45, 0x87, 0x06, 0x71, 0x31, 0x0c, 0xdd, 0x3e, 0x88, 0x07, 0x11, | |
0xe3, 0xe3, 0x25, 0x43, 0x9e, 0x07, 0x34, 0x4c, 0x79, 0x18, 0x89, 0x1b, | |
0x79, 0x87, 0x70, 0x83, 0x40, 0x30, 0x62, 0xd4, 0x8b, 0xe8, 0xd0, 0x9e, | |
0x79, 0x71, 0xe9, 0x05, 0x9b, 0x56, 0xb8, 0xf7, 0x6f, 0xf1, 0x02, 0xa7, | |
0x90, 0xcc, 0x9e, 0xca, 0x62, 0xbf, 0xad, 0x75, 0xb5, 0x30, 0xf6, 0x4c, | |
0xb1, 0x0e, 0xe8, 0x6c, 0xc0, 0xb5, 0x8b, 0xfa, 0x50, 0xd3, 0x1c, 0xa7, | |
0x90, 0x8c, 0xff, 0x71, 0x53, 0x8f, 0xf6, 0xea, 0xd7, 0x95, 0x38, 0x9a, | |
0x12, 0x6e, 0xfd, 0xc7, 0xc5, 0x36, 0x10, 0x9c, 0x3d, 0x25, 0xb9, 0x4d, | |
0x89, 0x33, 0xea, 0xd5, 0x3d, 0x8d, 0xc3, 0xbc, 0xe7, 0x52, 0x62, 0xbb, | |
0xc9, 0x23, 0x1e, 0x3a, 0x7d, 0xa8, 0x68, 0x7d, 0x03, 0x61, 0x27, 0xb5, | |
0x52, 0xbd, 0xfa, 0x9f, 0x70, 0xcf, 0x1c, 0xd9, 0x98, 0x64, 0xee, 0x1a, | |
0x52, 0xba, 0xe7, 0x63, 0x24, 0x7a, 0x51, 0x57, 0x20, 0x2e, 0x49, 0x75, | |
0x2b, 0x10, 0x15, 0x6d, 0xb0, 0x5b, 0x81, 0x80, 0x5f, 0x6a, 0x00, 0x9a, | |
0x4a, 0x27, 0x1e, 0x74, 0xe8, 0xe5, 0x96, 0x85, 0x7a, 0x50, 0x5b, 0xb4, | |
0x9b, 0x52, 0xa3, 0x2d, 0x7d, 0xa8, 0x41, 0xed, 0xd5, 0x3b, 0xcb, 0x60, | |
0xbc, 0x14, 0xc7, 0xe7, 0xf5, 0xf7, 0xa3, 0x6b, 0xce, 0xf3, 0xd3, 0xb0, | |
0x9e, 0xf0, 0x1c, 0x62, 0xa9, 0x64, 0x20, 0x22, 0xaa, 0x41, 0x0f, 0x62, | |
0x81, 0xa2, 0x9c, 0x70, 0x02, 0x11, 0x8e, 0x28, 0x0a, 0xc2, 0x51, 0x01, | |
0x1d, 0x22, 0x7d, 0xb6, 0x29, 0x11, 0x51, 0xad, 0xa8, 0x47, 0xef, 0x19, | |
0xa0, 0x28, 0x77, 0xe3, 0x67, 0xe2, 0x91, 0x32, 0xbe, 0x4e, 0x0b, 0x37, | |
0x68, 0x1e, 0xdc, 0x4c, 0x8c, 0xaf, 0x53, 0x6a, 0x81, 0x7a, 0x52, 0xbf, | |
0xae, 0x69, 0x9b, 0x38, 0xb7, 0xe9, 0xe3, 0x6a, 0xf1, 0x93, 0x96, 0xba, | |
0xda, 0xc7, 0xaa, 0x57, 0xe7, 0xa4, 0x8f, 0x2d, 0x63, 0xb5, 0x9c, 0x86, | |
0xea, 0x5f, 0xce, 0x76, 0x7f, 0x15, 0x17, 0x92, 0x06, 0xa4, 0xc4, 0x29, | |
0x23, 0xa6, 0x6a, 0xc3, 0x92, 0xb2, 0xa4, 0xc1, 0x29, 0x0a, 0x8f, 0xd2, | |
0x1a, 0xac, 0x69, 0xa9, 0x02, 0x59, 0x35, 0xfb, 0x02, 0x7a, 0xa5, 0xd5, | |
0x54, 0x3d, 0x56, 0x44, 0xd7, 0x37, 0x83, 0x8c, 0xaf, 0x6f, 0xb3, 0x78, | |
0x7b, 0x33, 0x08, 0xe8, 0xdd, 0x33, 0xf5, 0x31, 0xd6, 0xa6, 0xd6, 0xc7, | |
0x8f, 0xb8, 0xc6, 0x74, 0x7e, 0xfb, 0xab, 0xbf, 0x00, 0xec, 0x51, 0xe8, | |
0xd2, 0x17, 0x57, 0x55, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, | |
0x44, 0xae, 0x42, 0x60, 0x82, | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// NOTE: This doesn't actually work. Nothing draws. I'm putting this up here for those who are curious, and also (to be honest) so | |
// someone might point out a silly mistake I'm making. | |
package kit | |
import "core:intrinsics" | |
@(private) | |
L :: intrinsics.constant_utf16_cstring | |
import "core:image" | |
import "core:image/png" | |
import "core:bytes" | |
import "core:slice" | |
import "core:math" | |
import "core:mem" | |
import "core:time" | |
import win32 "core:sys/windows" | |
Flag :: enum { | |
Scale_2x, | |
Scale_3x, | |
Scale_4x, | |
Hide_Cursor, | |
FPS_30, | |
FPS_144, | |
FPS_INF, | |
} | |
Flags :: distinct bit_set[Flag] | |
Color :: image.RGBA_Pixel | |
WHITE := Color{0xff, 0xff, 0xff, 0xff} | |
BLACK := Color{0, 0, 0, 0xff} | |
Rect :: struct { | |
x, y, w, h: int, | |
} | |
Image :: image.Image | |
Glyph :: struct { | |
rect: Rect, | |
xadv: int, | |
} | |
Font :: struct { | |
image: ^Image, | |
glyphs: [256]Glyph, | |
} | |
Key_State :: enum u8 { | |
Down, | |
Pressed, | |
Released, | |
} | |
Key_States :: distinct bit_set[Key_State; u8] | |
Screen :: struct { | |
pixels: []Color, | |
w, h: int, | |
} | |
Context :: struct { | |
wants_quit: bool, | |
hide_cursor: bool, | |
// input | |
char_buf: [32]rune, | |
key_state: [256]Key_States, | |
mouse_state: [16]Key_States, | |
mouse_pos: struct {x, y: int}, | |
mouse_delta: struct {x, y: int}, | |
// time | |
step_time: time.Duration, | |
prev_time: time.Duration, | |
// graphics | |
clip: Rect, | |
font: Font, | |
screen: Screen, | |
// windows | |
win_w, win_h: int, | |
hwnd: win32.HWND, | |
hdc: win32.HDC, | |
} | |
BIG_RECT :: Rect{0, 0, 0xffffff, 0xffffff} | |
create :: proc(title: string, w: int, h: int, flags: Flags) -> ^Context { | |
ctx := new(Context) | |
ctx.screen = Screen{ | |
w = w, | |
h = h, | |
pixels = make([]Color, w * h), | |
} | |
ctx.step_time = flags_to_step_time(flags) | |
ctx.hide_cursor = .Hide_Cursor in flags | |
ctx.clip = Rect{0, 0, w, h} | |
instance := win32.HANDLE(win32.GetModuleHandleW(L(""))) | |
IDC_ARROW :: cast([^]u16)rawptr(uintptr(32512)) | |
window_class := win32.WNDCLASSEXW{ | |
cbSize = size_of(win32.WNDCLASSEXW), | |
lpfnWndProc = wndproc, | |
hInstance = instance, | |
hCursor = win32.LoadCursorW(instance, IDC_ARROW), | |
lpszClassName = win32.utf8_to_wstring(title), | |
hIcon = win32.LoadIconW(instance, L("icon")), | |
} | |
win32.RegisterClassExW(&window_class) | |
w := w | |
h := h | |
scale_size_by_flags(&w, &h, flags) | |
rect := win32.RECT{right = i32(w), bottom = i32(h)} | |
style := win32.WS_OVERLAPPEDWINDOW | |
win32.AdjustWindowRect(&rect, style, false) | |
ctx.hwnd = win32.CreateWindowExW(0, window_class.lpszClassName, window_class.lpszClassName, style, win32.CW_USEDEFAULT, win32.CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, nil, nil, instance, nil) | |
SetPropW(ctx.hwnd, L("Context"), win32.HANDLE(ctx)) | |
win32.ShowWindow(ctx.hwnd, win32.SW_NORMAL) | |
ctx.hdc = win32.GetDC(ctx.hwnd) | |
ctx.font = load_font(font_png[:]) | |
ctx.prev_time = now() | |
return ctx | |
} | |
destroy :: proc(using ctx: ^Context) { | |
win32.ReleaseDC(hwnd, hdc) | |
win32.DestroyWindow(hwnd) | |
free(ctx) | |
} | |
step :: proc(using ctx: ^Context, dt: ^time.Duration = nil) -> bool { | |
RedrawWindow(hwnd, nil, nil, RDW_INVALIDATE|RDW_UPDATENOW) | |
_now := now() | |
wait := prev_time + step_time - _now | |
prev := prev_time | |
if wait > 0 { | |
win32.timeBeginPeriod(1) | |
time.accurate_sleep(wait) | |
win32.timeEndPeriod(1) | |
prev_time += step_time | |
} else { | |
prev_time = _now | |
} | |
if dt != nil do dt^ = prev_time - prev | |
slice.fill(char_buf[:], 0) | |
for key in &key_state { | |
key -= {.Pressed, .Released} | |
} | |
for key in &mouse_state { | |
key -= {.Pressed, .Released} | |
} | |
msg: win32.MSG | |
for win32.PeekMessageW(&msg, hwnd, 0, 0, win32.PM_REMOVE) { | |
win32.TranslateMessage(&msg) | |
win32.DispatchMessageW(&msg) | |
} | |
return !wants_quit | |
} | |
load_font_file :: proc(filename: string) -> Font { | |
img, _ := image.load(filename) | |
return load_font_from_image(img) | |
} | |
load_font_mem :: proc(data: []byte) -> Font { | |
img, err := png.load(data) | |
return load_font_from_image(img) | |
} | |
load_font :: proc{load_font_file, load_font_mem} | |
destroy_font :: proc(font: Font) { | |
image.destroy(font.image) | |
} | |
text_width :: proc(font: ^Font, text: string) -> int { | |
x := 0 | |
for r in text { | |
x += font.glyphs[r].xadv | |
} | |
return x | |
} | |
get_char :: proc "contextless" (using ctx: ^Context) -> rune { | |
for c, i in char_buf { | |
if c == 0 do continue | |
char_buf[i] = 0 | |
return c | |
} | |
return 0 | |
} | |
key_down :: #force_inline proc "contextless" (using ctx: ^Context, key: int) -> bool { | |
return .Down in key_state[key] | |
} | |
key_pressed :: #force_inline proc "contextless" (using ctx: ^Context, key: int) -> bool { | |
return .Pressed in key_state[key] | |
} | |
key_released :: #force_inline proc "contextless" (using ctx: ^Context, key: int) -> bool { | |
return .Released in key_state[key] | |
} | |
mouse_pos :: #force_inline proc "contextless" (using ctx: ^Context) -> (x, y: int) { | |
x = mouse_pos.x | |
y = mouse_pos.y | |
return | |
} | |
mouse_delta :: #force_inline proc "contextless" (using ctx: ^Context) -> (x, y: int) { | |
x = mouse_delta.x | |
y = mouse_delta.y | |
return | |
} | |
mouse_down :: #force_inline proc "contextless" (using ctx: ^Context, button: int) -> bool { | |
return .Down in mouse_state[button] | |
} | |
mouse_pressed :: #force_inline proc "contextless" (using ctx: ^Context, button: int) -> bool { | |
return .Pressed in mouse_state[button] | |
} | |
mouse_released :: #force_inline proc "contextless" (using ctx: ^Context, button: int) -> bool { | |
return .Released in mouse_state[button] | |
} | |
clear :: proc "contextless" (using ctx: ^Context, color: Color) { | |
draw_rect(ctx, color, BIG_RECT) | |
} | |
set_clip :: proc "contextless" (using ctx: ^Context, rect: Rect) { | |
screen_rect := Rect{0, 0, screen.w, screen.h} | |
clip = intersect_rects(rect, screen_rect) | |
} | |
draw_point :: proc "contextless" (using ctx: ^Context, color: Color, x, y: int) { | |
if color.a == 0 do return | |
r := clip | |
if x < r.x || y < r.y || x >= r.x + r.w || y >= r.y + r.h do return | |
dst := &screen.pixels[x + y * screen.w] | |
dst^ = blend_pixel(dst^, color) | |
} | |
draw_rect :: proc "contextless" (using ctx: ^Context, color: Color, rect: Rect) { | |
if color.a == 0 do return | |
rect := rect | |
rect = intersect_rects(rect, clip) | |
d := &screen.pixels[rect.x + rect.y * screen.w] | |
dr := screen.w - rect.w | |
for y in 0..<rect.h { | |
for x in 0..<rect.w { | |
d^ = blend_pixel(d^, color) | |
d = intrinsics.ptr_offset(d, 1) | |
} | |
d = intrinsics.ptr_offset(d, dr) | |
} | |
} | |
draw_line :: proc "contextless" (using ctx: ^Context, color: Color, x1, y1, x2, y2: int) { | |
dx := abs(x2-x1) | |
sx := x1 < x2 ? 1 : -1 | |
dy := -abs(y2 - y1) | |
sy := y1 < y2 ? 1 : -1 | |
err := dx + dy | |
x1 := x1 | |
y1 := y1 | |
x2 := x2 | |
y2 := y2 | |
for { | |
draw_point(ctx, color, x1, y1) | |
if x1 == x2 && y1 == y2 do break | |
e2 := err << 1 | |
if e2 >= dy { | |
err += dy | |
x1 += sx | |
} | |
if e2 <= dx { | |
err += dx | |
y1 += sy | |
} | |
} | |
} | |
draw_image1 :: proc "contextless" (using ctx: ^Context, img: ^Image, x, y: int) { | |
dst := Rect{x, y, img.width, img.height} | |
src := Rect{0, 0, img.width, img.height} | |
draw_image3(ctx, WHITE, BLACK, img, dst, src) | |
} | |
draw_image2 :: proc "contextless" (using ctx: ^Context, color: Color, img: ^Image, x, y: int, src: Rect) { | |
dst := Rect{x, y, abs(src.w), abs(src.h)} | |
draw_image3(ctx, color, BLACK, img, dst, src) | |
} | |
draw_image3 :: proc "contextless" (using ctx: ^Context, mul_color, add_color: Color, img: ^Image, dst, src: Rect) { | |
if src.w == 0 || src.h == 0 || dst.w == 0 || dst.h == 0 do return | |
cx1 := clip.x | |
cy1 := clip.y | |
cx2 := cx1 + clip.w | |
cy2 := cy1 + clip.h | |
stepx := (src.w << 10) / dst.w | |
stepy := (src.h << 10) / dst.h | |
sy := src.y << 10 | |
dy := dst.y | |
if dy < cy1 { | |
sy += (cy1 - dy) * stepy | |
dy = cy1 | |
} | |
ey := min(cy2, dst.y + dst.h) | |
blend_fn := 1 | |
if transmute(u32)mul_color != 0xffffffff do blend_fn = 2 | |
if (transmute(u32)add_color & 0xffffff00) != 0xffffff00 do blend_fn = 3 | |
for ; dy < ey; dy += 1 { | |
if (dy >= cy1 && dy < cy2) { | |
sx := src.x << 10 | |
pixels := image_pixels(img) | |
srow := pixels[(sy >> 10)*img.width:(sy >> 10)*img.width+img.width] | |
drow := screen.pixels[dy*screen.w:dy*screen.w+screen.w] | |
dx := dst.x | |
if dx < cx1 { | |
sx += (cx1 - dx) * stepx | |
dx = cx1 | |
} | |
ex := min(cx2, dst.x + dst.w) | |
for ; dx < ex; dx += 1 { | |
s := &srow[sx >> 10] | |
d := &drow[dx] | |
switch blend_fn { | |
case 1: | |
d^ = blend_pixel(d^, s^) | |
case 2: | |
d^ = blend_pixel(d^, s^, mul_color) | |
case 3: | |
d^ = blend_pixel(d^, s^, mul_color, add_color) | |
} | |
sx += stepx | |
} | |
} | |
sy += stepy | |
} | |
} | |
@(private) | |
image_pixels :: #force_inline proc "contextless" (img: ^Image) -> []Color { | |
s: mem.Raw_Slice | |
s.data = &img.pixels.buf[0] | |
s.len = len(img.pixels.buf) / 4 | |
return transmute([]Color)s | |
} | |
draw_image :: proc{draw_image1, draw_image2, draw_image3} | |
draw_text1 :: proc "contextless" (ctx: ^Context, color: Color, text: string, x, y: int) -> int { | |
return draw_text2(ctx, color, ctx.font, text, x, y) | |
} | |
draw_text2 :: proc "contextless" (ctx: ^Context, color: Color, font: Font, text: string, x, y: int) -> int { | |
x := x | |
for r in text { | |
g := font.glyphs[r] | |
draw_image2(ctx, color, font.image, x, y, g.rect) | |
x += g.xadv | |
} | |
return x | |
} | |
draw_text :: proc{draw_text1, draw_text2} | |
@(private) | |
wndproc :: proc "stdcall" (hwnd: win32.HWND, message: win32.UINT, w_param: win32.WPARAM, l_param: win32.LPARAM) -> win32.LRESULT { | |
ctx := cast(^Context)GetPropW(hwnd, L("Context")) | |
switch message { | |
case win32.WM_PAINT: | |
bmi := win32.BITMAPINFO{ | |
bmiHeader = win32.BITMAPINFOHEADER{ | |
biSize = size_of(win32.BITMAPINFOHEADER), | |
biBitCount = 32, | |
biCompression = win32.BI_RGB, | |
biPlanes = 1, | |
biWidth = i32(ctx.screen.w), | |
biHeight = i32(ctx.screen.h), | |
}, | |
} | |
wr := get_adjusted_window_rect(ctx) | |
win32.StretchDIBits(ctx.hdc, i32(wr.x), i32(wr.y), i32(wr.w), i32(wr.h), 0, 0, i32(ctx.screen.w), i32(ctx.screen.h), &ctx.screen.pixels[0], &bmi, win32.DIB_RGB_COLORS, win32.SRCCOPY) | |
win32.ValidateRect(hwnd, nil) | |
case win32.WM_SETCURSOR: | |
if ctx.hide_cursor && win32.LOWORD(u32(l_param)) == win32.HTCLIENT { | |
win32.SetCursor(nil) | |
} | |
return win32.DefWindowProcW(hwnd, message, w_param, l_param) | |
case win32.WM_KEYDOWN, win32.WM_SYSKEYDOWN: | |
if l_param & (1 << 30) == 0 { | |
ctx.key_state[w_param] = {.Down, .Pressed} | |
} | |
case win32.WM_KEYUP, win32.WM_SYSKEYUP: | |
ctx.key_state[w_param] -= {.Down} | |
ctx.key_state[w_param] += {.Released} | |
case win32.WM_CHAR: | |
if w_param >= 32 { | |
for r in &ctx.char_buf { | |
if r != 0 do continue | |
r = rune(w_param) | |
break | |
} | |
} | |
case win32.WM_LBUTTONDOWN, win32.WM_LBUTTONUP, win32.WM_RBUTTONDOWN, win32.WM_RBUTTONUP, win32.WM_MBUTTONDOWN, win32.WM_MBUTTONUP: | |
button := (message == win32.WM_LBUTTONDOWN || message == win32.WM_LBUTTONUP) ? 1 : (message == win32.WM_RBUTTONDOWN || message == win32.WM_RBUTTONUP) ? 2 : 3 | |
if message == win32.WM_LBUTTONDOWN || message == win32.WM_RBUTTONDOWN || message == win32.WM_MBUTTONDOWN { | |
win32.SetCapture(hwnd) | |
ctx.mouse_state[button] += {.Down, .Pressed} | |
} else { | |
win32.ReleaseCapture() | |
ctx.mouse_state[button] -= {.Down} | |
} | |
fallthrough | |
case win32.WM_MOUSEMOVE: | |
wr := get_adjusted_window_rect(ctx) | |
prevx := ctx.mouse_pos.x | |
prevy := ctx.mouse_pos.y | |
ctx.mouse_pos.x = (cast(int)win32.GET_X_LPARAM(l_param) - wr.x) * ctx.screen.w / wr.w | |
ctx.mouse_pos.y = (cast(int)win32.GET_Y_LPARAM(l_param) - wr.y) * ctx.screen.h / wr.h | |
ctx.mouse_delta.x += ctx.mouse_pos.x - prevx | |
ctx.mouse_delta.y += ctx.mouse_pos.y - prevy | |
case win32.WM_SIZE: | |
if w_param != win32.SIZE_MINIMIZED { | |
ctx.win_w = int(win32.LOWORD(u32(l_param))) | |
ctx.win_h = int(win32.HIWORD(u32(l_param))) | |
ps: win32.PAINTSTRUCT | |
hdc := win32.BeginPaint(hwnd, &ps) | |
brush := win32.CreateSolidBrush(win32.RGB(0, 0, 0)) | |
win32.FillRect(hdc, &ps.rcPaint, brush) | |
win32.DeleteObject(win32.HGDIOBJ(brush)) | |
win32.EndPaint(hwnd, &ps) | |
RedrawWindow(ctx.hwnd, nil, nil, RDW_INVALIDATE|RDW_UPDATENOW) | |
} | |
case win32.WM_QUIT, win32.WM_CLOSE: | |
ctx.wants_quit = true | |
case: | |
return win32.DefWindowProcW(hwnd, message, w_param, l_param) | |
} | |
return 0 | |
} | |
@(private) | |
flags_to_step_time :: proc "contextless" (flags: Flags) -> time.Duration { | |
if .FPS_30 in flags do return 30 * time.Millisecond | |
if .FPS_144 in flags do return 144 * time.Millisecond | |
if .FPS_INF in flags do return 0 | |
return 60 * time.Millisecond | |
} | |
@(private) | |
scale_size_by_flags :: proc "contextless" (w, h: ^int, flags: Flags) { | |
if .Scale_2x in flags { | |
w^ *= 2 | |
h^ *= 2 | |
} else if .Scale_3x in flags { | |
w^ *= 3 | |
h^ *= 3 | |
} else if .Scale_4x in flags { | |
w^ *= 4 | |
h^ *= 4 | |
} | |
} | |
@(private) | |
check_column :: proc "contextless" (img: ^Image, x, y, h: int) -> bool { | |
x := x | |
y := y | |
h := h | |
for h > 0 { | |
pixels := image_pixels(img) | |
a := pixels[x+y*img.width].a | |
if a != 0 do return true | |
y += 1 | |
h -= 1 | |
} | |
return false | |
} | |
@(private) | |
load_font_from_image :: proc "contextless" (img: ^Image) -> (font: Font) { | |
font.image = img | |
for glyph, i in &font.glyphs { | |
r := Rect{ | |
(img.width / 16) * (i % 16), | |
(img.height / 16) * (i / 16), | |
img.width / 16, | |
img.height / 16, | |
} | |
for x := r.x + r.w - 1; x >= r.x; x -= 1 { | |
if check_column(font.image, x, r.y, r.h) do break | |
r.w -= 1 | |
} | |
for x := r.x; x < r.x + r.w; x += 1 { | |
if check_column(font.image, x, r.y, r.h) do break | |
r.x += 1 | |
r.w -= 1 | |
} | |
glyph.xadv = r.w + 1 | |
glyph.rect = r | |
} | |
font.glyphs[' '].rect = Rect{} | |
font.glyphs[' '].xadv = font.glyphs['a'].xadv | |
return | |
} | |
@(private) | |
intersect_rects :: #force_inline proc "contextless" (a, b: Rect) -> Rect { | |
x1 := max(a.x, b.x) | |
y1 := max(a.y, b.y) | |
x2 := min(a.x + a.w, b.x + b.w) | |
y2 := min(a.y + a.h, b.y + b.h) | |
return Rect{x1, y1, x2 - x1, y2 - y1} | |
} | |
@(private) | |
blend_pixel1 :: #force_inline proc "contextless" (dst, src: Color) -> Color { | |
res: Color | |
res_w: u32 | |
dst_w := transmute(u32)dst | |
src_w := transmute(u32)src | |
res_w = (dst_w & 0xff00ff) + ((((src_w & 0xff00ff) - (dst_w & 0xff00ff)) * u32(src.a)) >> 8) | |
res = transmute(Color)res_w | |
res.g = dst.g + (((src.g - dst.g) * src.a) >> 8) | |
res.a = dst.a | |
return res | |
} | |
@(private) | |
blend_pixel2 :: #force_inline proc "contextless" (dst: Color, src: Color, clr: Color) -> Color { | |
dst := dst | |
src := src | |
clr := clr | |
src.a = (src.a * clr.a) >> 8 | |
ia := 0xff - src.a | |
dst.r = ((src.r * clr.r * src.a) >> 16) + ((dst.r * ia) >> 8) | |
dst.g = ((src.g * clr.g * src.a) >> 16) + ((dst.g * ia) >> 8) | |
dst.b = ((src.b * clr.b * src.b) >> 16) + ((dst.b * ia) >> 8) | |
return dst | |
} | |
@(private) | |
blend_pixel3 :: #force_inline proc "contextless" (dst, src, clr, add: Color) -> Color { | |
src := src | |
src.r = min(255, src.r + add.r) | |
src.g = min(255, src.g + add.g) | |
src.b = min(255, src.b + add.b) | |
return blend_pixel2(dst, src, clr) | |
} | |
@(private) | |
blend_pixel :: proc{blend_pixel1, blend_pixel2, blend_pixel3} | |
@(private) | |
get_adjusted_window_rect :: proc "contextless" (using ctx: ^Context) -> Rect { | |
src_ar := f32(screen.h) / f32(screen.w) | |
dst_ar := f32(win_h) / f32(win_w) | |
w, h: int | |
if src_ar < dst_ar { | |
w = win_w | |
h = int(math.ceil(f32(w) * src_ar)) | |
} else { | |
h = win_h | |
w = int(math.ceil(f32(h) / src_ar)) | |
} | |
return Rect{(win_w - w) / 2, (win_h - h) / 2, w, h} | |
} | |
@(private) | |
now :: proc "contextless" () -> time.Duration { | |
_now := time.tick_now() | |
return time.Duration(_now._nsec) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kit | |
import win32 "core:sys/windows" | |
foreign import user32 "system:User32.lib" | |
@(default_calling_convention="stdcall", private) | |
foreign user32 { | |
SetPropW :: proc(hWnd: win32.HWND, lpString: win32.LPCWSTR, hData: win32.HANDLE) -> win32.BOOL --- | |
RedrawWindow :: proc(hWnd: win32.HWND, lprcUpdate: win32.LPRECT, hrgnUpdate: win32.HRGN, flags: win32.UINT) -> win32.BOOL --- | |
GetPropW :: proc(hWnd: win32.HWND, lpString: win32.LPCWSTR) -> win32.HANDLE --- | |
} | |
/* | |
* RedrawWindow() flags | |
*/ | |
/* | |
#define RDW_INVALIDATE 0x0001 | |
#define RDW_INTERNALPAINT 0x0002 | |
#define RDW_ERASE 0x0004 | |
#define RDW_VALIDATE 0x0008 | |
#define RDW_NOINTERNALPAINT 0x0010 | |
#define RDW_NOERASE 0x0020 | |
#define RDW_NOCHILDREN 0x0040 | |
#define RDW_ALLCHILDREN 0x0080 | |
#define RDW_UPDATENOW 0x0100 | |
#define RDW_ERASENOW 0x0200 | |
#define RDW_FRAME 0x0400 | |
#define RDW_NOFRAME 0x0800 | |
*/ | |
@(private) | |
RDW_INVALIDATE :: win32.UINT(0x0001) | |
@(private) | |
RDW_UPDATENOW :: win32.UINT(0x0100) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment