sdl-game-controller/sdl-game-controller.cc

232 lines
6.3 KiB
C++

#include <SDL.h>
#include "glcxx.hpp"
#include "GL3/gl3w.h"
#include <iostream>
#include <stdio.h>
#include <list>
using namespace std;
#define WIDTH 800
#define HEIGHT 800
std::shared_ptr<glcxx::Program> program;
std::shared_ptr<glcxx::Buffer> box_buffer;
std::shared_ptr<glcxx::Array> box_array;
static struct
{
GLint size;
GLint color;
GLint position;
} uniforms;
unsigned int color = 0u;
GLfloat size = 0.2;
GLfloat position[2] = {0.0, 0.0};
GLfloat colors[][4] = {
{1.0, 0.7, 0.0, 1.0},
{0.0, 0.2, 1.0, 1.0},
{1.0, 1.0, 0.0, 1.0},
{0.2, 1.0, 1.0, 1.0},
};
float movement[2];
static SDL_Event UpdateEvent;
static Uint32 UpdateCallback(Uint32 interval, void * param)
{
SDL_PushEvent(&UpdateEvent);
return interval;
}
bool init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glViewport(0, 0, WIDTH, HEIGHT);
try
{
program = glcxx::Program::create(
glcxx::Shader::create_from_file(GL_VERTEX_SHADER, "box.v.glsl"),
glcxx::Shader::create_from_file(GL_FRAGMENT_SHADER, "box.f.glsl"),
"coord", 0);
uniforms.size = program->get_uniform_location("size");
uniforms.color = program->get_uniform_location("color");
uniforms.position = program->get_uniform_location("position");
box_buffer = glcxx::Buffer::create(GL_ARRAY_BUFFER, GL_STATIC_DRAW,
{-1.0, -1.0,
1.0, -1.0,
1.0, 1.0,
-1.0, 1.0});
box_array = glcxx::Array::create();
box_array->bind();
box_buffer->bind();
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE,
2 * sizeof(GLfloat), NULL);
}
catch (glcxx::Error & e)
{
cerr << "glcxx error: " << e.what() << endl;
return false;
}
return true;
}
void display(SDL_Window * window)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
program->use();
box_array->bind();
glUniform4fv(uniforms.color, 1, colors[color]);
glUniform2fv(uniforms.position, 1, position);
glUniform1f(uniforms.size, size);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
SDL_GL_SwapWindow(window);
}
void process_movement(int axis, float amount)
{
position[axis] += amount;
if (position[axis] < -1.0)
position[axis] = -1.0;
else if (position[axis] > 1.0)
position[axis] = 1.0;
}
void process_movements()
{
for (int i = 0; i <= 1; i++)
{
process_movement(i, movement[i] * 25.0 / 1000.0);
}
}
int main(int argc, char *argv[])
{
if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS))
{
printf("Failed to initialize SDL!\n");
return 1;
}
atexit(SDL_Quit);
SDL_Window * window = SDL_CreateWindow(argv[0],
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
WIDTH,
HEIGHT,
SDL_WINDOW_OPENGL);
if (!window)
{
printf("Failed to create window!\n");
SDL_Quit();
return 2;
}
(void)SDL_GL_CreateContext(window);
if (gl3wInit())
{
cerr << "Failed to initialize GL3W" << endl;
return 2;
}
if (!gl3wIsSupported(3, 0))
{
cerr << "OpenGL 3.0 is not supported!" << endl;
return 2;
}
if (!init())
{
return 2;
}
UpdateEvent.type = SDL_USEREVENT;
UpdateEvent.user.code = 0;
SDL_AddTimer(25, UpdateCallback, NULL);
int n_joysticks = SDL_NumJoysticks();
std::list<SDL_GameController *> game_controllers;
for (int i = 0; i < n_joysticks; i++)
{
if (SDL_IsGameController(i))
{
SDL_GameController * game_controller = SDL_GameControllerOpen(i);
if (game_controller == nullptr)
{
cerr << "Failed to open game controller " << i << ": " << SDL_GetError() << endl;
return 2;
}
game_controllers.push_back(game_controller);
}
}
cout << "Found " << n_joysticks << " joystick devices, " << game_controllers.size() << " of which are game controllers" << endl;
display(window);
SDL_Event event;
bool exit = false;
for (;;)
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
exit = true;
else if (event.type == SDL_KEYDOWN)
{
if (event.key.keysym.sym == SDLK_ESCAPE)
exit = true;
}
else if (event.type == SDL_CONTROLLERAXISMOTION)
{
if (event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX)
{
movement[0] = event.caxis.value / 32768.0;
if (fabsf(movement[0]) < 0.02)
movement[0] = 0.0;
}
else if (event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY)
{
movement[1] = -event.caxis.value / 32768.0;
if (fabsf(movement[1]) < 0.02)
movement[1] = 0.0;
}
}
else if ((event.type == SDL_CONTROLLERBUTTONDOWN) &&
(event.cbutton.state == SDL_PRESSED))
{
switch (event.cbutton.button)
{
case SDL_CONTROLLER_BUTTON_A:
size *= 0.8;
break;
case SDL_CONTROLLER_BUTTON_B:
size *= 1.2;
break;
case SDL_CONTROLLER_BUTTON_X:
color++;
if (color >= sizeof(colors) / sizeof(colors[0]))
color = 0u;
break;
}
}
else if (event.type == SDL_USEREVENT)
{
process_movements();
}
}
if (exit)
break;
display(window);
}
for (auto game_controller : game_controllers)
{
SDL_GameControllerClose(game_controller);
}
return 0;
}