1 | // MIT License |
2 | |
3 | // Copyright (c) 2020 Vadim Grigoruk @nesbox // grigoruk@gmail.com |
4 | |
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy |
6 | // of this software and associated documentation files (the "Software"), to deal |
7 | // in the Software without restriction, including without limitation the rights |
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
9 | // copies of the Software, and to permit persons to whom the Software is |
10 | // furnished to do so, subject to the following conditions: |
11 | |
12 | // The above copyright notice and this permission notice shall be included in all |
13 | // copies or substantial portions of the Software. |
14 | |
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
21 | // SOFTWARE. |
22 | |
23 | #include "api.h" |
24 | #include "core.h" |
25 | |
26 | #include "tic_assert.h" |
27 | |
28 | static_assert(sizeof(tic80_gamepad) == 1, "tic80_gamepad" ); |
29 | static_assert(sizeof(tic80_gamepads) == 4, "tic80_gamepads" ); |
30 | static_assert(sizeof(tic80_mouse) == 4, "tic80_mouse" ); |
31 | static_assert(sizeof(tic80_keyboard) == 4, "tic80_keyboard" ); |
32 | static_assert(sizeof(tic80_input) == 12, "tic80_input" ); |
33 | |
34 | static bool isKeyPressed(const tic80_keyboard* input, tic_key key) |
35 | { |
36 | for (s32 i = 0; i < TIC80_KEY_BUFFER; i++) |
37 | if (input->keys[i] == key) |
38 | return true; |
39 | |
40 | return false; |
41 | } |
42 | |
43 | u32 tic_api_btnp(tic_mem* tic, s32 index, s32 hold, s32 period) |
44 | { |
45 | tic_core* core = (tic_core*)tic; |
46 | |
47 | if (index < 0) |
48 | { |
49 | return (~core->state.gamepads.previous.data) & core->memory.ram->input.gamepads.data; |
50 | } |
51 | else if (hold < 0 || period < 0) |
52 | { |
53 | return ((~core->state.gamepads.previous.data) & core->memory.ram->input.gamepads.data) & (1 << index); |
54 | } |
55 | |
56 | tic80_gamepads previous; |
57 | |
58 | previous.data = core->state.gamepads.holds[index] >= (u32)hold |
59 | ? period && core->state.gamepads.holds[index] % period ? core->state.gamepads.previous.data : 0 |
60 | : core->state.gamepads.previous.data; |
61 | |
62 | return ((~previous.data) & core->memory.ram->input.gamepads.data) & (1 << index); |
63 | } |
64 | |
65 | u32 tic_api_btn(tic_mem* tic, s32 index) |
66 | { |
67 | tic_core* core = (tic_core*)tic; |
68 | |
69 | if (index < 0) |
70 | { |
71 | return core->memory.ram->input.gamepads.data; |
72 | } |
73 | else |
74 | { |
75 | return core->memory.ram->input.gamepads.data & (1 << index); |
76 | } |
77 | } |
78 | |
79 | bool tic_api_key(tic_mem* tic, tic_key key) |
80 | { |
81 | return key > tic_key_unknown |
82 | ? isKeyPressed(&tic->ram->input.keyboard, key) |
83 | : tic->ram->input.keyboard.data; |
84 | } |
85 | |
86 | bool tic_api_keyp(tic_mem* tic, tic_key key, s32 hold, s32 period) |
87 | { |
88 | tic_core* core = (tic_core*)tic; |
89 | |
90 | if (key > tic_key_unknown) |
91 | { |
92 | bool prevDown = hold >= 0 && period >= 0 && core->state.keyboard.holds[key] >= (u32)hold |
93 | ? period && core->state.keyboard.holds[key] % period |
94 | ? isKeyPressed(&core->state.keyboard.previous, key) |
95 | : false |
96 | : isKeyPressed(&core->state.keyboard.previous, key); |
97 | |
98 | bool down = isKeyPressed(&tic->ram->input.keyboard, key); |
99 | |
100 | return !prevDown && down; |
101 | } |
102 | |
103 | for (s32 i = 0; i < TIC80_KEY_BUFFER; i++) |
104 | { |
105 | tic_key key = tic->ram->input.keyboard.keys[i]; |
106 | |
107 | if (key) |
108 | { |
109 | bool wasPressed = false; |
110 | |
111 | for (s32 p = 0; p < TIC80_KEY_BUFFER; p++) |
112 | { |
113 | if (core->state.keyboard.previous.keys[p] == key) |
114 | { |
115 | wasPressed = true; |
116 | break; |
117 | } |
118 | } |
119 | |
120 | if (!wasPressed) |
121 | return true; |
122 | } |
123 | } |
124 | |
125 | return false; |
126 | } |
127 | |
128 | tic_point tic_api_mouse(tic_mem* memory) |
129 | { |
130 | return memory->ram->input.mouse.relative |
131 | ? (tic_point){memory->ram->input.mouse.rx, memory->ram->input.mouse.ry} |
132 | : (tic_point){memory->ram->input.mouse.x - TIC80_OFFSET_LEFT, memory->ram->input.mouse.y - TIC80_OFFSET_TOP}; |
133 | } |
134 | |
135 | void tic_core_tick_io(tic_mem* tic) |
136 | { |
137 | tic_core* core = (tic_core*)tic; |
138 | |
139 | // process gamepads mapping |
140 | u8* keycodes = tic->ram->mapping.data; |
141 | for(s32 i = 0; i < sizeof(tic_mapping); ++i) |
142 | if(keycodes[i] && tic_api_key(tic, keycodes[i])) |
143 | tic->ram->input.gamepads.data |= 1 << i; |
144 | |
145 | // process gamepad |
146 | for (s32 i = 0; i < COUNT_OF(core->state.gamepads.holds); i++) |
147 | { |
148 | u32 mask = 1 << i; |
149 | u32 prevDown = core->state.gamepads.previous.data & mask; |
150 | u32 down = tic->ram->input.gamepads.data & mask; |
151 | |
152 | u32* hold = &core->state.gamepads.holds[i]; |
153 | if (prevDown && prevDown == down) (*hold)++; |
154 | else *hold = 0; |
155 | } |
156 | |
157 | // process keyboard |
158 | for (s32 i = 0; i < tic_keys_count; i++) |
159 | { |
160 | bool prevDown = isKeyPressed(&core->state.keyboard.previous, i); |
161 | bool down = isKeyPressed(&tic->ram->input.keyboard, i); |
162 | |
163 | u32* hold = &core->state.keyboard.holds[i]; |
164 | |
165 | if (prevDown && down) (*hold)++; |
166 | else *hold = 0; |
167 | } |
168 | } |
169 | |