diff --git a/build/vs2010/Lol.sln b/build/vs2010/Lol.sln index 40a0b4fa..91e445af 100644 --- a/build/vs2010/Lol.sln +++ b/build/vs2010/Lol.sln @@ -152,6 +152,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Demos", "Demos", "{E5C5E320 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Lol.js", "Lol.js", "{F7D4A671-612F-4FF4-883F-2097697694B7}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "07_input", "..\..\demos\tutorial\07_input.vcxproj", "{572E5B9C-7E19-489C-BD8A-E8401CFBBC47}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "06_sprite", "..\..\demos\tutorial\06_sprite.vcxproj", "{E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -941,6 +945,46 @@ Global {AA376B9B-484B-4DC4-982F-6CFA645E441E}.Release|Xbox 360.ActiveCfg = Release|Xbox 360 {AA376B9B-484B-4DC4-982F-6CFA645E441E}.Release|Xbox 360.Build.0 = Release|Xbox 360 {AA376B9B-484B-4DC4-982F-6CFA645E441E}.Release|Xbox 360.Deploy.0 = Release|Xbox 360 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Debug|Any CPU.ActiveCfg = Debug|x64 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Debug|ORBIS.ActiveCfg = Debug|x64 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Debug|PS3.ActiveCfg = Debug|x64 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Debug|Win32.ActiveCfg = Debug|Win32 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Debug|Win32.Build.0 = Debug|Win32 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Debug|x64.ActiveCfg = Debug|x64 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Debug|x64.Build.0 = Debug|x64 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Debug|Xbox 360.ActiveCfg = Debug|x64 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Release|Any CPU.ActiveCfg = Release|x64 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Release|Mixed Platforms.Build.0 = Release|Win32 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Release|ORBIS.ActiveCfg = Release|x64 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Release|PS3.ActiveCfg = Release|x64 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Release|Win32.ActiveCfg = Release|Win32 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Release|Win32.Build.0 = Release|Win32 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Release|x64.ActiveCfg = Release|x64 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Release|x64.Build.0 = Release|x64 + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47}.Release|Xbox 360.ActiveCfg = Release|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Debug|Any CPU.ActiveCfg = Debug|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Debug|Mixed Platforms.ActiveCfg = Debug|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Debug|Mixed Platforms.Build.0 = Debug|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Debug|ORBIS.ActiveCfg = Debug|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Debug|PS3.ActiveCfg = Debug|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Debug|Win32.ActiveCfg = Debug|Win32 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Debug|Win32.Build.0 = Debug|Win32 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Debug|x64.ActiveCfg = Debug|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Debug|x64.Build.0 = Debug|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Debug|Xbox 360.ActiveCfg = Debug|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Release|Any CPU.ActiveCfg = Release|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Release|Mixed Platforms.ActiveCfg = Release|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Release|Mixed Platforms.Build.0 = Release|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Release|ORBIS.ActiveCfg = Release|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Release|PS3.ActiveCfg = Release|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Release|Win32.ActiveCfg = Release|Win32 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Release|Win32.Build.0 = Release|Win32 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Release|x64.ActiveCfg = Release|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Release|x64.Build.0 = Release|x64 + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF}.Release|Xbox 360.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -965,7 +1009,8 @@ Global {80F81C11-8DA2-4990-91CB-9807783BA46E} = {E0491194-35E3-4513-9D31-608EA3165ECF} {EE203B88-44CF-4859-9D42-7A1F43FECB52} = {E0491194-35E3-4513-9D31-608EA3165ECF} {7CE9FE12-E4AB-4A22-90D4-2C15F0C30D4E} = {E0491194-35E3-4513-9D31-608EA3165ECF} - {B92ABADC-45BE-4CC5-B724-9426053123A1} = {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} + {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} = {E5C5E320-C077-4362-9A3F-3920C6447601} + {F7D4A671-612F-4FF4-883F-2097697694B7} = {E5C5E320-C077-4362-9A3F-3920C6447601} {7B083DA2-FE08-4F6D-BFDD-195D5C2783EB} = {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} {1C5B8702-290C-42DA-AA9E-671348F5B747} = {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} {6BF81B39-EDC2-4227-9992-C2D8ABEA95AF} = {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} @@ -973,6 +1018,9 @@ Global {B0A53D75-CBB4-4FDF-93AC-2D12A79ADA0E} = {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} {834852DB-EDB6-4FD0-BCF9-45CD01126962} = {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} {6BF81B39-EDC2-4227-9982-C2D8ABEA95AF} = {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} + {B92ABADC-45BE-4CC5-B724-9426053123A1} = {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47} = {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF} = {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} {32F3F8CF-D22E-45E4-BEB8-AD909E8C5515} = {33704AA4-F2B5-4138-A40D-E3E77F89ED46} {EE203B88-44CF-4859-9D42-7A5F40FECB52} = {8C77EAA8-1077-4EF7-AE53-97C6C60A3601} {B357514A-7881-422D-8358-161B689E7620} = {3D341D8A-E400-4B1D-BC05-B5C35487D9B5} @@ -986,8 +1034,6 @@ Global {C2E01551-B636-4324-8461-71811DF6FBB5} = {E27FDF36-50C4-4ED2-8CF5-A20FED016910} {58922993-9830-4A40-B462-0326342F69ED} = {9CC50C06-DF5E-41A7-AD90-04F05386E081} {FAF82AD2-D9F4-4694-9A01-103BC5B771B4} = {B583BBFF-BE97-4F4E-BA1E-1F978A31EAB0} - {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} = {E5C5E320-C077-4362-9A3F-3920C6447601} - {F7D4A671-612F-4FF4-883F-2097697694B7} = {E5C5E320-C077-4362-9A3F-3920C6447601} {AA376B9B-484B-4DC4-982F-6CFA645E441E} = {F7D4A671-612F-4FF4-883F-2097697694B7} EndGlobalSection EndGlobal diff --git a/demos/tutorial/06_sprite.vcxproj b/demos/tutorial/06_sprite.vcxproj index 961cdca4..d8dbc8b6 100644 --- a/demos/tutorial/06_sprite.vcxproj +++ b/demos/tutorial/06_sprite.vcxproj @@ -1,71 +1,71 @@ - - - - - Debug - PS3 - - - Debug - Win32 - - - Debug - x64 - - - Debug - Xbox 360 - - - Release - PS3 - - - Release - Win32 - - - Release - x64 - - - Release - Xbox 360 - - - - - - - - {9e62f2fe-3408-4eae-8238-fd84238ceeda} - - - {83d3b207-c601-4025-8f41-01dedc354661} - - - {d84021ca-b233-4e0f-8a52-071b83bbccc4} - - - - {1c5b8702-290c-42da-aa9e-671348f5b747} - Application - Win32Proj - - - - - - - - - - - - - - - - - + + + + + Debug + PS3 + + + Debug + Win32 + + + Debug + x64 + + + Debug + Xbox 360 + + + Release + PS3 + + + Release + Win32 + + + Release + x64 + + + Release + Xbox 360 + + + + + + + + {9e62f2fe-3408-4eae-8238-fd84238ceeda} + + + {83d3b207-c601-4025-8f41-01dedc354661} + + + {d84021ca-b233-4e0f-8a52-071b83bbccc4} + + + + {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF} + Application + Win32Proj + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demos/tutorial/07_input.cpp b/demos/tutorial/07_input.cpp new file mode 100644 index 00000000..a3dc46fe --- /dev/null +++ b/demos/tutorial/07_input.cpp @@ -0,0 +1,230 @@ +// +// Lol Engine - Cube tutorial +// +// Copyright: (c) 2011-2013 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#define LOL_INPUT_V2 + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" +#include "loldebug.h" + +using namespace std; +using namespace lol; + +LOLFX_RESOURCE_DECLARE(07_input); + +enum +{ + KEY_MANUAL_ROTATION, + KEY_DRAG_MESH, + KEY_MAX +}; + +enum +{ + AXIS_DRAG_PITCH, + AXIS_DRAG_YAW, + AXIS_PITCH, + AXIS_YAW, + AXIS_MAX +}; + +Controller* controller; + +class Cube : public WorldEntity +{ +public: + Cube() + { + m_pitch_angle = 0; + m_yaw_angle = 0; + m_autorot = true; + + /* Front vertices/colors */ + m_mesh.Push(vec3(-1.0, -1.0, 1.0), vec3(1.0, 0.0, 1.0)); + m_mesh.Push(vec3( 1.0, -1.0, 1.0), vec3(0.0, 1.0, 0.0)); + m_mesh.Push(vec3( 1.0, 1.0, 1.0), vec3(1.0, 0.5, 0.0)); + m_mesh.Push(vec3(-1.0, 1.0, 1.0), vec3(1.0, 1.0, 0.0)); + /* Back */ + m_mesh.Push(vec3(-1.0, -1.0, -1.0), vec3(1.0, 0.0, 0.0)); + m_mesh.Push(vec3( 1.0, -1.0, -1.0), vec3(0.0, 0.5, 0.0)); + m_mesh.Push(vec3( 1.0, 1.0, -1.0), vec3(0.0, 0.5, 1.0)); + m_mesh.Push(vec3(-1.0, 1.0, -1.0), vec3(0.0, 0.0, 1.0)); + + m_faces_indices << 0 << 1 << 2 << 2 << 3 << 0; + m_faces_indices << 1 << 5 << 6 << 6 << 2 << 1; + m_faces_indices << 7 << 6 << 5 << 5 << 4 << 7; + m_faces_indices << 4 << 0 << 3 << 3 << 7 << 4; + m_faces_indices << 4 << 5 << 1 << 1 << 0 << 4; + m_faces_indices << 3 << 2 << 6 << 6 << 7 << 3; + + m_lines_indices << 0 << 1 << 1 << 2 << 2 << 3 << 3 << 0; + m_lines_indices << 4 << 5 << 5 << 6 << 6 << 7 << 7 << 4; + m_lines_indices << 0 << 4 << 1 << 5 << 2 << 6 << 3 << 7; + + m_text = new Text(NULL, "data/font/ascii.png"); + m_text->SetPos(ivec3(5, 5, 1)); + Ticker::Ref(m_text); + + m_ready = false; + } + + ~Cube() + { + Ticker::Unref(m_text); + } + + virtual void TickGame(float seconds) + { + WorldEntity::TickGame(seconds); + + if (controller->GetKey(KEY_MANUAL_ROTATION).IsPressed()) + m_autorot = !m_autorot; + + if (controller->GetKey(KEY_DRAG_MESH).IsDown()) + { + InputDevice::CaptureMouse(true); + m_pitch_angle -= controller->GetAxis(AXIS_DRAG_PITCH).GetValue() * seconds * 100; + m_yaw_angle += controller->GetAxis(AXIS_DRAG_YAW).GetValue() * seconds * 100; + } + else + { + InputDevice::CaptureMouse(false); + if (m_autorot) + m_yaw_angle += seconds * 20; + } + if (lol::abs(controller->GetAxis(AXIS_PITCH).GetValue()) > 0.2f) + m_pitch_angle -= controller->GetAxis(AXIS_PITCH).GetValue() * seconds * 100; + if (lol::abs(controller->GetAxis(AXIS_YAW).GetValue()) > 1.0f) + m_yaw_angle += controller->GetAxis(AXIS_YAW).GetValue() * seconds * 100; + + InputDevice* mouse = InputDevice::Get("Mouse"); + if (mouse) + { + char buf[128]; + std::sprintf(buf, "cursor: (%0.3f, %0.3f) - pixel (%d, %d)", + mouse->GetCursor(0).x, mouse->GetCursor(0).y, + mouse->GetCursorPixel(0).x, mouse->GetCursorPixel(0).y); + m_text->SetText(buf); + } + else + { + m_text->SetText("no mouse detected"); + } + + mat4 anim = mat4::rotate(m_yaw_angle, vec3(0, 1, 0)) * mat4::rotate(m_pitch_angle, vec3(1, 0, 0)); + mat4 model = mat4::translate(vec3(0, 0, -4.5)); + mat4 view = mat4::lookat(vec3(0, 2, 0), vec3(0, 0, -4), vec3(0, 1, 0)); + mat4 proj = mat4::perspective(45.0f, 640.0f, 480.0f, 0.1f, 10.0f); + + m_matrix = proj * view * model * anim; + } + + virtual void TickDraw(float seconds) + { + WorldEntity::TickDraw(seconds); + + if (!m_ready) + { + m_shader = Shader::Create(LOLFX_RESOURCE_NAME(07_input)); + + m_mvp = m_shader->GetUniformLocation("in_Matrix"); + m_coord = m_shader->GetAttribLocation("in_Vertex", + VertexUsage::Position, 0); + m_color = m_shader->GetAttribLocation("in_Color", + VertexUsage::Color, 0); + + m_vdecl = + new VertexDeclaration(VertexStream(VertexUsage::Position, + VertexUsage::Color)); + + m_vbo = new VertexBuffer(m_mesh.Bytes()); + void *mesh = m_vbo->Lock(0, 0); + memcpy(mesh, &m_mesh[0], m_mesh.Bytes()); + m_vbo->Unlock(); + + m_lines_ibo = new IndexBuffer(m_lines_indices.Bytes()); + void *indices = m_lines_ibo->Lock(0, 0); + memcpy(indices, &m_lines_indices[0], m_lines_indices.Bytes()); + m_lines_ibo->Unlock(); + + m_faces_ibo = new IndexBuffer(m_faces_indices.Bytes()); + indices = m_faces_ibo->Lock(0, 0); + memcpy(indices, &m_faces_indices[0], m_faces_indices.Bytes()); + m_faces_ibo->Unlock(); + + /* FIXME: this object never cleans up */ + m_ready = true; + } + + g_renderer->SetClearColor(vec4(0.0f, 0.0f, 0.0f, 1.0f)); + + m_shader->Bind(); + m_vdecl->SetStream(m_vbo, m_coord, m_color); + m_vdecl->Bind(); + + m_shader->SetUniform(m_mvp, m_matrix); + m_lines_ibo->Bind(); + m_vdecl->DrawIndexedElements(MeshPrimitive::Lines, 0, 0, + m_mesh.Count(), 0, m_lines_indices.Count()); + m_lines_ibo->Unbind(); + + m_shader->SetUniform(m_mvp, m_matrix * mat4::scale(0.5f)); + m_faces_ibo->Bind(); + m_vdecl->DrawIndexedElements(MeshPrimitive::Triangles, 0, 0, + m_mesh.Count(), 0, m_faces_indices.Count()); + m_faces_ibo->Unbind(); + + m_vdecl->Unbind(); + } + +private: + bool m_autorot; + float m_pitch_angle; + float m_yaw_angle; + mat4 m_matrix; + Array m_mesh; + Array m_lines_indices, m_faces_indices; + + Shader *m_shader; + ShaderAttrib m_coord, m_color; + ShaderUniform m_mvp; + VertexDeclaration *m_vdecl; + VertexBuffer *m_vbo; + IndexBuffer *m_lines_ibo, *m_faces_ibo; + + Text *m_text; + bool m_ready; +}; + +int main(int argc, char **argv) +{ + System::Init(argc, argv); + + Application app("Tutorial 7: Input", ivec2(640, 480), 60.0f); + + new DebugFps(5, 5); + new Cube(); + + controller = new Controller(KEY_MAX, AXIS_MAX); + controller->GetKey(KEY_MANUAL_ROTATION).Bind("Keyboard", "Space"); + controller->GetKey(KEY_DRAG_MESH).Bind("Mouse", "ButtonLeft"); + controller->GetAxis(AXIS_DRAG_PITCH).Bind("Mouse", "Y"); + controller->GetAxis(AXIS_DRAG_YAW).Bind("Mouse", "X"); + controller->GetAxis(AXIS_PITCH).Bind("Joystick1", "Axis2"); + controller->GetAxis(AXIS_YAW).Bind("Joystick1", "Axis1"); + + app.Run(); + + return EXIT_SUCCESS; +} + diff --git a/demos/tutorial/07_input.lolfx b/demos/tutorial/07_input.lolfx new file mode 100644 index 00000000..8e1ae04f --- /dev/null +++ b/demos/tutorial/07_input.lolfx @@ -0,0 +1,50 @@ +[vert.glsl] + +#version 120 + +attribute vec3 in_Vertex; +attribute vec3 in_Color; +uniform mat4 in_Matrix; +varying vec3 pass_Color; + +void main(void) +{ + gl_Position = in_Matrix * vec4(in_Vertex, 1.0); + pass_Color = in_Color; +} + +[frag.glsl] + +#version 120 + +#if defined GL_ES +precision highp float; +#endif + +varying vec3 pass_Color; + +void main(void) +{ + gl_FragColor = vec4(pass_Color, 1.0); +} + +[vert.hlsl] + +void main(float3 in_Vertex : POSITION, + float3 in_Color : COLOR, + uniform float4x4 in_Matrix, + out float4 out_Position : POSITION, + out float3 pass_Color : COLOR) +{ + pass_Color = in_Color; + out_Position = mul(in_Matrix, float4(in_Vertex, 1.0)); +} + +[frag.hlsl] + +void main(float3 pass_Color : COLOR, + out float4 out_FragColor : COLOR) +{ + out_FragColor = float4(pass_Color, 1.0); +} + diff --git a/demos/tutorial/07_input.vcxproj b/demos/tutorial/07_input.vcxproj new file mode 100644 index 00000000..5da93262 --- /dev/null +++ b/demos/tutorial/07_input.vcxproj @@ -0,0 +1,82 @@ + + + + + Debug + ORBIS + + + Debug + PS3 + + + Debug + Win32 + + + Debug + x64 + + + Debug + Xbox 360 + + + Release + ORBIS + + + Release + PS3 + + + Release + Win32 + + + Release + x64 + + + Release + Xbox 360 + + + + + + + + + + + {9e62f2fe-3408-4eae-8238-fd84238ceeda} + + + {83d3b207-c601-4025-8f41-01dedc354661} + + + {d84021ca-b233-4e0f-8a52-071b83bbccc4} + + + + {572E5B9C-7E19-489C-BD8A-E8401CFBBC47} + Application + Win32Proj + + + + + + + + + + + + + + + + + diff --git a/demos/tutorial/11_fractal.cpp b/demos/tutorial/11_fractal.cpp index 0380e39b..e40b7272 100644 --- a/demos/tutorial/11_fractal.cpp +++ b/demos/tutorial/11_fractal.cpp @@ -120,7 +120,7 @@ public: m_position = ivec3(0, 0, 0); m_bbox[0] = m_position; m_bbox[1] = ivec3(m_window_size, 0); - Input::TrackMouse(this); + //Input::TrackMouse(this); #if LOL_FEATURE_THREADS /* Spawn worker threads and wait for their readiness. */ @@ -142,7 +142,7 @@ public: m_donequeue.Pop(); #endif - Input::UntrackMouse(this); + //Input::UntrackMouse(this); #if !defined __native_client__ Ticker::Unref(m_centertext); Ticker::Unref(m_mousetext); @@ -175,7 +175,8 @@ public: rcmplx worldmouse = m_center + rcmplx(ScreenToWorldOffset(m_mousepos)); - uint32_t buttons = Input::GetMouseButtons(); + uint32_t buttons = 0; + //uint32_t buttons = Input::GetMouseButtons(); #if !defined __CELLOS_LV2__ && !defined _XBOX if (buttons & 0x2) { diff --git a/demos/tutorial/Makefile.am b/demos/tutorial/Makefile.am index dfb0a477..b4b206e6 100644 --- a/demos/tutorial/Makefile.am +++ b/demos/tutorial/Makefile.am @@ -33,6 +33,10 @@ if USE_EMSCRIPTEN 06_sprite_LDFLAGS += --preload-file 06_sprite.png endif +07_input_SOURCES = 07_input.cpp 07_input.lolfx +07_input_CPPFLAGS = $(AM_CPPFLAGS) +07_input_DEPENDENCIES = @LOL_DEPS@ + 08_fbo_SOURCES = 08_fbo.cpp 08_fbo.lolfx 08_fbo_CPPFLAGS = $(AM_CPPFLAGS) 08_fbo_DEPENDENCIES = @LOL_DEPS@ diff --git a/src/core.h b/src/core.h index 8c514d6a..af3f158c 100644 --- a/src/core.h +++ b/src/core.h @@ -129,6 +129,11 @@ static inline int isnan(float f) #include "input/stick.h" #include "profiler.h" +// Input (v2) +#include "input/input.h" +#include "input/inputdevice.h" +#include "input/controller.h" + // Entities #include "entity.h" #include "worldentity.h" diff --git a/src/input/controller.cpp b/src/input/controller.cpp new file mode 100644 index 00000000..abf91d26 --- /dev/null +++ b/src/input/controller.cpp @@ -0,0 +1,147 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2013 Benjamin Litzelmann +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#ifdef LOL_INPUT_V2 + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" + +namespace lol +{ + +/////////////////////////////////////////////////////////////////////////////// +// KeyBinding + +void KeyBinding::Bind(const char* device_name, const char* key_name) +{ + m_device = InputDevice::Get(device_name); + if (!m_device) + { + Log::Warn("Trying to bind controller to device %s which doesn't exist", device_name); + return; + } + + m_keyindex = m_device->GetKeyIndex(key_name); + + if (m_keyindex < 0) + { + Log::Warn("Trying to bind controller to key %s.%s which doesn't exist", device_name, key_name); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// AxisBinding + +void AxisBinding::Bind(const char* device_name, const char* axis_name) +{ + m_device = InputDevice::Get(device_name); + if (!m_device) + { + Log::Warn("Trying to bind controller to device %s which doesn't exist", device_name); + return; + } + + m_axisindex = m_device->GetAxisIndex(axis_name); + + if (m_axisindex < 0) + { + Log::Warn("Trying to bind controller to axis %s.%s which doesn't exist", device_name, axis_name); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// Controller + +Array Controller::controllers; + +Controller::Controller(int nb_keys, int nb_axis) +{ + m_gamegroup = GAMEGROUP_BEFORE; + m_nb_keys = nb_keys; + m_nb_axis = nb_axis; + m_keys = new KeyBinding[m_nb_keys]; + m_axis = new AxisBinding[m_nb_axis]; + m_activate_nextframe = false; + m_deactivate_nextframe = false; + m_active = false; + controllers.Push(this); +} + +Controller::~Controller() +{ + for (int i = 0; i < controllers.Count(); ++i) + { + if (controllers[i] == this) + { + controllers.Remove(i); + break; + } + } +} + +void Controller::TickGame(float seconds) +{ + Entity::TickGame(seconds); + + for (int i = 0; i < m_nb_keys; ++i) + { + m_keys[i].Update(); + } + + for (int i = 0; i < m_nb_axis; ++i) + { + m_axis[i].Update(); + } + + if (m_activate_nextframe) + m_active = true; + + if (m_deactivate_nextframe) + m_active = false; + + m_activate_nextframe = false; + m_deactivate_nextframe = false; +} + +void Controller::Activate() +{ + m_activate_nextframe = true; + m_deactivate_nextframe = false; +} + +void Controller::Deactivate() +{ + m_deactivate_nextframe = true; + m_activate_nextframe = false; +} + +Array Controller::DeactivateAll() +{ + Array result; + + for (int i = 0; i < controllers.Count(); ++i) + { + if (controllers[i]->m_active || controllers[i]->m_activate_nextframe) + { + result.Push(controllers[i]); + controllers[i]->Deactivate(); + } + } + + return result; +} + +} /* namespace lol */ + +#endif // LOL_INPUT_V2 diff --git a/src/input/controller.h b/src/input/controller.h new file mode 100644 index 00000000..71cfe703 --- /dev/null +++ b/src/input/controller.h @@ -0,0 +1,102 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2013 Benjamin Litzelmann +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#if !defined __LOL_INPUT_CONTROLLER_H__ +#define __LOL_INPUT_CONTROLLER_H__ + +#if defined LOL_INPUT_V2 + +#include "core.h" + +namespace lol +{ + +class KeyBinding +{ +public: + KeyBinding() : m_current(false), m_previous(false), m_device(nullptr) {} + + bool IsDown() const { return m_current; } + bool IsUp() const { return !m_current; } + bool IsPressed() const { return m_current && !m_previous; } + bool IsReleased() const { return !m_current && m_previous; } + + void Bind(const char* device_name, const char* key_name); + +protected: + void Update() { m_previous = m_current; m_current = m_device ? m_device->GetKey(m_keyindex) : false; } + + const InputDevice* m_device; + int m_keyindex; + bool m_current; + bool m_previous; + + friend class Controller; +}; + +class AxisBinding +{ +public: + AxisBinding() : m_current(0.0f), m_previous(0.0f), m_device(nullptr) {} + + float GetValue() const { return m_current; } + float GetDelta() const { return m_current - m_previous; } + + void Bind(const char* device_name, const char* axis_name); + +protected: + void Update() { m_previous = m_current; m_current = m_device ? m_device->GetAxis(m_axisindex) : 0.0f; } + + const InputDevice* m_device; + int m_axisindex; + float m_current; + float m_previous; + + friend class Controller; +}; + + +class Controller : Entity +{ +public: + Controller(int nb_keys, int nb_axis); + ~Controller(); + + virtual void TickGame(float seconds); + + /** Activate the controller on next frame */ + void Activate(); + /** Deactivate the controller on next frame */ + void Deactivate(); + /** Deactivate every active controller on next frame and return an array of deactivated (previously active) controllers */ + static Array DeactivateAll(); + + KeyBinding& GetKey(int index) { ASSERT(index >= 0 && index < m_nb_keys); return m_keys[index]; } + AxisBinding& GetAxis(int index) { ASSERT(index >= 0 && index < m_nb_axis); return m_axis[index]; } + +protected: + KeyBinding* m_keys; + AxisBinding* m_axis; + int m_nb_keys; + int m_nb_axis; + +private: + static Array controllers; + bool m_activate_nextframe; + bool m_deactivate_nextframe; + bool m_active; +}; + +} /* namespace lol */ + +#endif // LOL_INPUT_V2 + +#endif // __LOL_INPUT_CONTROLLER_H__ + diff --git a/src/input/input.cpp b/src/input/input.cpp index a319e645..4dbeb228 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -8,6 +8,8 @@ // http://www.wtfpl.net/ for more details. // +#ifndef LOL_INPUT_V2 + #if defined HAVE_CONFIG_H # include "config.h" #endif @@ -478,3 +480,4 @@ void Input::UntrackStick(Stick *stick) } /* namespace lol */ +#endif // !LOL_INPUT_V2 diff --git a/src/input/input.h b/src/input/input.h index bd7f5b47..5eb3b3d2 100644 --- a/src/input/input.h +++ b/src/input/input.h @@ -16,6 +16,8 @@ #if !defined __LOL_INPUT_INPUT_H__ #define __LOL_INPUT_INPUT_H__ +#ifndef LOL_INPUT_V2 + #include #include @@ -456,5 +458,7 @@ public: } /* namespace lol */ +#endif // !LOL_INPUT_V2 + #endif // __LOL_INPUT_INPUT_H__ diff --git a/src/input/inputdevice.cpp b/src/input/inputdevice.cpp new file mode 100644 index 00000000..7ff3e4cc --- /dev/null +++ b/src/input/inputdevice.cpp @@ -0,0 +1,72 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2013 Benjamin Litzelmann +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#ifdef LOL_INPUT_V2 + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" + +#include "input/inputdevice_internal.h" + +namespace lol +{ + +Array InputDevice::devices; +bool InputDevice::m_capturemouse; + +void InputDeviceInternal::AddKey(const char* name) +{ + m_keynames.Push(name); + m_keys.Push(false); +} + +void InputDeviceInternal::AddAxis(const char* name, float sensitivity) +{ + m_axisnames.Push(name); + m_axis.Push(0.0f, sensitivity); +} + +void InputDeviceInternal::AddCursor(const char* name) +{ + m_cursornames.Push(name); + m_cursors.Push(vec2(0.0), ivec2(0)); +} + +InputDeviceInternal* InputDeviceInternal::CreateStandardKeyboard() +{ + InputDeviceInternal* keyboard = new InputDeviceInternal("Keyboard"); +# define KEY_FUNC(key, value) keyboard->AddKey(#key); +# include "input/keys.h" +# undef KEY_FUNC + return keyboard; +} + +InputDeviceInternal* InputDeviceInternal::CreateStandardMouse() +{ + InputDeviceInternal* mouse = new InputDeviceInternal("Mouse"); + mouse->AddKey("ButtonLeft"); + mouse->AddKey("ButtonMiddle"); + mouse->AddKey("ButtonRight"); + + mouse->AddAxis("X"); + mouse->AddAxis("Y"); + + mouse->AddCursor("Cursor"); + + // TODO: extended button, and wheel (as axis or as buttons? or both?) + return mouse; +} + +} /* namespace lol */ + +#endif // LOL_INPUT_V2 diff --git a/src/input/inputdevice.h b/src/input/inputdevice.h new file mode 100644 index 00000000..f382ef65 --- /dev/null +++ b/src/input/inputdevice.h @@ -0,0 +1,126 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2013 Benjamin Litzelmann +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#if !defined __LOL_INPUT_DEVICE_H__ +#define __LOL_INPUT_DEVICE_H__ + +#if defined LOL_INPUT_V2 + +#include "core.h" + +namespace lol +{ + +class InputDevice +{ +public: + /** Get the name of this input device */ + const String& GetName(); + + /** Get the index of the corresponding key, needed to call GetKey */ + int GetKeyIndex(const char* name) const { return GetItemIndex(name, m_keynames); } + /** Get the index of the corresponding axis, needed to call GetAxis */ + int GetAxisIndex(const char* name) const { return GetItemIndex(name, m_axisnames); } + /** Get the index of the corresponding cursor, needed to call GetCursor */ + int GetCursorIndex(const char* name) const { return GetItemIndex(name, m_cursornames); } + + /** Get the current state of the given key, true being pressed and false being released */ + bool GetKey(int index) const { return m_keys[index]; } + /** Get the current value of the given axis. Devices should cap this value between -1 and 1 as much as possible, through it is not guaranteed */ + float GetAxis(int index) const { return m_axis[index].m1 * m_axis[index].m2; } + /** Get the current value of the given cursor, 0,0 being the bottom-left corner and 1,1 being the top-right corner */ + vec2 GetCursor(int index) const { return m_cursors[index].m1; } + /** Get the coordinate of the pixel the cursor is currently over, 0,0 being the bottom-left corner. */ + ivec2 GetCursorPixel(int index) const { return m_cursors[index].m2; } + + + /** Set a per-device-axis sensitivity factor. The value returned by the operating system will be multiplied by this value before being returned by GetAxis */ + void SetAxisSensitivity(int index, float sensitivity) { m_axis[index].m2 = sensitivity; } + /** Get the per-device-axis sensitivity factor. The value returned by the operating system will be multiplied by this value before being returned by GetAxis */ + float GetAxisSensitivity(int index) const { return m_axis[index].m2; } + + /** Get a list of the name of all available keys in this device */ + const Array& GetAllKeys() const { return m_keynames; } + /** Get a list of the name of all available axis in this device */ + const Array& GetAllAxis() const { return m_axisnames; } + /** Get a list of the name of all available cursors in this device */ + const Array& GetAllCursors() const { return m_cursornames; } + + /** Get an input device by its name */ + static InputDevice* Get(const char* name) { return GetDevice(name); } + /** Set whether the mouse cursor should be captured. */ + static void CaptureMouse(bool activated) { m_capturemouse = activated; } + +protected: + // TODO: hide all of this in a InputDeviceData? + + String m_name; + + Array m_keynames; + Array m_axisnames; + Array m_cursornames; + + /** key states (pressed/released) */ + Array m_keys; + /** axis states (value and sensitivity) */ + Array m_axis; + /** cursor position */ + Array m_cursors; + + static bool m_capturemouse; + + InputDevice(const char* name) : m_name(name) + { + devices.Push(this); + } + + ~InputDevice() + { + for (int i = 0; i < devices.Count(); ++i) + { + if (devices[i] == this) + { + devices.Remove(i); + return; + } + } + } + +private: + static Array devices; + + template + int GetItemIndex(const char* name, const Array& Array) const + { + for (int i = 0; i < Array.Count(); ++i) + { + if (Array[i] == name) + return i; + } + return -1; + } + + static InputDevice* GetDevice(const char* name) + { + for (int i = 0; i < devices.Count(); ++i) + { + if (devices[i]->m_name == name) + return devices[i]; + } + return nullptr; + } +}; + +} /* namespace lol */ + +#endif // LOL_INPUT_V2 + +#endif // __LOL_INPUT_DEVICE_H__ + diff --git a/src/input/inputdevice_internal.h b/src/input/inputdevice_internal.h new file mode 100644 index 00000000..b1b91e3c --- /dev/null +++ b/src/input/inputdevice_internal.h @@ -0,0 +1,46 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2013 Benjamin Litzelmann +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#if !defined __LOL_INPUT_DEVICE_INTERNAL_H__ +#define __LOL_INPUT_DEVICE_H__ + +#if defined LOL_INPUT_V2 + +#include "core.h" + +namespace lol +{ + +/** Internal class (not public) that allows to construct an InputDevice dynamically, when the keys, axis and cursors are not known at compile time */ +class InputDeviceInternal : InputDevice +{ +public: + InputDeviceInternal(const char* name) : InputDevice(name) { } + + void AddKey(const char* name); + void AddAxis(const char* name, float sensitivity = 1.0f); + void AddCursor(const char* name); + + void SetKey(int index, bool state) { m_keys[index] = state; } + void SetAxis(int index, float value) { m_axis[index].m1 = value; } + void SetCursor(int index, const vec2& position, const ivec2& pixel) { m_cursors[index].m1 = position; m_cursors[index].m2 = pixel; } + + static bool GetMouseCapture() { return m_capturemouse; } + + static InputDeviceInternal* CreateStandardKeyboard(); + static InputDeviceInternal* CreateStandardMouse(); +}; + +} /* namespace lol */ + +#endif // LOL_INPUT_V2 + +#endif // __LOL_INPUT_DEVICE_INTERNAL_H__ + diff --git a/src/input/keyboard.cpp b/src/input/keyboard.cpp index 42a6e2b8..b2b384d3 100644 --- a/src/input/keyboard.cpp +++ b/src/input/keyboard.cpp @@ -8,6 +8,8 @@ // http://www.wtfpl.net/ for more details. // +#ifndef LOL_INPUT_V2 + #if defined HAVE_CONFIG_H # include "config.h" #endif @@ -66,3 +68,4 @@ uint32_t Keyboard::PopChar() } /* namespace lol */ +#endif // !LOL_INPUT_V2 diff --git a/src/input/keyboard.h b/src/input/keyboard.h index 31ba0c7f..e9e8358c 100644 --- a/src/input/keyboard.h +++ b/src/input/keyboard.h @@ -16,6 +16,8 @@ #if !defined __LOL_INPUT_KEYBOARD_H__ #define __LOL_INPUT_KEYBOARD_H__ +#ifndef LOL_INPUT_V2 + #include "entity.h" namespace lol @@ -39,5 +41,7 @@ private: } /* namespace lol */ +#endif // !LOL_INPUT_V2 + #endif // __LOL_INPUT_KEYBOARD_H__ diff --git a/src/input/keys.h b/src/input/keys.h new file mode 100644 index 00000000..cc75db42 --- /dev/null +++ b/src/input/keys.h @@ -0,0 +1,266 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2013 Benjamin Litzelmann +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License) Version 2) as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#if defined KEY_FUNC + +/* ASCII mapped keys */ +KEY_FUNC(Unknown, 0) +KEY_FUNC(First, 0) +KEY_FUNC(Backspace, 8) +KEY_FUNC(Tab, (int)'\t') +KEY_FUNC(Clear, 12) +KEY_FUNC(Return, 13) +KEY_FUNC(Pause, 19) +KEY_FUNC(Escape, 27) +KEY_FUNC(Space, (int)' ') +KEY_FUNC(Exclaim, (int)'!') +KEY_FUNC(DoubleQuote, (int)'"') +KEY_FUNC(Hash, (int)'#') +KEY_FUNC(Dollar, (int)'$') +KEY_FUNC(Ampersand, (int)'&') +KEY_FUNC(Quote, (int)'\'') +KEY_FUNC(LeftParen, (int)'(') +KEY_FUNC(RightParen, (int)')') +KEY_FUNC(Asterisk, (int)'*') +KEY_FUNC(Plus, (int)'+') +KEY_FUNC(Comma, (int)')') +KEY_FUNC(Minus, (int)'-') +KEY_FUNC(Period, (int)'.') +KEY_FUNC(Slash, (int)'/') +KEY_FUNC(K0, (int)'0') +KEY_FUNC(K1, (int)'1') +KEY_FUNC(K2, (int)'2') +KEY_FUNC(K3, (int)'3') +KEY_FUNC(K4, (int)'4') +KEY_FUNC(K5, (int)'5') +KEY_FUNC(K6, (int)'6') +KEY_FUNC(K7, (int)'7') +KEY_FUNC(K8, (int)'8') +KEY_FUNC(K9, (int)'9') +KEY_FUNC(Colon, (int)':') +KEY_FUNC(Semicolon, (int)';') +KEY_FUNC(Less, (int)'<') +KEY_FUNC(Equals, (int)'=') +KEY_FUNC(Greater, (int)'>') +KEY_FUNC(Question, (int)'?') +KEY_FUNC(At, (int)'@') +/* XXX: SDL decides to skip uppercase characters */ +KEY_FUNC(LeftBracket, (int)'[') +KEY_FUNC(BackSlash, (int)'\\') +KEY_FUNC(RightBracket, (int)']') +KEY_FUNC(Caret, (int)'^') +KEY_FUNC(Underscore, (int)'_') +KEY_FUNC(Backquote, (int)'`') +KEY_FUNC(A, (int)'a') +KEY_FUNC(B, (int)'b') +KEY_FUNC(C, (int)'c') +KEY_FUNC(D, (int)'d') +KEY_FUNC(E, (int)'e') +KEY_FUNC(F, (int)'f') +KEY_FUNC(G, (int)'g') +KEY_FUNC(H, (int)'h') +KEY_FUNC(I, (int)'i') +KEY_FUNC(J, (int)'j') +KEY_FUNC(K, (int)'k') +KEY_FUNC(L, (int)'l') +KEY_FUNC(M, (int)'m') +KEY_FUNC(N, (int)'n') +KEY_FUNC(O, (int)'o') +KEY_FUNC(P, (int)'p') +KEY_FUNC(Q, (int)'q') +KEY_FUNC(R, (int)'r') +KEY_FUNC(S, (int)'s') +KEY_FUNC(T, (int)'t') +KEY_FUNC(U, (int)'u') +KEY_FUNC(V, (int)'v') +KEY_FUNC(W, (int)'w') +KEY_FUNC(X, (int)'x') +KEY_FUNC(Y, (int)'y') +KEY_FUNC(Z, (int)'z') +KEY_FUNC(Delete, 127) + +/* International keyboard syms */ +#ifndef KEY_DISABLE_WORLD +KEY_FUNC(World0, 160) /* 0xA0 */ +KEY_FUNC(World1, 161) +KEY_FUNC(World2, 162) +KEY_FUNC(World3, 163) +KEY_FUNC(World4, 164) +KEY_FUNC(World5, 165) +KEY_FUNC(World6, 166) +KEY_FUNC(World7, 167) +KEY_FUNC(World8, 168) +KEY_FUNC(World9, 169) +KEY_FUNC(World10, 170) +KEY_FUNC(World11, 171) +KEY_FUNC(World12, 172) +KEY_FUNC(World13, 173) +KEY_FUNC(World14, 174) +KEY_FUNC(World15, 175) +KEY_FUNC(World16, 176) +KEY_FUNC(World17, 177) +KEY_FUNC(World18, 178) +KEY_FUNC(World19, 179) +KEY_FUNC(World20, 180) +KEY_FUNC(World21, 181) +KEY_FUNC(World22, 182) +KEY_FUNC(World23, 183) +KEY_FUNC(World24, 184) +KEY_FUNC(World25, 185) +KEY_FUNC(World26, 186) +KEY_FUNC(World27, 187) +KEY_FUNC(World28, 188) +KEY_FUNC(World29, 189) +KEY_FUNC(World30, 190) +KEY_FUNC(World31, 191) +KEY_FUNC(World32, 192) +KEY_FUNC(World33, 193) +KEY_FUNC(World34, 194) +KEY_FUNC(World35, 195) +KEY_FUNC(World36, 196) +KEY_FUNC(World37, 197) +KEY_FUNC(World38, 198) +KEY_FUNC(World39, 199) +KEY_FUNC(World40, 200) +KEY_FUNC(World41, 201) +KEY_FUNC(World42, 202) +KEY_FUNC(World43, 203) +KEY_FUNC(World44, 204) +KEY_FUNC(World45, 205) +KEY_FUNC(World46, 206) +KEY_FUNC(World47, 207) +KEY_FUNC(World48, 208) +KEY_FUNC(World49, 209) +KEY_FUNC(World50, 210) +KEY_FUNC(World51, 211) +KEY_FUNC(World52, 212) +KEY_FUNC(World53, 213) +KEY_FUNC(World54, 214) +KEY_FUNC(World55, 215) +KEY_FUNC(World56, 216) +KEY_FUNC(World57, 217) +KEY_FUNC(World58, 218) +KEY_FUNC(World59, 219) +KEY_FUNC(World60, 220) +KEY_FUNC(World61, 221) +KEY_FUNC(World62, 222) +KEY_FUNC(World63, 223) +KEY_FUNC(World64, 224) +KEY_FUNC(World65, 225) +KEY_FUNC(World66, 226) +KEY_FUNC(World67, 227) +KEY_FUNC(World68, 228) +KEY_FUNC(World69, 229) +KEY_FUNC(World70, 230) +KEY_FUNC(World71, 231) +KEY_FUNC(World72, 232) +KEY_FUNC(World73, 233) +KEY_FUNC(World74, 234) +KEY_FUNC(World75, 235) +KEY_FUNC(World76, 236) +KEY_FUNC(World77, 237) +KEY_FUNC(World78, 238) +KEY_FUNC(World79, 239) +KEY_FUNC(World80, 240) +KEY_FUNC(World81, 241) +KEY_FUNC(World82, 242) +KEY_FUNC(World83, 243) +KEY_FUNC(World84, 244) +KEY_FUNC(World85, 245) +KEY_FUNC(World86, 246) +KEY_FUNC(World87, 247) +KEY_FUNC(World88, 248) +KEY_FUNC(World89, 249) +KEY_FUNC(World90, 250) +KEY_FUNC(World91, 251) +KEY_FUNC(World92, 252) +KEY_FUNC(World93, 253) +KEY_FUNC(World94, 254) +KEY_FUNC(World95, 255) /* 0xFF */ +#endif // !KEY_DISABLE_WORLD + +/* Numeric keypad */ +KEY_FUNC(KP0, 256) +KEY_FUNC(KP1, 257) +KEY_FUNC(KP2, 258) +KEY_FUNC(KP3, 259) +KEY_FUNC(KP4, 260) +KEY_FUNC(KP5, 261) +KEY_FUNC(KP6, 262) +KEY_FUNC(KP7, 263) +KEY_FUNC(KP8, 264) +KEY_FUNC(KP9, 265) +KEY_FUNC(KPPeriod, 266) +KEY_FUNC(KPDivide, 267) +KEY_FUNC(KPMultiply, 268) +KEY_FUNC(KPMinus, 269) +KEY_FUNC(KPPlus, 270) +KEY_FUNC(KPEnter, 271) +KEY_FUNC(KPEquals, 272) + +/* Arrows + Home/End pad */ +KEY_FUNC(Up, 273) +KEY_FUNC(Down, 274) +KEY_FUNC(Right, 275) +KEY_FUNC(Left, 276) +KEY_FUNC(Insert, 277) +KEY_FUNC(Home, 278) +KEY_FUNC(End, 279) +KEY_FUNC(PageUp, 280) +KEY_FUNC(PageDown, 281) + +/* Function keys */ +KEY_FUNC(F1, 282) +KEY_FUNC(F2, 283) +KEY_FUNC(F3, 284) +KEY_FUNC(F4, 285) +KEY_FUNC(F5, 286) +KEY_FUNC(F6, 287) +KEY_FUNC(F7, 288) +KEY_FUNC(F8, 289) +KEY_FUNC(F9, 290) +KEY_FUNC(F10, 291) +KEY_FUNC(F11, 292) +KEY_FUNC(F12, 293) +KEY_FUNC(F13, 294) +KEY_FUNC(F14, 295) +KEY_FUNC(F15, 296) + +/* Modifier keys */ +KEY_FUNC(NumLock, 300) +KEY_FUNC(CapsLock, 301) +KEY_FUNC(ScrollLock, 302) +KEY_FUNC(RightShift, 303) +KEY_FUNC(LeftShift, 304) +KEY_FUNC(RightCtrl, 305) +KEY_FUNC(LeftCtrl, 306) +KEY_FUNC(RightAlt, 307) +KEY_FUNC(LeftAlt, 308) +KEY_FUNC(RightMeta, 309) +KEY_FUNC(LeftMeta, 310) +KEY_FUNC(LeftSuper, 311) /* Left "Windows" key */ +KEY_FUNC(RightSuper, 312) /* Right "Windows" key */ +KEY_FUNC(Mode, 313) /* "Alt Gr" key */ +KEY_FUNC(Compose, 314) /* Multi-key compose key */ + +/* Miscellaneous function keys */ +KEY_FUNC(Help, 315) +KEY_FUNC(Print, 316) +KEY_FUNC(SysReq, 317) +KEY_FUNC(Break, 318) +KEY_FUNC(Menu, 319) +KEY_FUNC(Power, 320) /* Power Macintosh power key */ +KEY_FUNC(Euro, 321) /* Some european keyboards */ +KEY_FUNC(Undo, 322) /* Atari keyboard has Undo */ + +/* Add any other keys here, but ensure Last value matches the last + 1 */ +KEY_FUNC(Last, 323) + +#endif // KEY_FUNC diff --git a/src/input/stick.cpp b/src/input/stick.cpp index 65140acf..05fee2d4 100644 --- a/src/input/stick.cpp +++ b/src/input/stick.cpp @@ -8,6 +8,8 @@ // http://www.wtfpl.net/ for more details. // +#ifndef LOL_INPUT_V2 + #if defined HAVE_CONFIG_H # include "config.h" #endif @@ -107,3 +109,4 @@ int Stick::GetButton(int n) } /* namespace lol */ +#endif // !LOL_INPUT_V2 diff --git a/src/input/stick.h b/src/input/stick.h index c3f95787..da5c64a4 100644 --- a/src/input/stick.h +++ b/src/input/stick.h @@ -16,6 +16,8 @@ #if !defined __LOL_INPUT_STICK_H__ #define __LOL_INPUT_STICK_H__ +#ifndef LOL_INPUT_V2 + #include "entity.h" namespace lol @@ -48,5 +50,7 @@ private: } /* namespace lol */ +#endif // !LOL_INPUT_V2 + #endif // __LOL_INPUT_STICK_H__ diff --git a/src/lolcore.vcxproj b/src/lolcore.vcxproj index 16300ed1..cec031dc 100644 --- a/src/lolcore.vcxproj +++ b/src/lolcore.vcxproj @@ -144,7 +144,9 @@ + + @@ -205,8 +207,12 @@ + + + + diff --git a/src/lolcore.vcxproj.filters b/src/lolcore.vcxproj.filters index 565d851f..811ab416 100644 --- a/src/lolcore.vcxproj.filters +++ b/src/lolcore.vcxproj.filters @@ -312,6 +312,12 @@ debug + + input + + + input + @@ -608,6 +614,18 @@ lol\image + + input + + + input + + + input + + + input + diff --git a/src/platform/d3d9/d3d9input.cpp b/src/platform/d3d9/d3d9input.cpp index a9809278..23d99dcc 100644 --- a/src/platform/d3d9/d3d9input.cpp +++ b/src/platform/d3d9/d3d9input.cpp @@ -20,6 +20,10 @@ #include "core.h" #include "d3d9input.h" +#ifdef LOL_INPUT_V2 +#include "input/inputdevice_internal.h" +#endif // LOL_INPUT_V2 + namespace lol { @@ -33,8 +37,12 @@ class D3d9InputData private: #if defined USE_XINPUT +#if defined LOL_INPUT_V2 + Array m_joysticks; +#else Array m_joysticks; -#endif +#endif // LOL_INPUT_V2 +#endif // USE_XINPUT }; /* @@ -50,11 +58,21 @@ D3d9Input::D3d9Input() XINPUT_STATE state; if (XInputGetState(i, &state) != ERROR_SUCCESS) continue; - +#if defined LOL_INPUT_V2 + // TODO: we can put more friendly name here, such as LeftAxisX, ButtonX... + InputDeviceInternal* stick = new InputDeviceInternal(String::Printf("Joystick%d", i+1).C()); + for (int j = 0; j < 4; ++j) + stick->AddAxis(String::Printf("Axis%d", j+1).C()); + for (int j = 0; j < 16; ++j) + stick->AddKey(String::Printf("Button%d", j+1).C()); + + m_data->m_joysticks.Push(i, stick); +#else Stick *stick = Input::CreateStick(); stick->SetAxisCount(4); stick->SetButtonCount(16); m_data->m_joysticks.Push(i, stick); +#endif // LOL_INPUT_V2 } #endif @@ -67,8 +85,12 @@ D3d9Input::~D3d9Input() /* Unregister all the joysticks we added */ while (m_data->m_joysticks.Count()) { - Input::DestroyStick(m_data->m_joysticks[0].m2); - m_data->m_joysticks.Remove(0); +#if defined LOL_INPUT_V2 + delete m_data->m_joysticks[0].m2; +#else + Input::DestroyStick(m_data->m_joysticks[0].m2); +#endif // LOL_INPUT_V2 + m_data->m_joysticks.Remove(0); } #endif delete m_data; @@ -96,8 +118,12 @@ void D3d9Input::TickDraw(float seconds) m_data->m_joysticks[i].m2->SetAxis(3, -(float)state.Gamepad.sThumbRY / 32768.f); for (int b = 0; b < 16; b++) - m_data->m_joysticks[i].m2->SetButton(b, ((uint16_t)(state.Gamepad.wButtons) >> b) & 1); - } +#if defined LOL_INPUT_V2 + m_data->m_joysticks[i].m2->SetKey(b, ((uint16_t)(state.Gamepad.wButtons) >> b) & 1); +#else + m_data->m_joysticks[i].m2->SetButton(b, ((uint16_t)(state.Gamepad.wButtons) >> b) & 1); +#endif // LOL_INPUT_V2 + } #endif } diff --git a/src/platform/sdl/sdlapp.cpp b/src/platform/sdl/sdlapp.cpp index 57289083..bbd93a00 100644 --- a/src/platform/sdl/sdlapp.cpp +++ b/src/platform/sdl/sdlapp.cpp @@ -66,6 +66,12 @@ SdlApp::SdlApp(char const *title, ivec2 res, float fps) : exit(EXIT_FAILURE); } +# ifdef LOL_INPUT_V2 + const SDL_VideoInfo* vidinfo = SDL_GetVideoInfo(); + int screen_w = vidinfo->current_w; + int screen_h = vidinfo->current_h; +# endif + # if defined USE_D3D9 SDL_Surface *video = SDL_SetVideoMode(res.x, res.y, 16, 0); SDL_SysWMinfo wminfo; @@ -77,6 +83,9 @@ SdlApp::SdlApp(char const *title, ivec2 res, float fps) : # else SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); +# ifdef LOL_INPUT_V2 + // TODO: when implementing fullscreen, be sure to overwrite screen_w and screen_h with the value of vidinfo after the call to SDL_SetVideoMode +# endif SDL_Surface *video = SDL_SetVideoMode(res.x, res.y, 0, SDL_OPENGL); # endif if (!video) @@ -100,7 +109,11 @@ SdlApp::SdlApp(char const *title, ivec2 res, float fps) : new D3d9Input(); # endif - new SdlInput(); +# ifdef LOL_INPUT_V2 + new SdlInput(video->w, video->h, screen_w, screen_h); +# else + new SdlInput(); +# endif #endif } diff --git a/src/platform/sdl/sdlinput.cpp b/src/platform/sdl/sdlinput.cpp index 5022c1a0..54378ebd 100644 --- a/src/platform/sdl/sdlinput.cpp +++ b/src/platform/sdl/sdlinput.cpp @@ -23,6 +23,10 @@ #include "core.h" #include "sdlinput.h" +#ifdef LOL_INPUT_V2 +#include "input/inputdevice_internal.h" +#endif // LOL_INPUT_V2 + /* We force joystick polling because no events are received when * there is no SDL display (eg. on the Raspberry Pi). */ #define SDL_FORCE_POLL_JOYSTICK 1 @@ -42,17 +46,44 @@ private: void Tick(float seconds); static ivec2 GetMousePos(); + static void SetMousePos(ivec2 position); + #if USE_SDL +# ifdef LOL_INPUT_V2 + SdlInputData(int app_w, int app_h, int screen_w, int screen_h) : + m_prevmouse(ivec2(0)), + m_app_w((float)app_w), + m_app_h((float)app_h), + m_screen_w((float)screen_w), + m_screen_h((float)screen_h) + { } + + Array m_joysticks; + InputDeviceInternal* m_mouse; + InputDeviceInternal* m_keyboard; + ivec2 m_prevmouse; + float m_app_w; + float m_app_h; + float m_screen_w; + float m_screen_h; + bool m_mousecapture; +# else Array m_joysticks; -#endif +# endif // LOL_INPUT_V2 +#endif // USE_SDL }; /* * Public SdlInput class */ +#ifdef LOL_INPUT_V2 +SdlInput::SdlInput(int app_w, int app_h, int screen_w, int screen_h) + : m_data(new SdlInputData(app_w, app_h, screen_w, screen_h)) +#else SdlInput::SdlInput() : m_data(new SdlInputData()) +#endif { #if USE_SDL /* Enable Unicode translation of keyboard events */ @@ -67,6 +98,11 @@ SdlInput::SdlInput() SDL_JoystickEventState(SDL_ENABLE); # endif +#ifdef LOL_INPUT_V2 + m_data->m_keyboard = InputDeviceInternal::CreateStandardKeyboard(); + m_data->m_mouse = InputDeviceInternal::CreateStandardMouse(); +#endif + /* Register all the joysticks we can find, and let the input * system decide what it wants to track. */ for (int i = 0; i < SDL_NumJoysticks(); i++) @@ -88,6 +124,15 @@ SdlInput::SdlInput() continue; } +# ifdef LOL_INPUT_V2 + InputDeviceInternal* stick = new InputDeviceInternal(String::Printf("Joystick%d", i+1).C()); + for (int i = 0; i < SDL_JoystickNumAxes(sdlstick); ++i) + stick->AddAxis(String::Printf("Axis%d", i+1).C()); + for (int i = 0; i < SDL_JoystickNumButtons(sdlstick); ++i) + stick->AddKey(String::Printf("Button%d", i+1).C()); + + m_data->m_joysticks.Push(sdlstick, stick); +# else // !LOL_INPUT_V2 Stick *stick = Input::CreateStick(); stick->SetAxisCount(SDL_JoystickNumAxes(sdlstick)); stick->SetButtonCount(SDL_JoystickNumButtons(sdlstick)); @@ -97,6 +142,7 @@ SdlInput::SdlInput() //stick->RemapAxis(2, 4); m_data->m_joysticks.Push(sdlstick, stick); +# endif } # endif #endif @@ -111,7 +157,11 @@ SdlInput::~SdlInput() while (m_data->m_joysticks.Count()) { SDL_JoystickClose(m_data->m_joysticks[0].m1); +# ifdef LOL_INPUT_V2 + delete m_data->m_joysticks[0].m2; +# else Input::DestroyStick(m_data->m_joysticks[0].m2); +# endif m_data->m_joysticks.Remove(0); } #endif @@ -139,19 +189,23 @@ void SdlInput::TickDraw(float seconds) void SdlInputData::Tick(float seconds) { #if USE_SDL - /* Handle mouse input */ - ivec2 mouse = SdlInputData::GetMousePos();; - Input::SetMousePos(mouse); - /* Pump all joystick events because no event is coming to us. */ # if SDL_FORCE_POLL_JOYSTICK && !EMSCRIPTEN SDL_JoystickUpdate(); for (int j = 0; j < m_joysticks.Count(); j++) { +# ifdef LOL_INPUT_V2 + for (int i = 0; i < SDL_JoystickNumButtons(m_joysticks[j].m1); i++) + m_joysticks[j].m2->SetKey(i, SDL_JoystickGetButton(m_joysticks[j].m1, i) != 0); + for (int i = 0; i < SDL_JoystickNumAxes(m_joysticks[j].m1); i++) + m_joysticks[j].m2->SetAxis(i, (float)SDL_JoystickGetAxis(m_joysticks[j].m1, i) / 32768.f); +# else // !LOL_INPUT_V2 for (int i = 0; i < SDL_JoystickNumButtons(m_joysticks[j].m1); i++) m_joysticks[j].m2->SetButton(i, SDL_JoystickGetButton(m_joysticks[j].m1, i)); for (int i = 0; i < SDL_JoystickNumAxes(m_joysticks[j].m1); i++) m_joysticks[j].m2->SetAxis(i, (float)SDL_JoystickGetAxis(m_joysticks[j].m1, i) / 32768.f); + +# endif } # endif @@ -173,17 +227,28 @@ void SdlInputData::Tick(float seconds) case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: { - ivec2 newmouse = SdlInputData::GetMousePos(); - if (newmouse != mouse) - Input::SetMousePos(mouse = newmouse); +#ifdef LOL_INPUT_V2 + m_mouse->SetKey(event.button.button - 1, event.type == SDL_MOUSEBUTTONDOWN); +#else // !LOL_INPUT_V2 if (event.type == SDL_MOUSEBUTTONDOWN) Input::SetMouseButton(event.button.button - 1); else Input::UnsetMouseButton(event.button.button - 1); +#endif // LOL_INPUT_V2 break; } # if !SDL_FORCE_POLL_JOYSTICK +# ifdef LOL_INPUT_V2 + case SDL_JOYAXISMOTION: + m_joysticks[event.jaxis.which].m2->SetAxis(event.jaxis.axis, (float)event.jaxis.value / 32768.f); + break; + + case SDL_JOYBUTTONUP: + case SDL_JOYBUTTONDOWN: + m_joysticks[event.jbutton.which].m2->SetKey(event.jbutton.button, event.jbutton.state); + break; +# else // !LOL_INPUT_V2 case SDL_JOYAXISMOTION: m_joysticks[event.jaxis.which].m2->SetAxis(event.jaxis.axis, (float)event.jaxis.value / 32768.f); break; @@ -192,12 +257,40 @@ void SdlInputData::Tick(float seconds) case SDL_JOYBUTTONDOWN: m_joysticks[event.jbutton.which].m2->SetButton(event.jbutton.button, event.jbutton.state); break; +# endif // LOL_INPUT_V2 # endif } } - /* Send the whole keyboard state to the input system */ - Array &lolstate = Input::GetKeyboardState(); + /* Handle mouse input */ + ivec2 mouse = SdlInputData::GetMousePos(); +# ifdef LOL_INPUT_V2 + if (InputDeviceInternal::GetMouseCapture() != m_mousecapture) + { + m_mousecapture = InputDeviceInternal::GetMouseCapture(); + SDL_WM_GrabInput(m_mousecapture ? SDL_GRAB_ON : SDL_GRAB_OFF); + //SDL_ShowCursor(m_mousecapture ? SDL_DISABLE : SDL_ENABLE); + } + + if (mouse.x >= 0 && mouse.x < m_app_w && mouse.y >= 0 && mouse.y < m_app_h) + { + m_mouse->SetCursor(0, vec2((float)(mouse.x) / m_app_w, (float)(mouse.y) / m_app_h), mouse); + // Note: 100.0f is an arbitrary value that makes it feel about the same than an xbox controller joystick + m_mouse->SetAxis(0, (float)(mouse.x - m_prevmouse.x) * 100.0f / m_screen_w); + m_mouse->SetAxis(1, (float)(mouse.y - m_prevmouse.y) * 100.0f / m_screen_h); + } + + if (m_mousecapture) + { + mouse = ivec2((int)m_app_w / 2, (int)m_app_h / 2); + SdlInputData::SetMousePos(mouse); + } + + m_prevmouse = mouse; + +# else // !LOL_INPUT_V2 + Input::SetMousePos(mouse); +# endif // LOL_INPUT_V2 # if SDL_VERSION_ATLEAST(1,3,0) Uint8 *sdlstate = SDL_GetKeyboardState(nullptr); @@ -205,6 +298,19 @@ void SdlInputData::Tick(float seconds) Uint8 *sdlstate = SDL_GetKeyState(nullptr); # endif + int keyindex = 0; +# ifdef LOL_INPUT_V2 +# define KEY_FUNC(name, index) m_keyboard->SetKey(keyindex++, sdlstate[index] != 0); +# if !defined SDLK_WORLD_0 +# define KEY_DISABLE_WORLD +# endif // !SDLK_WORLD_0 +# include "input/keys.h" +# undef KEY_FUNC +# else // !LOL_INPUT_V2 + + /* Send the whole keyboard state to the input system */ + Array &lolstate = Input::GetKeyboardState(); + lolstate[Key::Unknown] = sdlstate[SDLK_UNKNOWN]; lolstate[Key::Backspace] = sdlstate[SDLK_BACKSPACE]; lolstate[Key::Tab] = sdlstate[SDLK_TAB]; @@ -376,7 +482,7 @@ void SdlInputData::Tick(float seconds) lolstate[Key::World93] = sdlstate[SDLK_WORLD_93]; lolstate[Key::World94] = sdlstate[SDLK_WORLD_94]; lolstate[Key::World95] = sdlstate[SDLK_WORLD_95]; -#endif +#endif // SDLK_WORLD_0 lolstate[Key::KP0] = sdlstate[SDLK_KP0]; lolstate[Key::KP1] = sdlstate[SDLK_KP1]; @@ -448,7 +554,9 @@ void SdlInputData::Tick(float seconds) lolstate[Key::Undo] = sdlstate[SDLK_UNDO]; UNUSED(seconds); -#endif +# endif // LOL_INPUT_V2 + +#endif // USE_SDL } ivec2 SdlInputData::GetMousePos() @@ -467,5 +575,10 @@ ivec2 SdlInputData::GetMousePos() return ret; } +void SdlInputData::SetMousePos(ivec2 position) +{ + SDL_WarpMouse((uint16_t)position.x, (uint16_t)position.y); +} + } /* namespace lol */ diff --git a/src/platform/sdl/sdlinput.h b/src/platform/sdl/sdlinput.h index 56feb041..50f360db 100644 --- a/src/platform/sdl/sdlinput.h +++ b/src/platform/sdl/sdlinput.h @@ -26,8 +26,14 @@ class SdlInputData; class SdlInput : public Entity { public: +#ifdef LOL_INPUT_V2 + /** passing the screen resolution (note: not the windowed app resolution!) allows to make the mouse axis resolution-independent */ + SdlInput(int app_w, int app_h, int screen_w, int screen_h); +#else SdlInput(); +#endif virtual ~SdlInput(); + void SetScreenResolution(); protected: virtual void TickGame(float seconds);