source: trunk/src/input/input.cpp @ 2818

Last change on this file since 2818 was 2818, checked in by sam, 8 years ago

build: fix a few compilation issues with input v2.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
File size: 11.3 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://www.wtfpl.net/ for more details.
9//
10
11
12#if defined HAVE_CONFIG_H
13#   include "config.h"
14#endif
15
16#include <cstdlib>
17
18#include "core.h"
19
20#ifndef LOL_INPUT_V2
21
22namespace lol
23{
24
25/*
26 * Input implementation class
27 */
28
29InputTracker* Input::m_input_tracker = nullptr;
30
31static class InputData
32{
33    friend class Input;
34
35public:
36    InputData()
37      : mouse(-1),
38        buttons(0),
39        nentities(0),
40        lastfocus(0)
41    {
42        m_keystate.Resize(Key::Last);
43        memset(&m_keystate[0], 0, m_keystate.Bytes());
44    }
45
46private:
47    ivec2 mouse;
48    uint32_t buttons;
49
50    Array<uint8_t> m_keystate;
51
52    static int const MAX_ENTITIES = 100;
53    WorldEntity *entities[MAX_ENTITIES];
54    int nentities;
55    WorldEntity *lastfocus;
56
57    Array<Stick *> m_sticks;
58}
59inputdata;
60
61static InputData * const data = &inputdata;
62
63/*
64 * ButtonSetting class
65 */
66
67int ButtonSetting::GetActionSettingIdx(Action a)
68{
69    for (int i = 0; i < m_associated_action_list.Count(); i++)
70        if (ACTION_CMP(m_associated_action_list[i].m_action, a))
71            return i;
72    return -1;
73}
74
75/*
76 * InputTracker class
77 */
78
79InputTracker::InputTracker()
80{
81    m_gamegroup = GAMEGROUP_BEFORE;
82
83    for (int i = 0; i < Key::Last * 2; ++i)
84        m_input_status << 0;
85
86    Ticker::Ref(this);
87}
88
89//Internal
90int InputTracker::GetButtonSettingIdx(Key k)
91{
92    for (int i = 0; i < m_input_assocation_list.Count(); i++)
93        if (m_input_assocation_list[i].m_raw_button == k)
94            return i;
95    return -1;
96}
97
98//-----
99int InputTracker::GetCurrentButtonStatus(Key k)
100{
101    if (k < m_input_status.Count())
102        return m_input_status[k];
103    return 0;
104}
105
106//-----
107int InputTracker::GetPreviousButtonStatus(Key k)
108{
109    if (k < m_input_status.Count())
110        return m_input_status[(int)k + (int)Key::Last];
111    return 0;
112}
113
114//Internal : Updates the action status & timers
115void InputTracker::UpdateActionStatus(float seconds)
116{
117    Array<uint8_t> &keystate = Input::GetKeyboardState();
118
119    //SOOOoooo ugly.
120    for (int i = 0; i < Key::Last; ++i)
121    {
122        m_input_status[i + Key::Last] = m_input_status[i];
123        m_input_status[i] = keystate[i];
124    }
125
126    for (int i = 0; i < m_input_assocation_list.Count(); i++)
127    {
128        ButtonSetting &CurIT = m_input_assocation_list[i];
129
130        for (int j = 0; j < CurIT.m_associated_action_list.Count(); j++)
131        {
132            ActionSetting &CurAS = CurIT.m_associated_action_list[j];
133
134            if (CurAS.m_buffered_since <= CurAS.m_buffering_time)
135                CurAS.m_buffered_since += seconds;
136
137            if (GetCurrentButtonStatus(CurIT.m_raw_button) &&
138                CurAS.m_buffering_time >= .0f)
139                CurAS.m_buffered_since = .0f;
140        }
141    }
142}
143
144//Helps link a software input Action-Id to an hardware input Button-Id.
145void InputTracker::LinkActionToKey(Action a, Key k)
146{
147    int ITIdx = GetButtonSettingIdx(k);
148    if (ITIdx == -1)
149    {
150        ITIdx = m_input_assocation_list.Count();
151        m_input_assocation_list << ButtonSetting(k);
152    }
153
154    ButtonSetting &CurIT = m_input_assocation_list[ITIdx];
155
156    int ASIdx = CurIT.GetActionSettingIdx(a);
157    if (ASIdx == -1)
158    {
159        ASIdx = CurIT.m_associated_action_list.Count();
160        CurIT.m_associated_action_list << ActionSetting(a);
161    }
162}
163
164//Helps unlink a software input Action-Id to an hardware input k-Id.
165void InputTracker::UnlinkAction(Action a)
166{
167    for (int i = 0; i < m_input_assocation_list.Count(); i++)
168    {
169        ButtonSetting &CurIT = m_input_assocation_list[i];
170        int ASIdx = CurIT.GetActionSettingIdx(a);
171        if (ASIdx != -1)
172            CurIT.m_associated_action_list.Remove(ASIdx);
173    }
174}
175
176//Returns the current status of a given action
177int InputTracker::GetStatus(Action a)
178{
179    for (int i = 0; i < m_input_assocation_list.Count(); i++)
180    {
181        ButtonSetting &CurIT = m_input_assocation_list[i];
182        int ASIdx = CurIT.GetActionSettingIdx(a);
183        if (ASIdx != -1)
184        {
185            ActionSetting &CurAS = CurIT.m_associated_action_list[ASIdx];
186
187            if (CurAS.m_buffering_time >= .0f && CurAS.m_buffered_since <= CurAS.m_buffering_time)
188                return 1;
189            return 0;
190        }
191    }
192    return 0;
193}
194
195//Returns TRUE if action status went from Active to Inactive this frame
196bool InputTracker::WasReleased(Action a)
197{
198    for (int i = 0; i < m_input_assocation_list.Count(); i++)
199    {
200        ButtonSetting &CurIT = m_input_assocation_list[i];
201        int ASIdx = CurIT.GetActionSettingIdx(a);
202        if (ASIdx != -1)
203        {
204
205            if (GetPreviousButtonStatus(CurIT.m_raw_button) &&
206                !GetCurrentButtonStatus(CurIT.m_raw_button))
207                return true;
208            return false;
209        }
210    }
211    return false;
212}
213
214//Returns TRUE if action status went from Inactive to Active this frame
215bool InputTracker::WasPressed(Action a)
216{
217    for (int i = 0; i < m_input_assocation_list.Count(); i++)
218    {
219        ButtonSetting &CurIT = m_input_assocation_list[i];
220        int ASIdx = CurIT.GetActionSettingIdx(a);
221        if (ASIdx != -1)
222        {
223            if (!GetPreviousButtonStatus(CurIT.m_raw_button) &&
224                GetCurrentButtonStatus(CurIT.m_raw_button))
225                return true;
226            return false;
227        }
228    }
229    return false;
230}
231
232//Returns the current status of a given action
233int InputTracker::GetStatus(Key k)
234{
235    return GetCurrentButtonStatus(k);
236}
237
238//Returns TRUE if action status went from Active to Inactive this frame
239bool InputTracker::WasReleased(Key k)
240{
241    if (GetPreviousButtonStatus(k) &&
242        !GetCurrentButtonStatus(k))
243        return true;
244    return false;
245}
246
247//Returns TRUE if action status went from Inactive to Active this frame
248bool InputTracker::WasPressed(Key k)
249{
250    if (!GetPreviousButtonStatus(k) &&
251        GetCurrentButtonStatus(k))
252        return true;
253    return false;
254}
255
256/*
257 * Public Input class
258 */
259
260#if 0
261vec2 Input::GetAxis(int axis)
262{
263    vec2 ret;
264
265    /* Simulate a joystick using the keyboard. */
266    int left = GetKeyState(Key::D) - (GetKeyState(Key::A) | GetKeyState(Key::Q));
267    int up = (GetKeyState(Key::W) | GetKeyState(Key::Z)) - GetKeyState(Key::S);
268    ret.x += left;
269    ret.y += up;
270    if (left && up)
271        ret = ret * sqrtf(0.5f);
272
273    return ret;
274}
275#endif
276
277ivec2 Input::GetMousePos()
278{
279    return data->mouse;
280}
281
282uint32_t Input::GetMouseButtons()
283{
284    return data->buttons;
285}
286
287Array<uint8_t> &Input::GetKeyboardState()
288{
289    return data->m_keystate;
290}
291
292int Input::GetKeyState(int key)
293{
294    return data->m_keystate[key];
295}
296
297//Helps link a software input Action-Id to an hardware input Button-Id.
298void Input::LinkActionToKey(Action a, Key k)
299{
300    if (CheckInputTrackerInit())
301        Input::m_input_tracker->LinkActionToKey(a, k);
302}
303
304//Helps unlink a software input Action-Id to an hardware input Button-Id.
305void Input::UnlinkAction(Action a)
306{
307    if (CheckInputTrackerInit())
308        Input::m_input_tracker->UnlinkAction(a);
309}
310
311//Returns the current status of a given action
312int Input::GetStatus(Action a)
313{
314    if (CheckInputTrackerInit())
315        return Input::m_input_tracker->GetStatus(a);
316    return 0;
317}
318
319//Returns TRUE if action status when from Active to Inactive this frame
320bool Input::WasPressed(Action a)
321{
322    if (CheckInputTrackerInit())
323        return Input::m_input_tracker->WasPressed(a);
324    return false;
325}
326
327//Returns TRUE if action status when from Active to Inactive this frame
328bool Input::WasReleased(Action a)
329{
330    if (CheckInputTrackerInit())
331        return Input::m_input_tracker->WasReleased(a);
332    return false;
333}
334
335//Returns the current status of a given action
336int Input::GetStatus(Key k)
337{
338    if (CheckInputTrackerInit())
339        return Input::m_input_tracker->GetStatus(k);
340    return 0;
341}
342
343//Returns TRUE if action status when from Active to Inactive this frame
344bool Input::WasPressed(Key k)
345{
346    if (CheckInputTrackerInit())
347        return Input::m_input_tracker->WasPressed(k);
348    return false;
349}
350
351//Returns TRUE if action status when from Active to Inactive this frame
352bool Input::WasReleased(Key k)
353{
354    if (CheckInputTrackerInit())
355        return Input::m_input_tracker->WasReleased(k);
356    return false;
357}
358
359//--
360void Input::TrackMouse(WorldEntity *e)
361{
362    if (data->nentities >= InputData::MAX_ENTITIES)
363        return;
364    data->entities[data->nentities] = e;
365    data->nentities++;
366}
367
368void Input::UntrackMouse(WorldEntity *e)
369{
370    for (int n = 0; n < data->nentities; n++)
371    {
372        if (data->entities[n] != e)
373            continue;
374
375        data->entities[n] = data->entities[data->nentities - 1];
376        data->nentities--;
377        n--;
378    }
379}
380
381void Input::SetMousePos(ivec2 coord)
382{
383    data->mouse = coord;
384
385    WorldEntity *top = nullptr;
386
387    /* Find the top “widget” amongst all entities that match the
388     * mouse coordinates */
389    for (int n = 0; n < data->nentities; n++)
390    {
391        if (coord.x < data->entities[n]->m_bbox[0].x
392             || coord.x >= data->entities[n]->m_bbox[1].x
393             || coord.y < data->entities[n]->m_bbox[0].y
394             || coord.y >= data->entities[n]->m_bbox[1].y)
395            continue;
396
397        if (!top || top->m_bbox[1].z < data->entities[n]->m_bbox[1].z)
398            top = data->entities[n];
399    }
400
401    for (int n = 0; n < data->nentities; n++)
402    {
403        if (data->entities[n] == top)
404        {
405            data->entities[n]->m_mousepos = coord - (ivec2)top->m_bbox[0].xy;
406            if (top != data->lastfocus)
407                data->entities[n]->m_pressed = data->buttons;
408            else
409                data->entities[n]->m_clicked = 0;
410        }
411        else
412        {
413            data->entities[n]->m_mousepos = ivec2(-1);
414            /* FIXME */
415            data->entities[n]->m_released = 0;
416            data->entities[n]->m_pressed = 0;
417            data->entities[n]->m_clicked = 0;
418        }
419    }
420
421    data->lastfocus = top;
422}
423
424void Input::SetMouseButton(int index)
425{
426    uint32_t flag = 1 << index;
427    data->buttons |= flag;
428
429    if (data->lastfocus)
430    {
431        if (!(data->lastfocus->m_pressed & flag))
432            data->lastfocus->m_clicked |= flag;
433        data->lastfocus->m_pressed |= flag;
434        data->lastfocus->m_released &= ~flag;
435    }
436}
437
438void Input::UnsetMouseButton(int index)
439{
440    uint32_t flag = 1 << index;
441    data->buttons &= ~flag;
442
443    if (data->lastfocus)
444    {
445        if (!(data->lastfocus->m_pressed & flag))
446            data->lastfocus->m_released |= flag;
447        data->lastfocus->m_pressed &= ~flag;
448        data->lastfocus->m_clicked &= ~flag;
449    }
450}
451
452Stick *Input::CreateStick()
453{
454    Stick *stick = new Stick();
455    Ticker::Ref(stick);
456    data->m_sticks.Push(stick);
457    return stick;
458}
459
460void Input::DestroyStick(Stick *stick)
461{
462    for (int i = 0; i < data->m_sticks.Count(); i++)
463        if (data->m_sticks[i] == stick)
464            data->m_sticks.Remove(i);
465    Ticker::Unref(stick);
466}
467
468Stick *Input::TrackStick(int desired)
469{
470    /* FIXME: add the possibility to choose amongst sticks */
471    if (desired >= data->m_sticks.Count())
472        return nullptr;
473    Ticker::Ref(data->m_sticks[desired]);
474    return data->m_sticks[desired];
475}
476
477void Input::UntrackStick(Stick *stick)
478{
479    Ticker::Unref(stick);
480}
481
482} /* namespace lol */
483
484#endif // !LOL_INPUT_V2
Note: See TracBrowser for help on using the repository browser.