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

Last change on this file since 1949 was 1949, checked in by sam, 7 years ago

misc: very minor tweaks here and there.

  • Property svn:keywords set to Id
File size: 11.7 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2012 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://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include <cstdlib>
16
17#if defined USE_SDL
18#   if defined HAVE_SDL_SDL_H
19#      include <SDL/SDL.h>
20#   else
21#      include <SDL.h>
22#   endif
23#endif
24
25#include "core.h"
26
27namespace lol
28{
29
30/*
31 * Input implementation class
32 */
33
34InputTracker* Input::m_input_tracker = NULL;
35
36static class InputData
37{
38    friend class Input;
39
40public:
41    InputData()
42      : mouse(-1),
43        buttons(0),
44        nentities(0),
45        lastfocus(0)
46    { }
47
48private:
49    ivec2 mouse;
50    ivec3 buttons;
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#if defined USE_SDL
118#if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION >= 3
119    Uint8 *keystate = SDL_GetKeyboardState(NULL);
120#else
121    Uint8 *keystate = SDL_GetKeyState(NULL);
122#endif
123    //SOOOoooo ugly.
124    for (int i = 0; i < Key::Last; ++i)
125    {
126        m_input_status[i + Key::Last] = m_input_status[i];
127        m_input_status[i] = keystate[i];
128    }
129#endif
130
131    for (int i = 0; i < m_input_assocation_list.Count(); i++)
132    {
133        ButtonSetting &CurIT = m_input_assocation_list[i];
134
135        for (int j = 0; j < CurIT.m_associated_action_list.Count(); j++)
136        {
137            ActionSetting &CurAS = CurIT.m_associated_action_list[j];
138
139            if (CurAS.m_buffered_since <= CurAS.m_buffering_time)
140                CurAS.m_buffered_since += seconds;
141
142            if (GetCurrentButtonStatus(CurIT.m_raw_button) &&
143                CurAS.m_buffering_time >= .0f)
144                CurAS.m_buffered_since = .0f;
145        }
146    }
147}
148
149//Helps link a software input Action-Id to an hardware input Button-Id.
150void InputTracker::LinkActionToKey(Action a, Key k)
151{
152    int ITIdx = GetButtonSettingIdx(k);
153    if (ITIdx == -1)
154    {
155        ITIdx = m_input_assocation_list.Count();
156        m_input_assocation_list << ButtonSetting(k);
157    }
158
159    ButtonSetting &CurIT = m_input_assocation_list[ITIdx];
160
161    int ASIdx = CurIT.GetActionSettingIdx(a);
162    if (ASIdx == -1)
163    {
164        ASIdx = CurIT.m_associated_action_list.Count();
165        CurIT.m_associated_action_list << ActionSetting(a);
166    }
167}
168
169//Helps unlink a software input Action-Id to an hardware input k-Id.
170void InputTracker::UnlinkAction(Action a)
171{
172    for (int i = 0; i < m_input_assocation_list.Count(); i++)
173    {
174        ButtonSetting &CurIT = m_input_assocation_list[i];
175        int ASIdx = CurIT.GetActionSettingIdx(a);
176        if (ASIdx != -1)
177            CurIT.m_associated_action_list.Remove(ASIdx);
178    }
179}
180
181//Returns the current status of a given action
182int InputTracker::GetStatus(Action a)
183{
184    for (int i = 0; i < m_input_assocation_list.Count(); i++)
185    {
186        ButtonSetting &CurIT = m_input_assocation_list[i];
187        int ASIdx = CurIT.GetActionSettingIdx(a);
188        if (ASIdx != -1)
189        {
190            ActionSetting &CurAS = CurIT.m_associated_action_list[ASIdx];
191
192            if (CurAS.m_buffering_time >= .0f && CurAS.m_buffered_since <= CurAS.m_buffering_time)
193                return 1;
194            return 0;
195        }
196    }
197    return 0;
198}
199
200//Returns TRUE if action status went from Active to Inactive this frame
201bool InputTracker::WasReleased(Action a)
202{
203    for (int i = 0; i < m_input_assocation_list.Count(); i++)
204    {
205        ButtonSetting &CurIT = m_input_assocation_list[i];
206        int ASIdx = CurIT.GetActionSettingIdx(a);
207        if (ASIdx != -1)
208        {
209
210            if (GetPreviousButtonStatus(CurIT.m_raw_button) &&
211                !GetCurrentButtonStatus(CurIT.m_raw_button))
212                return true;
213            return false;
214        }
215    }
216    return false;
217}
218
219//Returns TRUE if action status went from Inactive to Active this frame
220bool InputTracker::WasPressed(Action a)
221{
222    for (int i = 0; i < m_input_assocation_list.Count(); i++)
223    {
224        ButtonSetting &CurIT = m_input_assocation_list[i];
225        int ASIdx = CurIT.GetActionSettingIdx(a);
226        if (ASIdx != -1)
227        {
228            if (!GetPreviousButtonStatus(CurIT.m_raw_button) &&
229                GetCurrentButtonStatus(CurIT.m_raw_button))
230                return true;
231            return false;
232        }
233    }
234    return false;
235}
236
237//Returns the current status of a given action
238int InputTracker::GetStatus(Key k)
239{
240    return GetCurrentButtonStatus(k);
241}
242
243//Returns TRUE if action status went from Active to Inactive this frame
244bool InputTracker::WasReleased(Key k)
245{
246    if (GetPreviousButtonStatus(k) &&
247        !GetCurrentButtonStatus(k))
248        return true;
249    return false;
250}
251
252//Returns TRUE if action status went from Inactive to Active this frame
253bool InputTracker::WasPressed(Key k)
254{
255    if (!GetPreviousButtonStatus(k) &&
256        GetCurrentButtonStatus(k))
257        return true;
258    return false;
259}
260
261/*
262 * Public Input class
263 */
264
265#if 0
266vec2 Input::GetAxis(int axis)
267{
268    vec2 ret;
269
270#if defined USE_SDL
271    /* Simulate a joystick using the keyboard. This SDL call is free. */
272#if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION >= 3
273    Uint8 *keystate = SDL_GetKeyboardState(NULL);
274#else
275    Uint8 *keystate = SDL_GetKeyState(NULL);
276#endif
277    int left = keystate[SDLK_d] - (keystate[SDLK_a] | keystate[SDLK_q]);
278    int up = (keystate[SDLK_w] | keystate[SDLK_z]) - keystate[SDLK_s] ;
279    ret.x += left;
280    ret.y += up;
281    if (left && up)
282        ret = ret * sqrtf(0.5f);
283#else
284    ret = vec2(0, 0);
285#endif
286
287    return ret;
288}
289#endif
290
291ivec2 Input::GetMousePos()
292{
293    return data->mouse;
294}
295
296ivec3 Input::GetMouseButtons()
297{
298    return data->buttons;
299}
300
301//BH : Added this, is a v0.1 Alpha version.
302int Input::GetButtonState(int button)
303{
304#if defined USE_SDL
305#   if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION >= 3
306    Uint8 *keystate = SDL_GetKeyboardState(NULL);
307#   else
308    Uint8 *keystate = SDL_GetKeyState(NULL);
309#   endif
310    return keystate[button];
311#else
312    return 0;
313#endif
314}
315
316//Helps link a software input Action-Id to an hardware input Button-Id.
317void Input::LinkActionToKey(Action a, Key k)
318{
319    if (CheckInputTrackerInit())
320        Input::m_input_tracker->LinkActionToKey(a, k);
321}
322
323//Helps unlink a software input Action-Id to an hardware input Button-Id.
324void Input::UnlinkAction(Action a)
325{
326    if (CheckInputTrackerInit())
327        Input::m_input_tracker->UnlinkAction(a);
328}
329
330//Returns the current status of a given action
331int Input::GetStatus(Action a)
332{
333    if (CheckInputTrackerInit())
334        return Input::m_input_tracker->GetStatus(a);
335    return 0;
336}
337
338//Returns TRUE if action status when from Active to Inactive this frame
339bool Input::WasPressed(Action a)
340{
341    if (CheckInputTrackerInit())
342        return Input::m_input_tracker->WasPressed(a);
343    return false;
344}
345
346//Returns TRUE if action status when from Active to Inactive this frame
347bool Input::WasReleased(Action a)
348{
349    if (CheckInputTrackerInit())
350        return Input::m_input_tracker->WasReleased(a);
351    return false;
352}
353
354//Returns the current status of a given action
355int Input::GetStatus(Key k)
356{
357    if (CheckInputTrackerInit())
358        return Input::m_input_tracker->GetStatus(k);
359    return 0;
360}
361
362//Returns TRUE if action status when from Active to Inactive this frame
363bool Input::WasPressed(Key k)
364{
365    if (CheckInputTrackerInit())
366        return Input::m_input_tracker->WasPressed(k);
367    return false;
368}
369
370//Returns TRUE if action status when from Active to Inactive this frame
371bool Input::WasReleased(Key k)
372{
373    if (CheckInputTrackerInit())
374        return Input::m_input_tracker->WasReleased(k);
375    return false;
376}
377
378//--
379void Input::TrackMouse(WorldEntity *e)
380{
381    if (data->nentities >= InputData::MAX_ENTITIES)
382        return;
383    data->entities[data->nentities] = e;
384    data->nentities++;
385}
386
387void Input::UntrackMouse(WorldEntity *e)
388{
389    for (int n = 0; n < data->nentities; n++)
390    {
391        if (data->entities[n] != e)
392            continue;
393
394        data->entities[n] = data->entities[data->nentities - 1];
395        data->nentities--;
396        n--;
397    }
398}
399
400void Input::SetMousePos(ivec2 coord)
401{
402    data->mouse = coord;
403
404    WorldEntity *top = NULL;
405
406    /* Find the top “widget” amongst all entities that match the
407     * mouse coordinates */
408    for (int n = 0; n < data->nentities; n++)
409    {
410        if (coord.x < data->entities[n]->m_bbox[0].x
411             || coord.x >= data->entities[n]->m_bbox[1].x
412             || coord.y < data->entities[n]->m_bbox[0].y
413             || coord.y >= data->entities[n]->m_bbox[1].y)
414            continue;
415
416        if (!top || top->m_bbox[1].z < data->entities[n]->m_bbox[1].z)
417            top = data->entities[n];
418    }
419
420    for (int n = 0; n < data->nentities; n++)
421    {
422        if (data->entities[n] == top)
423        {
424            data->entities[n]->m_mousepos = coord - (ivec2)top->m_bbox[0].xy;
425            if (top != data->lastfocus)
426                data->entities[n]->m_pressed = data->buttons;
427            else
428                data->entities[n]->m_clicked = ivec3(0);
429        }
430        else
431        {
432            data->entities[n]->m_mousepos = ivec2(-1);
433            /* FIXME */
434            data->entities[n]->m_released = ivec3(0);
435            data->entities[n]->m_pressed = ivec3(0);
436            data->entities[n]->m_clicked = ivec3(0);
437        }
438    }
439
440    data->lastfocus = top;
441}
442
443void Input::SetMouseButton(int index)
444{
445    data->buttons[index] = 1;
446
447    if (data->lastfocus)
448    {
449        if (!data->lastfocus->m_pressed[index])
450            data->lastfocus->m_clicked[index] = 1;
451        data->lastfocus->m_pressed[index] = 1;
452        data->lastfocus->m_released[index] = 0;
453    }
454}
455
456void Input::UnsetMouseButton(int index)
457{
458    data->buttons[index] = 0;
459
460    if (data->lastfocus)
461    {
462        if (data->lastfocus->m_pressed[index])
463            data->lastfocus->m_released[index] = 1;
464        data->lastfocus->m_pressed[index] = 0;
465        data->lastfocus->m_clicked[index] = 0;
466    }
467}
468
469Stick *Input::CreateStick()
470{
471    Stick *stick = new Stick();
472    Ticker::Ref(stick);
473    data->m_sticks.Push(stick);
474    return stick;
475}
476
477void Input::DestroyStick(Stick *stick)
478{
479    for (int i = 0; i < data->m_sticks.Count(); i++)
480        if (data->m_sticks[i] == stick)
481            data->m_sticks.Remove(i);
482    Ticker::Unref(stick);
483}
484
485Stick *Input::TrackStick(int desired)
486{
487    /* FIXME: add the possibility to choose amongst sticks */
488    if (desired >= data->m_sticks.Count())
489        return NULL;
490    Ticker::Ref(data->m_sticks[desired]);
491    return data->m_sticks[desired];
492}
493
494void Input::UntrackStick(Stick *stick)
495{
496    Ticker::Unref(stick);
497}
498
499} /* namespace lol */
500
Note: See TracBrowser for help on using the repository browser.