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

Last change on this file since 2816 was 2816, checked in by lolbot, 8 years ago

fixed 542 files out of 2754:

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