karl2d.odin 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. package karl2d
  2. import "base:runtime"
  3. import "core:mem"
  4. import "core:log"
  5. import "core:math"
  6. import "core:math/linalg"
  7. import "core:slice"
  8. import "core:image"
  9. import "core:image/bmp"
  10. import "core:image/png"
  11. import "core:image/tga"
  12. import hm "handle_map"
  13. _ :: bmp
  14. _ :: png
  15. _ :: tga
  16. Handle :: hm.Handle
  17. Texture_Handle :: distinct Handle
  18. // Opens a window and initializes some internal state. The internal state will use `allocator` for
  19. // all dynamically allocated memory. The return value can be ignored unless you need to later call
  20. // `set_state`.
  21. init :: proc(window_width: int, window_height: int, window_title: string,
  22. allocator := context.allocator, loc := #caller_location) -> ^State {
  23. s = new(State, allocator, loc)
  24. s.allocator = allocator
  25. s.custom_context = context
  26. s.width = window_width
  27. s.height = window_height
  28. s.wi = WINDOW_INTERFACE_WIN32
  29. wi = s.wi
  30. window_state_alloc_error: runtime.Allocator_Error
  31. s.window_state, window_state_alloc_error = mem.alloc(wi.state_size())
  32. log.assertf(window_state_alloc_error == nil, "Failed allocating memory for window state: %v", window_state_alloc_error)
  33. wi.init(s.window_state, window_width, window_height, window_title, allocator)
  34. s.window = wi.window_handle()
  35. s.rb = BACKEND_D3D11
  36. rb_alloc_error: runtime.Allocator_Error
  37. s.rb_state, rb_alloc_error = mem.alloc(s.rb.state_size())
  38. log.assertf(rb_alloc_error == nil, "Failed allocating memory for rendering backend: %v", rb_alloc_error)
  39. s.proj_matrix = make_default_projection(window_width, window_height)
  40. s.view_matrix = 1
  41. s.rb.init(s.rb_state, s.window, window_width, window_height, allocator)
  42. s.vertex_buffer_cpu = make([]u8, VERTEX_BUFFER_MAX, allocator, loc)
  43. white_rect: [16*16*4]u8
  44. slice.fill(white_rect[:], 255)
  45. s.shape_drawing_texture = s.rb.load_texture(white_rect[:], 16, 16)
  46. s.default_shader = s.rb.load_shader(string(DEFAULT_SHADER_SOURCE), {
  47. .RG32_Float,
  48. .RG32_Float,
  49. .RGBA8_Norm,
  50. })
  51. return s
  52. }
  53. DEFAULT_SHADER_SOURCE :: #load("shader.hlsl")
  54. // Closes the window and cleans up the internal state.
  55. shutdown :: proc() {
  56. s.rb.destroy_texture(s.shape_drawing_texture)
  57. destroy_shader(s.default_shader)
  58. s.rb.shutdown()
  59. delete(s.vertex_buffer_cpu, s.allocator)
  60. wi.shutdown()
  61. a := s.allocator
  62. free(s.window_state, a)
  63. free(s.rb_state, a)
  64. free(s, a)
  65. s = nil
  66. }
  67. // Clear the backbuffer with supplied color.
  68. clear :: proc(color: Color) {
  69. s.rb.clear(color)
  70. }
  71. // Present the backbuffer. Call at end of frame to make everything you've drawn appear on the screen.
  72. present :: proc() {
  73. draw_current_batch()
  74. s.rb.present()
  75. }
  76. // Call at start or end of frame to process all events that have arrived to the window.
  77. //
  78. // WARNING: Not calling this will make your program impossible to interact with.
  79. process_events :: proc() {
  80. s.keys_went_up = {}
  81. s.keys_went_down = {}
  82. wi.process_events()
  83. events := wi.get_events()
  84. for &event in events {
  85. switch &e in event {
  86. case Window_Event_Close_Wanted:
  87. s.close_window_wanted = true
  88. case Window_Event_Key_Went_Down:
  89. s.keys_went_down[e.key] = true
  90. s.keys_is_held[e.key] = true
  91. case Window_Event_Key_Went_Up:
  92. s.keys_is_held[e.key] = false
  93. s.keys_went_up[e.key] = true
  94. }
  95. }
  96. wi.clear_events()
  97. }
  98. /* Flushes the current batch. This sends off everything to the GPU that has been queued in the
  99. current batch. Normally, you do not need to do this manually. It is done automatically when these
  100. procedures run:
  101. present
  102. set_camera
  103. set_shader
  104. TODO: complete this list and motivate why it needs to happen on those procs (or do that in the
  105. docs for those procs).
  106. */
  107. draw_current_batch :: proc() {
  108. shader := s.batch_shader.? or_else s.default_shader
  109. s.rb.draw(shader, s.batch_texture, s.vertex_buffer_cpu[:s.vertex_buffer_cpu_used])
  110. s.vertex_buffer_cpu_used = 0
  111. }
  112. // Can be used to restore the internal state using the pointer returned by `init`. Useful after
  113. // reloading the library (for example, when doing code hot reload).
  114. set_internal_state :: proc(state: ^State) {
  115. s = state
  116. s.rb.set_internal_state(s.rb_state)
  117. }
  118. get_screen_width :: proc() -> int {
  119. return s.rb.get_swapchain_width()
  120. }
  121. get_screen_height :: proc() -> int {
  122. return s.rb.get_swapchain_height()
  123. }
  124. key_went_down :: proc(key: Keyboard_Key) -> bool {
  125. return s.keys_went_down[key]
  126. }
  127. key_went_up :: proc(key: Keyboard_Key) -> bool {
  128. return s.keys_went_up[key]
  129. }
  130. key_is_held :: proc(key: Keyboard_Key) -> bool {
  131. return s.keys_is_held[key]
  132. }
  133. // Returns true if the user has tried to close the window.
  134. close_window_wanted :: proc() -> bool {
  135. return s.close_window_wanted
  136. }
  137. set_window_position :: proc(x: int, y: int) {
  138. wi.set_position(x, y)
  139. }
  140. set_window_size :: proc(width: int, height: int) {
  141. panic("Not implemented")
  142. }
  143. set_camera :: proc(camera: Maybe(Camera)) {
  144. if camera == s.batch_camera {
  145. return
  146. }
  147. draw_current_batch()
  148. s.batch_camera = camera
  149. s.proj_matrix = make_default_projection(s.width, s.height)
  150. if c, c_ok := camera.?; c_ok {
  151. origin_trans := linalg.matrix4_translate(vec3_from_vec2(-c.origin))
  152. translate := linalg.matrix4_translate(vec3_from_vec2(c.target))
  153. rot := linalg.matrix4_rotate_f32(c.rotation * math.RAD_PER_DEG, {0, 0, 1})
  154. camera_matrix := translate * rot * origin_trans
  155. s.view_matrix = linalg.inverse(camera_matrix)
  156. s.proj_matrix[0, 0] *= c.zoom
  157. s.proj_matrix[1, 1] *= c.zoom
  158. } else {
  159. s.view_matrix = 1
  160. }
  161. s.rb.set_view_projection_matrix(s.proj_matrix * s.view_matrix)
  162. }
  163. load_texture_from_file :: proc(filename: string) -> Texture {
  164. img, img_err := image.load_from_file(filename, options = {.alpha_add_if_missing}, allocator = context.temp_allocator)
  165. if img_err != nil {
  166. log.errorf("Error loading texture %v: %v", filename, img_err)
  167. return {}
  168. }
  169. backend_tex := s.rb.load_texture(img.pixels.buf[:], img.width, img.height)
  170. return {
  171. handle = backend_tex,
  172. width = img.width,
  173. height = img.height,
  174. }
  175. }
  176. destroy_texture :: proc(tex: Texture) {
  177. s.rb.destroy_texture(tex.handle)
  178. }
  179. draw_rect :: proc(r: Rect, c: Color) {
  180. if s.batch_texture != TEXTURE_NONE && s.batch_texture != s.shape_drawing_texture {
  181. draw_current_batch()
  182. }
  183. s.batch_texture = s.shape_drawing_texture
  184. _batch_vertex({r.x, r.y}, {0, 0}, c)
  185. _batch_vertex({r.x + r.w, r.y}, {1, 0}, c)
  186. _batch_vertex({r.x + r.w, r.y + r.h}, {1, 1}, c)
  187. _batch_vertex({r.x, r.y}, {0, 0}, c)
  188. _batch_vertex({r.x + r.w, r.y + r.h}, {1, 1}, c)
  189. _batch_vertex({r.x, r.y + r.h}, {0, 1}, c)
  190. }
  191. draw_rect_outline :: proc(r: Rect, thickness: f32, color: Color) {
  192. t := thickness
  193. // Based on DrawRectangleLinesEx from Raylib
  194. top := Rect {
  195. r.x,
  196. r.y,
  197. r.w,
  198. t,
  199. }
  200. bottom := Rect {
  201. r.x,
  202. r.y + r.h - t,
  203. r.w,
  204. t,
  205. }
  206. left := Rect {
  207. r.x,
  208. r.y + t,
  209. t,
  210. r.h - t * 2,
  211. }
  212. right := Rect {
  213. r.x + r.w - t,
  214. r.y + t,
  215. t,
  216. r.h - t * 2,
  217. }
  218. draw_rect(top, color)
  219. draw_rect(bottom, color)
  220. draw_rect(left, color)
  221. draw_rect(right, color)
  222. }
  223. draw_circle :: proc(center: Vec2, radius: f32, color: Color) {
  224. panic("not implemented")
  225. }
  226. draw_line :: proc(start: Vec2, end: Vec2, thickness: f32, color: Color) {
  227. }
  228. draw_texture :: proc(tex: Texture, pos: Vec2, tint := WHITE) {
  229. draw_texture_ex(
  230. tex,
  231. {0, 0, f32(tex.width), f32(tex.height)},
  232. {pos.x, pos.y, f32(tex.width), f32(tex.height)},
  233. {},
  234. 0,
  235. tint,
  236. )
  237. }
  238. draw_texture_rect :: proc(tex: Texture, rect: Rect, pos: Vec2, tint := WHITE) {
  239. draw_texture_ex(
  240. tex,
  241. rect,
  242. {pos.x, pos.y, rect.w, rect.h},
  243. {},
  244. 0,
  245. tint,
  246. )
  247. }
  248. draw_texture_ex :: proc(tex: Texture, src: Rect, dst: Rect, origin: Vec2, rotation: f32, tint := WHITE) {
  249. if tex.width == 0 || tex.height == 0 {
  250. return
  251. }
  252. if s.batch_texture != TEXTURE_NONE && s.batch_texture != tex.handle {
  253. draw_current_batch()
  254. }
  255. r := dst
  256. r.x -= origin.x
  257. r.y -= origin.y
  258. s.batch_texture = tex.handle
  259. tl, tr, bl, br: Vec2
  260. // Rotation adapted from Raylib's "DrawTexturePro"
  261. if rotation == 0 {
  262. x := dst.x - origin.x
  263. y := dst.y - origin.y
  264. tl = { x, y }
  265. tr = { x + dst.w, y }
  266. bl = { x, y + dst.h }
  267. br = { x + dst.w, y + dst.h }
  268. } else {
  269. sin_rot := math.sin(rotation * math.RAD_PER_DEG)
  270. cos_rot := math.cos(rotation * math.RAD_PER_DEG)
  271. x := dst.x
  272. y := dst.y
  273. dx := -origin.x
  274. dy := -origin.y
  275. tl = {
  276. x + dx * cos_rot - dy * sin_rot,
  277. y + dx * sin_rot + dy * cos_rot,
  278. }
  279. tr = {
  280. x + (dx + dst.w) * cos_rot - dy * sin_rot,
  281. y + (dx + dst.w) * sin_rot + dy * cos_rot,
  282. }
  283. bl = {
  284. x + dx * cos_rot - (dy + dst.h) * sin_rot,
  285. y + dx * sin_rot + (dy + dst.h) * cos_rot,
  286. }
  287. br = {
  288. x + (dx + dst.w) * cos_rot - (dy + dst.h) * sin_rot,
  289. y + (dx + dst.w) * sin_rot + (dy + dst.h) * cos_rot,
  290. }
  291. }
  292. ts := Vec2{f32(tex.width), f32(tex.height)}
  293. up := Vec2{src.x, src.y} / ts
  294. us := Vec2{src.w, src.h} / ts
  295. c := tint
  296. _batch_vertex(tl, up, c)
  297. _batch_vertex(tr, up + {us.x, 0}, c)
  298. _batch_vertex(br, up + us, c)
  299. _batch_vertex(tl, up, c)
  300. _batch_vertex(br, up + us, c)
  301. _batch_vertex(bl, up + {0, us.y}, c)
  302. }
  303. load_shader :: proc(shader_source: string, layout_formats: []Shader_Input_Format = {}) -> Shader {
  304. return s.rb.load_shader(shader_source, layout_formats)
  305. }
  306. destroy_shader :: proc(shader: Shader) {
  307. s.rb.destroy_shader(shader)
  308. }
  309. set_shader :: proc(shader: Maybe(Shader)) {
  310. if maybe_handle_equal(shader, s.batch_shader) {
  311. return
  312. }
  313. draw_current_batch()
  314. s.batch_shader = shader
  315. }
  316. maybe_handle_equal :: proc(m1: Maybe($T), m2: Maybe(T)) -> bool {
  317. if m1 == nil && m2 == nil {
  318. return true
  319. }
  320. m1v, m1v_ok := m1.?
  321. m2v, m2v_ok := m2.?
  322. if !m1v_ok || !m2v_ok {
  323. return false
  324. }
  325. return m1v.handle == m2v.handle
  326. }
  327. set_shader_constant :: proc(shd: Shader, loc: Shader_Constant_Location, val: $T) {
  328. draw_current_batch()
  329. if int(loc.buffer_idx) >= len(shd.constant_buffers) {
  330. log.warnf("Constant buffer idx %v is out of bounds", loc.buffer_idx)
  331. return
  332. }
  333. b := &shd.constant_buffers[loc.buffer_idx]
  334. if int(loc.offset) + size_of(val) > len(b.cpu_data) {
  335. log.warnf("Constant buffer idx %v is trying to be written out of bounds by at offset %v with %v bytes", loc.buffer_idx, loc.offset, size_of(val))
  336. return
  337. }
  338. dst := (^T)(&b.cpu_data[loc.offset])
  339. dst^ = val
  340. }
  341. set_shader_constant_mat4 :: proc(shader: Shader, loc: Shader_Constant_Location, val: matrix[4,4]f32) {
  342. set_shader_constant(shader, loc, val)
  343. }
  344. set_shader_constant_f32 :: proc(shader: Shader, loc: Shader_Constant_Location, val: f32) {
  345. set_shader_constant(shader, loc, val)
  346. }
  347. set_shader_constant_vec2 :: proc(shader: Shader, loc: Shader_Constant_Location, val: Vec2) {
  348. set_shader_constant(shader, loc, val)
  349. }
  350. get_default_shader :: proc() -> Shader {
  351. return s.default_shader
  352. }
  353. set_scissor_rect :: proc(scissor_rect: Maybe(Rect)) {
  354. panic("not implemented")
  355. }
  356. screen_to_world :: proc(pos: Vec2, camera: Camera) -> Vec2 {
  357. panic("not implemented")
  358. }
  359. draw_text :: proc(text: string, pos: Vec2, font_size: f32, color: Color) {
  360. }
  361. mouse_button_went_down :: proc(button: Mouse_Button) -> bool {
  362. panic("not implemented")
  363. }
  364. mouse_button_went_up :: proc(button: Mouse_Button) -> bool {
  365. panic("not implemented")
  366. }
  367. mouse_button_is_held :: proc(button: Mouse_Button) -> bool {
  368. panic("not implemented")
  369. }
  370. get_mouse_wheel_delta :: proc() -> f32 {
  371. return 0
  372. }
  373. get_mouse_position :: proc() -> Vec2 {
  374. panic("not implemented")
  375. }
  376. _batch_vertex :: proc(v: Vec2, uv: Vec2, color: Color) {
  377. v := v
  378. if s.vertex_buffer_cpu_used == len(s.vertex_buffer_cpu) {
  379. panic("Must dispatch here")
  380. }
  381. shd := s.batch_shader.? or_else s.default_shader
  382. base_offset := s.vertex_buffer_cpu_used
  383. pos_offset := shd.default_input_offsets[.Position]
  384. uv_offset := shd.default_input_offsets[.UV]
  385. color_offset := shd.default_input_offsets[.Color]
  386. if pos_offset != -1 {
  387. (^Vec2)(&s.vertex_buffer_cpu[base_offset + pos_offset])^ = v
  388. }
  389. if uv_offset != -1 {
  390. (^Vec2)(&s.vertex_buffer_cpu[base_offset + uv_offset])^ = uv
  391. }
  392. if color_offset != -1 {
  393. (^Color)(&s.vertex_buffer_cpu[base_offset + color_offset])^ = color
  394. }
  395. override_offset: int
  396. for &o, idx in shd.input_overrides {
  397. input := &shd.inputs[idx]
  398. sz := shader_input_format_size(input.format)
  399. if o.used != 0 {
  400. mem.copy(&s.vertex_buffer_cpu[base_offset + override_offset], raw_data(&o.val), o.used)
  401. }
  402. override_offset += sz
  403. }
  404. s.vertex_buffer_cpu_used += shd.vertex_size
  405. }
  406. State :: struct {
  407. allocator: runtime.Allocator,
  408. custom_context: runtime.Context,
  409. wi: Window_Interface,
  410. window_state: rawptr,
  411. rb: Rendering_Backend,
  412. rb_state: rawptr,
  413. close_window_wanted: bool,
  414. keys_went_down: #sparse [Keyboard_Key]bool,
  415. keys_went_up: #sparse [Keyboard_Key]bool,
  416. keys_is_held: #sparse [Keyboard_Key]bool,
  417. window: Window_Handle,
  418. width: int,
  419. height: int,
  420. shape_drawing_texture: Texture_Handle,
  421. batch_camera: Maybe(Camera),
  422. batch_shader: Maybe(Shader),
  423. batch_texture: Texture_Handle,
  424. view_matrix: Mat4,
  425. proj_matrix: Mat4,
  426. vertex_buffer_cpu: []u8,
  427. vertex_buffer_cpu_used: int,
  428. default_shader: Shader,
  429. }
  430. @(private="file")
  431. s: ^State
  432. wi: Window_Interface
  433. Shader_Input_Format :: enum {
  434. Unknown,
  435. RGBA32_Float,
  436. RGBA8_Norm,
  437. RGBA8_Norm_SRGB,
  438. RG32_Float,
  439. R32_Float,
  440. }
  441. Color :: [4]u8
  442. Vec2 :: [2]f32
  443. Vec3 :: [3]f32
  444. Mat4 :: matrix[4,4]f32
  445. Vec2i :: [2]int
  446. Rect :: struct {
  447. x, y: f32,
  448. w, h: f32,
  449. }
  450. Texture :: struct {
  451. handle: Texture_Handle,
  452. width: int,
  453. height: int,
  454. }
  455. Shader :: struct {
  456. handle: Shader_Handle,
  457. constant_buffers: []Shader_Constant_Buffer,
  458. constant_lookup: map[string]Shader_Constant_Location,
  459. constant_builtin_locations: [Shader_Builtin_Constant]Maybe(Shader_Constant_Location),
  460. inputs: []Shader_Input,
  461. input_overrides: []Shader_Input_Value_Override,
  462. default_input_offsets: [Shader_Default_Inputs]int,
  463. vertex_size: int,
  464. }
  465. Camera :: struct {
  466. target: Vec2,
  467. origin: Vec2,
  468. rotation: f32,
  469. zoom: f32,
  470. }
  471. // Support for up to 255 mouse buttons. Cast an int to type `Mouse_Button` to use things outside the
  472. // options presented here.
  473. Mouse_Button :: enum {
  474. Left,
  475. Right,
  476. Middle,
  477. Max = 255,
  478. }
  479. // TODO: These are just copied from raylib, we probably want a list of our own "default colors"
  480. WHITE :: Color { 255, 255, 255, 255 }
  481. BLACK :: Color { 0, 0, 0, 255 }
  482. GRAY :: Color{ 130, 130, 130, 255 }
  483. RED :: Color { 230, 41, 55, 255 }
  484. YELLOW :: Color { 253, 249, 0, 255 }
  485. BLUE :: Color { 0, 121, 241, 255 }
  486. MAGENTA :: Color { 255, 0, 255, 255 }
  487. DARKGRAY :: Color{ 80, 80, 80, 255 }
  488. GREEN :: Color{ 0, 228, 48, 255 }
  489. Shader_Handle :: distinct Handle
  490. SHADER_NONE :: Shader_Handle {}
  491. // Based on Raylib / GLFW
  492. Keyboard_Key :: enum {
  493. None = 0,
  494. // Alphanumeric keys
  495. Apostrophe = 39,
  496. Comma = 44,
  497. Minus = 45,
  498. Period = 46,
  499. Slash = 47,
  500. Zero = 48,
  501. One = 49,
  502. Two = 50,
  503. Three = 51,
  504. Four = 52,
  505. Five = 53,
  506. Six = 54,
  507. Seven = 55,
  508. Eight = 56,
  509. Nine = 57,
  510. Semicolon = 59,
  511. Equal = 61,
  512. A = 65,
  513. B = 66,
  514. C = 67,
  515. D = 68,
  516. E = 69,
  517. F = 70,
  518. G = 71,
  519. H = 72,
  520. I = 73,
  521. J = 74,
  522. K = 75,
  523. L = 76,
  524. M = 77,
  525. N = 78,
  526. O = 79,
  527. P = 80,
  528. Q = 81,
  529. R = 82,
  530. S = 83,
  531. T = 84,
  532. U = 85,
  533. V = 86,
  534. W = 87,
  535. X = 88,
  536. Y = 89,
  537. Z = 90,
  538. Left_Bracket = 91,
  539. Backslash = 92,
  540. Right_Bracket = 93,
  541. Grave = 96,
  542. // Function keys
  543. Space = 32,
  544. Escape = 256,
  545. Enter = 257,
  546. Tab = 258,
  547. Backspace = 259,
  548. Insert = 260,
  549. Delete = 261,
  550. Right = 262,
  551. Left = 263,
  552. Down = 264,
  553. Up = 265,
  554. Page_Up = 266,
  555. Page_Down = 267,
  556. Home = 268,
  557. End = 269,
  558. Caps_Lock = 280,
  559. Scroll_Lock = 281,
  560. Num_Lock = 282,
  561. Print_Screen = 283,
  562. Pause = 284,
  563. F1 = 290,
  564. F2 = 291,
  565. F3 = 292,
  566. F4 = 293,
  567. F5 = 294,
  568. F6 = 295,
  569. F7 = 296,
  570. F8 = 297,
  571. F9 = 298,
  572. F10 = 299,
  573. F11 = 300,
  574. F12 = 301,
  575. Left_Shift = 340,
  576. Left_Control = 341,
  577. Left_Alt = 342,
  578. Left_Super = 343,
  579. Right_Shift = 344,
  580. Right_Control = 345,
  581. Right_Alt = 346,
  582. Right_Super = 347,
  583. Menu = 348,
  584. // Keypad keys
  585. KP_0 = 320,
  586. KP_1 = 321,
  587. KP_2 = 322,
  588. KP_3 = 323,
  589. KP_4 = 324,
  590. KP_5 = 325,
  591. KP_6 = 326,
  592. KP_7 = 327,
  593. KP_8 = 328,
  594. KP_9 = 329,
  595. KP_Decimal = 330,
  596. KP_Divide = 331,
  597. KP_Multiply = 332,
  598. KP_Subtract = 333,
  599. KP_Add = 334,
  600. KP_Enter = 335,
  601. KP_Equal = 336,
  602. }