first commit

This commit is contained in:
Maschell 2020-08-30 00:41:54 +02:00
commit 9c189354cb
34 changed files with 5844 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
.idea/
build/
cmake-build-debug/
cmake/
*.elf
*.rpx

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "cmake/sdl2"]
path = cmake/sdl2
url = https://github.com/aminosbh/sdl2-cmake-modules

40
CMakeLists.txt Normal file
View File

@ -0,0 +1,40 @@
cmake_minimum_required(VERSION 3.17)
project(SDL2_Playground)
set(CMAKE_CXX_STANDARD 20)
add_executable(${PROJECT_NAME}
src/main.cpp
src/gui/GuiElement.h
src/gui/GuiFrame.cpp
src/gui/GuiFrame.h
src/gui/GuiImage.cpp
src/gui/GuiImage.h
src/gui/sigslot.h
src/CVideo.cpp
src/CVideo.h
src/gui/GuiElement.cpp
src/gui/GuiText.cpp
src/gui/GuiText.h
src/gui/GuiSound.cpp
src/gui/GuiSound.h
src/gui/GuiTrigger.cpp
src/gui/GuiTrigger.h
src/gui/GuiController.h
src/gui/GuiButton.cpp
src/gui/GuiButton.h
src/gui/SDLController.h src/MainWindow.cpp src/MainWindow.h src/gui/SDLControllerJoystick.h src/gui/SDLControllerMouse.h
src/gui/SDLControllerWiiUGamepad.h
src/gui/SDLControllerWiiUProContoller.h
)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/sdl2)
find_package(SDL2 REQUIRED)
find_package(SDL2_image REQUIRED)
find_package(SDL2_ttf REQUIRED)
find_package(SDL2_mixer REQUIRED)
target_link_libraries(${PROJECT_NAME} SDL2::Main SDL2::Image SDL2::TTF SDL2::Mixer)

144
Makefile.wiiu Normal file
View File

@ -0,0 +1,144 @@
#-------------------------------------------------------------------------------
.SUFFIXES:
#-------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/wut/share/wut_rules
WUMS_ROOT := $(DEVKITPRO)/wums
#-------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#-------------------------------------------------------------------------------
TARGET := SDL2_Playground
BUILD := build
SOURCES := src \
src/gui
DATA := data
INCLUDES := source
#-------------------------------------------------------------------------------
# options for code generation
#-------------------------------------------------------------------------------
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(MACHDEP)
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
CXXFLAGS := $(CFLAGS) -std=c++14
ASFLAGS := -g $(ARCH)
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map)
LIBS := -lSDL2_mixer -lSDL2 -lSDL2_image -ljpeg -lvorbisidec -logg -lmodplug -lmpg123 -lSDL2_ttf -lfreetype -lpng -lz -lbz2 -lwut
#-------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level
# containing include and lib
#-------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUMS_ROOT)
#-------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#-------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#-------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#-------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#-------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#-------------------------------------------------------------------------------
export LD := $(CC)
#-------------------------------------------------------------------------------
else
#-------------------------------------------------------------------------------
export LD := $(CXX)
#-------------------------------------------------------------------------------
endif
#-------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#-------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.wiiu
#-------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).rpx $(TARGET).elf
#-------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#-------------------------------------------------------------------------------
# main targets
#-------------------------------------------------------------------------------
all : $(OUTPUT).rpx
$(OUTPUT).rpx : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
$(OFILES_SRC) : $(HFILES_BIN)
#-------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#-------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#-------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
%.o: %.s
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER)
-include $(DEPENDS)
#-------------------------------------------------------------------------------
endif
#-------------------------------------------------------------------------------

20
README.md Normal file
View File

@ -0,0 +1,20 @@
# Building
## Windows with devkitPros version of msys2
Setup mingw:
1. Add the mingw64 repository to `/etc/pacman.conf`.
```
[mingw64]
Server = https://repo.msys2.org/mingw/x86_64
```
2. Install packages (List taken from [here](https://gist.github.com/thales17/fb2e4cff60890a51d9dddd4c6e832ad2))
```
pacman -Syu
pacman -S git mingw-w64-x86_64-toolchain mingw64/mingw-w64-x86_64-SDL2 mingw64/mingw-w64-x86_64-SDL2_mixer mingw64/mingw-w64-x86_64-SDL2_image mingw64/mingw-w64-x86_64-SDL2_ttf mingw64/mingw-w64-x86_64-SDL2_net mingw64/mingw-w64-x86_64-cmake mingw-w64-x86_64-glm make
```
```
mkdir build && cd build
C:\devkitPro\msys2\mingw64\bin\cmake.exe -DSDL2_PATH=C:/devkitPro/msys2/mingw64 -Wno-dev -G "Unix Makefiles" -DCMAKE_CXX_COMPILER=C:/devkitPro/msys2/mingw64/bin/g++.exe DCMAKE_C_COMPILER=C:/devkitPro/msys2/mingw64/bin/gcc.exe ../
make
```

1
cmake/sdl2 Submodule

@ -0,0 +1 @@
Subproject commit ad006a3daae65a612ed87415037e32188b81071e

74
src/CVideo.cpp Normal file
View File

@ -0,0 +1,74 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "CVideo.h"
#include "logger.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>
CVideo::CVideo() {
SDL_Init(SDL_INIT_EVERYTHING);
auto SDLFlags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC;
//Setup window
window = SDL_CreateWindow(nullptr, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, 0);
if (!window) { return; }
renderer = SDL_CreateRenderer(window, -1, SDLFlags);
if (!renderer) { return; }
SDL_SetRenderTarget(renderer, NULL);
if (SDL_Init(SDL_INIT_AUDIO) != 0) {
DEBUG_FUNCTION_LINE("SDL init error: %s\n", SDL_GetError());
return;
}
int flags = 0;
int result = 0;
if (flags != (result = Mix_Init(flags))) {
DEBUG_FUNCTION_LINE("Could not initialize mixer (result: %d).\n", result);
DEBUG_FUNCTION_LINE("Mix_Init: %s\n", Mix_GetError());
}
auto dev = Mix_OpenAudio(22050, AUDIO_S16SYS, 2, 640);
SDL_PauseAudioDevice(dev, 0);
}
CVideo::~CVideo() {
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
SDL_Renderer *CVideo::getRenderer() {
return renderer;
}
float CVideo::getHeight() {
int h = 0;
SDL_GetWindowSize(window, NULL, &h);
return h;
}
float CVideo::getWidth() {
int w = 0;
SDL_GetWindowSize(window, &w, NULL);
return w;
}
unsigned int CVideo::getPixelFormat() {
return SDL_GetWindowPixelFormat(window);
}

36
src/CVideo.h Normal file
View File

@ -0,0 +1,36 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <SDL2/SDL_render.h>
class CVideo {
public:
CVideo();
virtual ~CVideo();
SDL_Renderer *getRenderer();
float getHeight();
float getWidth();
unsigned int getPixelFormat();
private:
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
};

75
src/MainWindow.cpp Normal file
View File

@ -0,0 +1,75 @@
#include "MainWindow.h"
MainWindow::~MainWindow() {
delete label;;
delete touchTrigger;;
delete sound;;
delete image;;
delete image2;;
delete image3;;
delete image4;;
delete image5;;
delete image;;
delete label;;
delete button;;
delete bgMusic;;
}
MainWindow::MainWindow(int32_t w, int32_t h) : GuiFrame(w, h) {
#if defined _WIN32
auto picture_path = "test.png";
auto font_path = "FreeSans.ttf";
auto bgMusic_path = "bgMusic.ogg";
auto music_click = "button_click.mp3";
#else
auto picture_path = "fs:/vol/external01/test.png";
auto font_path = "fs:/vol/external01/FreeSans.ttf";
auto bgMusic_path = "fs:/vol/external01/bgMusic.ogg";
auto music_click = "fs:/vol/external01/button_click.mp3";
#endif
TTF_Init();
TTF_Font *font;
font = TTF_OpenFont(font_path, 35);
label = new GuiText("This is a test AVAVAVVAVA", 25, {255, 255, 0, 255}, font);
bgMusic = new GuiSound(bgMusic_path);
bgMusic->SetLoop(true);
bgMusic->Play();
image = new GuiImage(picture_path);
image2 = new GuiImage(picture_path);
image3 = new GuiImage(picture_path);
image4 = new GuiImage(picture_path);
image5 = new GuiImage(picture_path);
button = new GuiButton(image5->getWidth(), image5->getHeight());
this->setAlignment(ALIGN_TOP_LEFT);
this->append(button);
this->append(image);
this->append(image2);
this->append(image3);
this->append(image4);
image->setAlignment(ALIGN_TOP_LEFT);
image2->setAlignment(ALIGN_TOP_RIGHT);
image3->setAlignment(ALIGN_BOTTOM | ALIGN_LEFT);
image4->setAlignment(ALIGN_BOTTOM | ALIGN_RIGHT);
button->setAlignment(ALIGN_CENTERED);
button->setImage(image5);
sound = new GuiSound(music_click);
touchTrigger = new GuiTrigger(GuiTrigger::CHANNEL_1, GuiTrigger::TOUCHED);
touchTrigger = new GuiTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::TOUCHED);
button->setTrigger(touchTrigger);
button->setEffectGrow();
label->setAlignment(ALIGN_CENTERED);
button->setLabel(label);
button->setSoundClick(sound);
button->clicked.connect(this, &MainWindow::test);
}

29
src/MainWindow.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <iostream>
#include "gui/GuiFrame.h"
#include "gui/GuiButton.h"
#include "logger.h"
class MainWindow : public GuiFrame, public sigslot::has_slots<> {
public:
void test(GuiButton *, const GuiController *, GuiTrigger *) {
DEBUG_FUNCTION_LINE("Hello, you have clicked the button");
}
~MainWindow();
MainWindow(int32_t w, int32_t h);
private:
GuiText *label = nullptr;
GuiTrigger *touchTrigger = nullptr;
GuiSound *sound = nullptr;
GuiImage *image = nullptr;
GuiImage *image2 = nullptr;
GuiImage *image3 = nullptr;
GuiImage *image4 = nullptr;
GuiImage *image5 = nullptr;
GuiButton *button = nullptr;
GuiSound *bgMusic = nullptr;
};

275
src/gui/GuiButton.cpp Normal file
View File

@ -0,0 +1,275 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <iostream>
#include "GuiButton.h"
#include "GuiController.h"
/**
* Constructor for the GuiButton class.
*/
GuiButton::GuiButton(float w, float h) {
width = w;
height = h;
image = NULL;
imageOver = NULL;
imageHold = NULL;
imageClick = NULL;
icon = NULL;
iconOver = NULL;
for (int32_t i = 0; i < 4; i++) {
label[i] = NULL;
labelOver[i] = NULL;
labelHold[i] = NULL;
labelClick[i] = NULL;
}
for (int32_t i = 0; i < iMaxGuiTriggers; i++) {
trigger[i] = NULL;
}
soundOver = NULL;
soundHold = NULL;
soundClick = NULL;
clickedTrigger = NULL;
heldTrigger = NULL;
selectable = true;
holdable = false;
clickable = true;
}
/**
* Destructor for the GuiButton class.
*/
GuiButton::~GuiButton() {
}
void GuiButton::setImage(GuiImage *img) {
image = img;
if (img) { img->setParent(this); }
}
void GuiButton::setImageOver(GuiImage *img) {
imageOver = img;
if (img) { img->setParent(this); }
}
void GuiButton::setImageHold(GuiImage *img) {
imageHold = img;
if (img) { img->setParent(this); }
}
void GuiButton::setImageClick(GuiImage *img) {
imageClick = img;
if (img) { img->setParent(this); }
}
void GuiButton::setIcon(GuiImage *img) {
icon = img;
if (img) { img->setParent(this); }
}
void GuiButton::setIconOver(GuiImage *img) {
iconOver = img;
if (img) { img->setParent(this); }
}
void GuiButton::setLabel(GuiText *txt, int32_t n) {
label[n] = txt;
if (txt) { txt->setParent(this); }
}
void GuiButton::setLabelOver(GuiText *txt, int32_t n) {
labelOver[n] = txt;
if (txt) { txt->setParent(this); }
}
void GuiButton::setLabelHold(GuiText *txt, int32_t n) {
labelHold[n] = txt;
if (txt) { txt->setParent(this); }
}
void GuiButton::setLabelClick(GuiText *txt, int32_t n) {
labelClick[n] = txt;
if (txt) { txt->setParent(this); }
}
void GuiButton::setSoundOver(GuiSound *snd) {
soundOver = snd;
}
void GuiButton::setSoundHold(GuiSound *snd) {
soundHold = snd;
}
void GuiButton::setSoundClick(GuiSound *snd) {
soundClick = snd;
}
void GuiButton::setTrigger(GuiTrigger *t, int32_t idx) {
if (idx >= 0 && idx < iMaxGuiTriggers) {
trigger[idx] = t;
} else {
for (int32_t i = 0; i < iMaxGuiTriggers; i++) {
if (!trigger[i]) {
trigger[i] = t;
break;
}
}
}
}
void GuiButton::resetState(void) {
clickedTrigger = NULL;
heldTrigger = NULL;
GuiElement::resetState();
}
/**
* Draw the button on screen
*/
void GuiButton::draw(CVideo *v) {
if (!this->isVisible()) {
return;
}
// draw image
if ((isDrawOverOnlyWhenSelected() && (isStateSet(STATE_SELECTED) && imageOver)) ||
(!isDrawOverOnlyWhenSelected() && (isStateSet(STATE_OVER | STATE_SELECTED | STATE_CLICKED | STATE_HELD) && imageOver))) {
imageOver->draw(v);
} else if (image) {
image->draw(v);
}
if ((isDrawOverOnlyWhenSelected() && (isStateSet(STATE_SELECTED) && iconOver)) ||
(!isDrawOverOnlyWhenSelected() && (isStateSet(STATE_OVER | STATE_SELECTED | STATE_CLICKED | STATE_HELD) && iconOver))) {
iconOver->draw(v);
} else if (icon) {
icon->draw(v);
}
// draw text
for (int32_t i = 0; i < 4; i++) {
if (isStateSet(STATE_OVER | STATE_SELECTED | STATE_CLICKED | STATE_HELD) && labelOver[i]) {
labelOver[i]->draw(v);
} else if (label[i]) {
label[i]->draw(v);
}
}
}
void GuiButton::update(GuiController *c) {
if (!c || isStateSet(STATE_DISABLED | STATE_HIDDEN | STATE_DISABLE_INPUT, c->chanIdx)) {
return;
} else if (parentElement && (parentElement->isStateSet(STATE_DISABLED | STATE_HIDDEN | STATE_DISABLE_INPUT, c->chanIdx))) {
return;
}
if (selectable) {
if (c->data.validPointer && this->isInside(c->data.x, c->data.y)) {
if (!isStateSet(STATE_OVER, c->chanIdx)) {
setState(STATE_OVER, c->chanIdx);
//if(this->isRumbleActive())
// this->rumble(t->chan);
if (soundOver) {
soundOver->Play();
}
if (effectsOver && !effects) {
// initiate effects
effects = effectsOver;
effectAmount = effectAmountOver;
effectTarget = effectTargetOver;
}
pointedOn(this, c);
}
} else if (isStateSet(STATE_OVER, c->chanIdx)) {
this->clearState(STATE_OVER, c->chanIdx);
pointedOff(this, c);
if (effectTarget == effectTargetOver && effectAmount == effectAmountOver) {
// initiate effects (in reverse)
effects = effectsOver;
effectAmount = -effectAmountOver;
effectTarget = 100;
}
}
}
for (int32_t i = 0; i < iMaxGuiTriggers; i++) {
if (!trigger[i]) {
continue;
}
// button triggers
if (clickable) {
int32_t isClicked = trigger[i]->clicked(c);
if (!clickedTrigger && (isClicked != GuiTrigger::CLICKED_NONE)
&& (trigger[i]->isClickEverywhere() || (isStateSet(STATE_SELECTED | STATE_OVER, c->chanIdx) && trigger[i]->isSelectionClickEverywhere()) || this->isInside(c->data.x, c->data.y))) {
if (soundClick) {
soundClick->Play();
}
clickedTrigger = trigger[i];
if (!isStateSet(STATE_CLICKED, c->chanIdx)) {
if (isClicked == GuiTrigger::CLICKED_TOUCH) {
setState(STATE_CLICKED_TOUCH, c->chanIdx);
} else {
setState(STATE_CLICKED, c->chanIdx);
}
}
clicked(this, c, trigger[i]);
} else if ((isStateSet(STATE_CLICKED, c->chanIdx) || isStateSet(STATE_CLICKED_TOUCH, c->chanIdx)) && (clickedTrigger == trigger[i]) && !isStateSet(STATE_HELD, c->chanIdx) && !trigger[i]->held(c) &&
((isClicked == GuiTrigger::CLICKED_NONE) || trigger[i]->released(c))) {
if ((isStateSet(STATE_CLICKED_TOUCH, c->chanIdx) && this->isInside(c->data.x, c->data.y)) || (isStateSet(STATE_CLICKED, c->chanIdx))) {
clickedTrigger = NULL;
clearState(STATE_CLICKED, c->chanIdx);
released(this, c, trigger[i]);
}
}
}
if (holdable) {
bool isHeld = trigger[i]->held(c);
if ((!heldTrigger || heldTrigger == trigger[i]) && isHeld
&& (trigger[i]->isHoldEverywhere() || (isStateSet(STATE_SELECTED | STATE_OVER, c->chanIdx) && trigger[i]->isSelectionClickEverywhere()) || this->isInside(c->data.x, c->data.y))) {
heldTrigger = trigger[i];
if (!isStateSet(STATE_HELD, c->chanIdx)) {
setState(STATE_HELD, c->chanIdx);
}
held(this, c, trigger[i]);
} else if (isStateSet(STATE_HELD, c->chanIdx) && (heldTrigger == trigger[i]) && (!isHeld || trigger[i]->released(c))) {
//! click is removed at this point and converted to held
if (clickedTrigger == trigger[i]) {
clickedTrigger = NULL;
clearState(STATE_CLICKED, c->chanIdx);
}
heldTrigger = NULL;
clearState(STATE_HELD, c->chanIdx);
released(this, c, trigger[i]);
}
}
}
}

129
src/gui/GuiButton.h Normal file
View File

@ -0,0 +1,129 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include "GuiElement.h"
#include "GuiImage.h"
#include "GuiText.h"
#include "GuiSound.h"
#include "GuiTrigger.h"
#include "../CVideo.h"
//!Display, manage, and manipulate buttons in the GUI. Buttons can have images, icons, text, and sound set (all of which are optional)
class GuiButton : public GuiElement {
public:
//!Constructor
//!\param w Width
//!\param h Height
GuiButton(float w, float h);
//!Destructor
virtual ~GuiButton();
//!Sets the button's image
//!\param i Pointer to GuiImage object
void setImage(GuiImage *i);
//!Sets the button's image on over
//!\param i Pointer to GuiImage object
void setImageOver(GuiImage *i);
void setIcon(GuiImage *i);
void setIconOver(GuiImage *i);
//!Sets the button's image on hold
//!\param i Pointer to GuiImage object
void setImageHold(GuiImage *i);
//!Sets the button's image on click
//!\param i Pointer to GuiImage object
void setImageClick(GuiImage *i);
//!Sets the button's label
//!\param t Pointer to GuiText object
//!\param n Index of label to set (optional, default is 0)
void setLabel(GuiText *t, int32_t n = 0);
//!Sets the button's label on over (eg: different colored text)
//!\param t Pointer to GuiText object
//!\param n Index of label to set (optional, default is 0)
void setLabelOver(GuiText *t, int32_t n = 0);
//!Sets the button's label on hold
//!\param t Pointer to GuiText object
//!\param n Index of label to set (optional, default is 0)
void setLabelHold(GuiText *t, int32_t n = 0);
//!Sets the button's label on click
//!\param t Pointer to GuiText object
//!\param n Index of label to set (optional, default is 0)
void setLabelClick(GuiText *t, int32_t n = 0);
//!Sets the sound to play on over
//!\param s Pointer to GuiSound object
void setSoundOver(GuiSound *s);
//!Sets the sound to play on hold
//!\param s Pointer to GuiSound object
void setSoundHold(GuiSound *s);
//!Sets the sound to play on click
//!\param s Pointer to GuiSound object
void setSoundClick(GuiSound *s);
//!Set a new GuiTrigger for the element
//!\param i Index of trigger array to set
//!\param t Pointer to GuiTrigger
void setTrigger(GuiTrigger *t, int32_t idx = -1);
//!
void resetState(void);
//!Constantly called to draw the GuiButton
void draw(CVideo *video);
//!Constantly called to allow the GuiButton to respond to updated input data
//!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD
void update(GuiController *c);
sigslot::signal2<GuiButton *, const GuiController *> selected;
sigslot::signal2<GuiButton *, const GuiController *> deSelected;
sigslot::signal2<GuiButton *, const GuiController *> pointedOn;
sigslot::signal2<GuiButton *, const GuiController *> pointedOff;
sigslot::signal3<GuiButton *, const GuiController *, GuiTrigger *> clicked;
sigslot::signal3<GuiButton *, const GuiController *, GuiTrigger *> held;
sigslot::signal3<GuiButton *, const GuiController *, GuiTrigger *> released;
protected:
static const int32_t iMaxGuiTriggers = 10;
GuiImage *image; //!< Button image (default)
GuiImage *imageOver; //!< Button image for STATE_SELECTED
GuiImage *imageHold; //!< Button image for STATE_HELD
GuiImage *imageClick; //!< Button image for STATE_CLICKED
GuiImage *icon;
GuiImage *iconOver;
GuiText *label[4]; //!< Label(s) to display (default)
GuiText *labelOver[4]; //!< Label(s) to display for STATE_SELECTED
GuiText *labelHold[4]; //!< Label(s) to display for STATE_HELD
GuiText *labelClick[4]; //!< Label(s) to display for STATE_CLICKED
GuiSound *soundOver; //!< Sound to play for STATE_SELECTED
GuiSound *soundHold; //!< Sound to play for STATE_HELD
GuiSound *soundClick; //!< Sound to play for STATE_CLICKED
GuiTrigger *trigger[iMaxGuiTriggers]; //!< GuiTriggers (input actions) that this element responds to
GuiTrigger *clickedTrigger;
GuiTrigger *heldTrigger;
};

68
src/gui/GuiController.h Normal file
View File

@ -0,0 +1,68 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <string.h>
#include "GuiTrigger.h"
class GuiController {
public:
//!Constructor
GuiController(int32_t channel)
: chan(channel) {
memset(&lastData, 0, sizeof(lastData));
memset(&data, 0, sizeof(data));
switch (chan) {
default:
case GuiTrigger::CHANNEL_1:
chanIdx = 0;
break;
case GuiTrigger::CHANNEL_2:
chanIdx = 1;
break;
case GuiTrigger::CHANNEL_3:
chanIdx = 2;
break;
case GuiTrigger::CHANNEL_4:
chanIdx = 3;
break;
case GuiTrigger::CHANNEL_5:
chanIdx = 4;
break;
}
}
//!Destructor
virtual ~GuiController() {}
typedef struct {
uint32_t buttons_h;
uint32_t buttons_d;
uint32_t buttons_r;
bool validPointer;
bool touched;
float pointerAngle;
int32_t x;
int32_t y;
} PadData;
int32_t chan;
int32_t chanIdx;
PadData data;
PadData lastData;
};

290
src/gui/GuiElement.cpp Normal file
View File

@ -0,0 +1,290 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "GuiElement.h"
//! TODO remove this!
static int32_t screenwidth = 1280;
static int32_t screenheight = 720;
/**
* Constructor for the Object class.
*/
GuiElement::GuiElement() {
xoffset = 0.0f;
yoffset = 0.0f;
zoffset = 0.0f;
width = 0.0f;
height = 0.0f;
alpha = 1.0f;
scaleX = 1.0f;
scaleY = 1.0f;
scaleZ = 1.0f;
for (int32_t i = 0; i < 5; i++) {
state[i] = STATE_DEFAULT;
}
stateChan = -1;
parentElement = NULL;
rumble = true;
selectable = false;
clickable = false;
holdable = false;
drawOverOnlyWhenSelected = false;
visible = true;
yoffsetDyn = 0;
xoffsetDyn = 0;
alphaDyn = -1;
scaleDyn = 1;
effects = EFFECT_NONE;
effectAmount = 0;
effectTarget = 0;
effectsOver = EFFECT_NONE;
effectAmountOver = 0;
effectTargetOver = 0;
angle = 0.0f;
// default alignment - align to top left
alignment = (ALIGN_TOP_LEFT);
}
/**
* Get the left position of the GuiElement.
* @see SetLeft()
* @return Left position in pixel.
*/
float GuiElement::getLeft() {
float pWidth = 0;
float pLeft = 0;
float pScaleX = 1.0f;
if (parentElement) {
pWidth = parentElement->getWidth();
pLeft = parentElement->getLeft();
pScaleX = parentElement->getScaleX();
}
pLeft += xoffsetDyn;
float x = pLeft;
//! TODO: the conversion from int to float and back to int is bad for performance, change that
if (alignment & ALIGN_CENTER) {
x = pLeft + pWidth * 0.5f * pScaleX - width * 0.5f * getScaleX();
} else if (alignment & ALIGN_RIGHT) {
x = pLeft + pWidth * pScaleX - width * getScaleX();
}
return x + xoffset;
}
/**
* Get the top position of the GuiElement.
* @see SetTop()
* @return Top position in pixel.
*/
float GuiElement::getTop() {
float pHeight = 0;
float pTop = 0;
float pScaleY = 1.0f;
if (parentElement) {
pHeight = parentElement->getHeight();
pTop = parentElement->getTop();
pScaleY = parentElement->getScaleY();
}
pTop += yoffsetDyn;
float y = pTop;
//! TODO: the conversion from int to float and back to int is bad for performance, change that
if (alignment & ALIGN_MIDDLE) {
y = pTop + pHeight * 0.5f * pScaleY - getHeight() * 0.5f * getScaleY();
} else if (alignment & ALIGN_BOTTOM) {
y = pTop + pHeight * pScaleY - getHeight() * getScaleY();
}
return y + yoffset;
}
void GuiElement::setEffect(int32_t eff, int32_t amount, int32_t target) {
if (eff & EFFECT_SLIDE_IN) {
// these calculations overcompensate a little
if (eff & EFFECT_SLIDE_TOP) {
if (eff & EFFECT_SLIDE_FROM) {
yoffsetDyn = (int32_t) -getHeight() * scaleY;
} else {
yoffsetDyn = -screenheight;
}
} else if (eff & EFFECT_SLIDE_LEFT) {
if (eff & EFFECT_SLIDE_FROM) {
xoffsetDyn = (int32_t) -getWidth() * scaleX;
} else {
xoffsetDyn = -screenwidth;
}
} else if (eff & EFFECT_SLIDE_BOTTOM) {
if (eff & EFFECT_SLIDE_FROM) {
yoffsetDyn = (int32_t) getHeight() * scaleY;
} else {
yoffsetDyn = screenheight;
}
} else if (eff & EFFECT_SLIDE_RIGHT) {
if (eff & EFFECT_SLIDE_FROM) {
xoffsetDyn = (int32_t) getWidth() * scaleX;
} else {
xoffsetDyn = screenwidth;
}
}
}
if ((eff & EFFECT_FADE) && amount > 0) {
alphaDyn = 0;
} else if ((eff & EFFECT_FADE) && amount < 0) {
alphaDyn = alpha;
}
effects |= eff;
effectAmount = amount;
effectTarget = target;
}
//!Sets an effect to be enabled on wiimote cursor over
//!\param e Effect to enable
//!\param a Amount of the effect (usage varies on effect)
//!\param t Target amount of the effect (usage varies on effect)
void GuiElement::setEffectOnOver(int32_t e, int32_t a, int32_t t) {
effectsOver |= e;
effectAmountOver = a;
effectTargetOver = t;
}
void GuiElement::resetEffects() {
yoffsetDyn = 0;
xoffsetDyn = 0;
alphaDyn = -1;
scaleDyn = 1;
effects = EFFECT_NONE;
effectAmount = 0;
effectTarget = 0;
effectsOver = EFFECT_NONE;
effectAmountOver = 0;
effectTargetOver = 0;
}
void GuiElement::updateEffects() {
if (!this->isVisible() && parentElement) {
return;
}
if (effects & (EFFECT_SLIDE_IN | EFFECT_SLIDE_OUT | EFFECT_SLIDE_FROM)) {
if (effects & EFFECT_SLIDE_IN) {
if (effects & EFFECT_SLIDE_LEFT) {
xoffsetDyn += effectAmount;
if (xoffsetDyn >= 0) {
xoffsetDyn = 0;
effects = 0;
effectFinished(this);
}
} else if (effects & EFFECT_SLIDE_RIGHT) {
xoffsetDyn -= effectAmount;
if (xoffsetDyn <= 0) {
xoffsetDyn = 0;
effects = 0;
effectFinished(this);
}
} else if (effects & EFFECT_SLIDE_TOP) {
yoffsetDyn += effectAmount;
if (yoffsetDyn >= 0) {
yoffsetDyn = 0;
effects = 0;
effectFinished(this);
}
} else if (effects & EFFECT_SLIDE_BOTTOM) {
yoffsetDyn -= effectAmount;
if (yoffsetDyn <= 0) {
yoffsetDyn = 0;
effects = 0;
effectFinished(this);
}
}
} else {
if (effects & EFFECT_SLIDE_LEFT) {
xoffsetDyn -= effectAmount;
if (xoffsetDyn <= -screenwidth) {
effects = 0; // shut off effect
effectFinished(this);
} else if ((effects & EFFECT_SLIDE_FROM) && xoffsetDyn <= -getWidth()) {
effects = 0; // shut off effect
effectFinished(this);
}
} else if (effects & EFFECT_SLIDE_RIGHT) {
xoffsetDyn += effectAmount;
if (xoffsetDyn >= screenwidth) {
effects = 0; // shut off effect
effectFinished(this);
} else if ((effects & EFFECT_SLIDE_FROM) && xoffsetDyn >= getWidth() * scaleX) {
effects = 0; // shut off effect
effectFinished(this);
}
} else if (effects & EFFECT_SLIDE_TOP) {
yoffsetDyn -= effectAmount;
if (yoffsetDyn <= -screenheight) {
effects = 0; // shut off effect
effectFinished(this);
} else if ((effects & EFFECT_SLIDE_FROM) && yoffsetDyn <= -getHeight()) {
effects = 0; // shut off effect
effectFinished(this);
}
} else if (effects & EFFECT_SLIDE_BOTTOM) {
yoffsetDyn += effectAmount;
if (yoffsetDyn >= screenheight) {
effects = 0; // shut off effect
effectFinished(this);
} else if ((effects & EFFECT_SLIDE_FROM) && yoffsetDyn >= getHeight()) {
effects = 0; // shut off effect
effectFinished(this);
}
}
}
} else if (effects & EFFECT_FADE) {
alphaDyn += effectAmount * (1.0f / 255.0f);
if (effectAmount < 0 && alphaDyn <= 0) {
alphaDyn = 0;
effects = 0; // shut off effect
effectFinished(this);
} else if (effectAmount > 0 && alphaDyn >= alpha) {
alphaDyn = alpha;
effects = 0; // shut off effect
effectFinished(this);
}
} else if (effects & EFFECT_SCALE) {
scaleDyn += effectAmount * 0.01f;
if ((effectAmount < 0 && scaleDyn <= (effectTarget * 0.01f))
|| (effectAmount > 0 && scaleDyn >= (effectTarget * 0.01f))) {
scaleDyn = effectTarget * 0.01f;
effects = 0; // shut off effect
effectFinished(this);
}
}
}

604
src/gui/GuiElement.h Normal file
View File

@ -0,0 +1,604 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <string>
#include <vector>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wchar.h>
#include <math.h>
#include <iostream>
#include "sigslot.h"
enum {
EFFECT_NONE = 0x00,
EFFECT_SLIDE_TOP = 0x01,
EFFECT_SLIDE_BOTTOM = 0x02,
EFFECT_SLIDE_RIGHT = 0x04,
EFFECT_SLIDE_LEFT = 0x08,
EFFECT_SLIDE_IN = 0x10,
EFFECT_SLIDE_OUT = 0x20,
EFFECT_SLIDE_FROM = 0x40,
EFFECT_FADE = 0x80,
EFFECT_SCALE = 0x100,
EFFECT_COLOR_TRANSITION = 0x200
};
enum {
ALIGN_LEFT = 0x01,
ALIGN_CENTER = 0x02,
ALIGN_RIGHT = 0x04,
ALIGN_TOP = 0x10,
ALIGN_MIDDLE = 0x20,
ALIGN_BOTTOM = 0x40,
ALIGN_TOP_LEFT = ALIGN_LEFT | ALIGN_TOP,
ALIGN_TOP_CENTER = ALIGN_CENTER | ALIGN_TOP,
ALIGN_TOP_RIGHT = ALIGN_RIGHT | ALIGN_TOP,
ALIGN_CENTERED = ALIGN_CENTER | ALIGN_MIDDLE,
};
//!Forward declaration
class GuiController;
class CVideo;
//!Primary GUI class. Most other classes inherit from this class.
class GuiElement {
public:
//!Constructor
GuiElement();
//!Destructor
virtual ~GuiElement() {}
//!Set the element's parent
//!\param e Pointer to parent element
virtual void setParent(GuiElement *e) {
parentElement = e;
}
//!Gets the element's parent
//!\return Pointer to parent element
virtual GuiElement *getParent() {
return parentElement;
}
//!Gets the current leftmost coordinate of the element
//!Considers horizontal alignment, x offset, width, and parent element's GetLeft() / GetWidth() values
//!\return left coordinate
virtual float getLeft();
//!Gets the current topmost coordinate of the element
//!Considers vertical alignment, y offset, height, and parent element's GetTop() / GetHeight() values
//!\return top coordinate
virtual float getTop();
//!Gets the current Z coordinate of the element
//!\return Z coordinate
virtual float getDepth() {
float zParent = 0.0f;
if (parentElement) {
zParent = parentElement->getDepth();
}
return zParent + zoffset;
}
virtual float getCenterX(void) {
float pCenterX = 0.0f;
if (parentElement) {
pCenterX = parentElement->getCenterX();
}
pCenterX += xoffset + xoffsetDyn;
if (alignment & ALIGN_LEFT) {
float pWidth = 0.0f;
float pScale = 0.0f;
if (parentElement) {
pWidth = parentElement->getWidth();
pScale = parentElement->getScaleX();
}
pCenterX -= pWidth * 0.5f * pScale - width * 0.5f * getScaleX();
} else if (alignment & ALIGN_RIGHT) {
float pWidth = 0.0f;
float pScale = 0.0f;
if (parentElement) {
pWidth = parentElement->getWidth();
pScale = parentElement->getScaleX();
}
pCenterX += pWidth * 0.5f * pScale - width * 0.5f * getScaleX();
}
return pCenterX;
}
virtual float getCenterY(void) {
float pCenterY = 0.0f;
if (parentElement) {
pCenterY = parentElement->getCenterY();
}
pCenterY += yoffset + yoffsetDyn;
if (alignment & ALIGN_TOP) {
float pHeight = 0.0f;
float pScale = 0.0f;
if (parentElement) {
pHeight = parentElement->getHeight();
pScale = parentElement->getScaleY();
}
pCenterY += pHeight * 0.5f * pScale + getHeight() * 0.5f * getScaleY();
} else if (alignment & ALIGN_BOTTOM) {
float pHeight = 0.0f;
float pScale = 0.0f;
if (parentElement) {
pHeight = parentElement->getHeight();
pScale = parentElement->getScaleY();
}
pCenterY -= pHeight * 0.5f * pScale - getHeight() * 0.5f * getScaleY();
}
return pCenterY;
}
//!Gets elements xoffset
virtual float getOffsetX() {
return xoffset;
}
//!Gets elements yoffset
virtual float getOffsetY() {
return yoffset;
}
//!Gets the current width of the element. Does not currently consider the scale
//!\return width
virtual float getWidth() {
return width;
};
//!Gets the height of the element. Does not currently consider the scale
//!\return height
virtual float getHeight() {
return height;
}
//!Sets the size (width/height) of the element
//!\param w Width of element
//!\param h Height of element
virtual void setSize(float w, float h) {
width = w;
height = h;
}
//!Sets the element's visibility
//!\param v Visibility (true = visible)
virtual void setVisible(bool v) {
visible = v;
visibleChanged(this, v);
}
//!Checks whether or not the element is visible
//!\return true if visible, false otherwise
virtual bool isVisible() const {
return !isStateSet(STATE_HIDDEN) && visible;
};
//!Checks whether or not the element is selectable
//!\return true if selectable, false otherwise
virtual bool isSelectable() {
return !isStateSet(STATE_DISABLED) && selectable;
}
virtual bool isDrawOverOnlyWhenSelected() {
return drawOverOnlyWhenSelected;
}
virtual void setdrawOverOnlyWhenSelected(bool s) {
drawOverOnlyWhenSelected = s;
}
//!Checks whether or not the element is clickable
//!\return true if clickable, false otherwise
virtual bool isClickable() {
return !isStateSet(STATE_DISABLED) && clickable;
}
//!Checks whether or not the element is holdable
//!\return true if holdable, false otherwise
virtual bool isHoldable() {
return !isStateSet(STATE_DISABLED) && holdable;
}
//!Sets whether or not the element is selectable
//!\param s Selectable
virtual void setSelectable(bool s) {
selectable = s;
}
//!Sets whether or not the element is clickable
//!\param c Clickable
virtual void setClickable(bool c) {
clickable = c;
}
//!Sets whether or not the element is holdable
//!\param c Holdable
virtual void setHoldable(bool d) {
holdable = d;
}
//!Sets the element's state
//!\param s State (STATE_DEFAULT, STATE_SELECTED, STATE_CLICKED, STATE_DISABLED)
//!\param c Controller channel (0-3, -1 = none)
virtual void setState(int32_t s, int32_t c = -1) {
if (c >= 0 && c < 5) {
state[c] |= s;
} else {
for (int32_t i = 0; i < 5; i++) {
state[i] |= s;
}
}
stateChan = c;
stateChanged(this, s, c);
}
virtual void clearState(int32_t s, int32_t c = -1) {
if (c >= 0 && c < 5) {
state[c] &= ~s;
} else {
for (int32_t i = 0; i < 5; i++) {
state[i] &= ~s;
}
}
stateChan = c;
stateChanged(this, s, c);
}
virtual bool isStateSet(int32_t s, int32_t c = -1) const {
if (c >= 0 && c < 5) {
return (state[c] & s) != 0;
} else {
for (int32_t i = 0; i < 5; i++) {
if ((state[i] & s) != 0) {
return true;
}
}
return false;
}
}
//!Gets the element's current state
//!\return state
virtual int32_t getState(int32_t c = 0) {
return state[c];
};
//!Gets the controller channel that last changed the element's state
//!\return Channel number (0-3, -1 = no channel)
virtual int32_t getStateChan() {
return stateChan;
};
//!Resets the element's state to STATE_DEFAULT
virtual void resetState() {
for (int32_t i = 0; i < 5; i++) {
state[i] = STATE_DEFAULT;
}
stateChan = -1;
}
//!Sets the element's alpha value
//!\param a alpha value
virtual void setAlpha(float a) {
alpha = a;
}
//!Gets the element's alpha value
//!Considers alpha, alphaDyn, and the parent element's getAlpha() value
//!\return alpha
virtual float getAlpha() {
float a;
if (alphaDyn >= 0) {
a = alphaDyn;
} else {
a = alpha;
}
if (parentElement) {
a = (a * parentElement->getAlpha());
}
return a;
}
//!Sets the element's scale
//!\param s scale (1 is 100%)
virtual void setScale(float s) {
scaleX = s;
scaleY = s;
scaleZ = s;
}
//!Sets the element's scale
//!\param s scale (1 is 100%)
virtual void setScaleX(float s) {
scaleX = s;
}
//!Sets the element's scale
//!\param s scale (1 is 100%)
virtual void setScaleY(float s) {
scaleY = s;
}
//!Sets the element's scale
//!\param s scale (1 is 100%)
virtual void setScaleZ(float s) {
scaleZ = s;
}
//!Gets the element's current scale
//!Considers scale, scaleDyn, and the parent element's getScale() value
virtual float getScale() {
float s = 0.5f * (scaleX + scaleY) * scaleDyn;
if (parentElement) {
s *= parentElement->getScale();
}
return s;
}
//!Gets the element's current scale
//!Considers scale, scaleDyn, and the parent element's getScale() value
virtual float getScaleX() {
float s = scaleX * scaleDyn;
if (parentElement) {
s *= parentElement->getScaleX();
}
return s;
}
//!Gets the element's current scale
//!Considers scale, scaleDyn, and the parent element's getScale() value
virtual float getScaleY() {
float s = scaleY * scaleDyn;
if (parentElement) {
s *= parentElement->getScaleY();
}
return s;
}
//!Gets the element's current scale
//!Considers scale, scaleDyn, and the parent element's getScale() value
virtual float getScaleZ() {
float s = scaleZ;
if (parentElement) {
s *= parentElement->getScaleZ();
}
return s;
}
//!Checks whether rumble was requested by the element
//!\return true is rumble was requested, false otherwise
virtual bool isRumbleActive() {
return rumble;
}
//!Sets whether or not the element is requesting a rumble event
//!\param r true if requesting rumble, false if not
virtual void setRumble(bool r) {
rumble = r;
}
//!Set an effect for the element
//!\param e Effect to enable
//!\param a Amount of the effect (usage varies on effect)
//!\param t Target amount of the effect (usage varies on effect)
virtual void setEffect(int32_t e, int32_t a, int32_t t = 0);
//!Sets an effect to be enabled on wiimote cursor over
//!\param e Effect to enable
//!\param a Amount of the effect (usage varies on effect)
//!\param t Target amount of the effect (usage varies on effect)
virtual void setEffectOnOver(int32_t e, int32_t a, int32_t t = 0);
//!Shortcut to SetEffectOnOver(EFFECT_SCALE, 4, 110)
virtual void setEffectGrow() {
setEffectOnOver(EFFECT_SCALE, 4, 110);
}
//!Reset all applied effects
virtual void resetEffects();
//!Gets the current element effects
//!\return element effects
virtual int32_t getEffect() const {
return effects;
}
//!\return true if element animation is on going
virtual bool isAnimated() const {
return (parentElement != 0) && (getEffect() > 0);
}
//!Checks whether the specified coordinates are within the element's boundaries
//!\param x X coordinate
//!\param y Y coordinate
//!\return true if contained within, false otherwise
virtual bool isInside(float x, float y) {
return (x > (this->getCenterX() - getScaleX() * getWidth() * 0.5f)
&& x < (this->getCenterX() + getScaleX() * getWidth() * 0.5f)
&& y > (this->getCenterY() - getScaleY() * getHeight() * 0.5f)
&& y < (this->getCenterY() + getScaleY() * getHeight() * 0.5f));
}
//!Sets the element's position
//!\param x X coordinate
//!\param y Y coordinate
virtual void setPosition(float x, float y) {
xoffset = x;
yoffset = y;
}
//!Sets the element's position
//!\param x X coordinate
//!\param y Y coordinate
//!\param z Z coordinate
virtual void setPosition(float x, float y, float z) {
xoffset = x;
yoffset = y;
zoffset = z;
}
//!Gets whether or not the element is in STATE_SELECTED
//!\return true if selected, false otherwise
virtual int32_t getSelected() {
return -1;
}
//!Sets the element's alignment respective to its parent element
//!Bitwise ALIGN_LEFT | ALIGN_RIGHT | ALIGN_CENTRE, ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE)
//!\param align Alignment
virtual void setAlignment(int32_t a) {
alignment = a;
}
//!Gets the element's alignment
virtual int32_t getAlignment() const {
return alignment;
}
//!Angle of the object
virtual void setAngle(float a) {
angle = a;
}
//!Angle of the object
virtual float getAngle() const {
float r_angle = angle;
if (parentElement) { r_angle += parentElement->getAngle(); }
return r_angle;
}
//!Called constantly to allow the element to respond to the current input data
//!\param t Pointer to a GuiController, containing the current input data from PAD/WPAD/VPAD
virtual void update(GuiController *t) {}
//!Called constantly to redraw the element
virtual void draw(CVideo *v) {}
//!Called constantly to process stuff in the element
virtual void process() {}
//!Updates the element's effects (dynamic values)
//!Called by Draw(), used for animation purposes
virtual void updateEffects();
typedef struct _POINT {
int32_t x;
int32_t y;
} POINT;
enum {
STATE_DEFAULT = 0,
STATE_SELECTED = 0x01,
STATE_CLICKED = 0x02,
STATE_HELD = 0x04,
STATE_OVER = 0x08,
STATE_HIDDEN = 0x10,
STATE_DISABLE_INPUT = 0x20,
STATE_CLICKED_TOUCH = 0x40,
STATE_DISABLED = 0x80
};
//! Switch pointer from control to screen position
POINT PtrToScreen(POINT p) {
//! TODO for 3D
//POINT r = { p.x + getLeft(), p.y + getTop() };
return p;
}
//! Switch pointer screen to control position
POINT PtrToControl(POINT p) {
//! TODO for 3D
//POINT r = { p.x - getLeft(), p.y - getTop() };
return p;
}
//! Signals
sigslot::signal2<GuiElement *, bool> visibleChanged;
sigslot::signal3<GuiElement *, int32_t, int32_t> stateChanged;
sigslot::signal1<GuiElement *> effectFinished;
protected:
bool rumble; //!< Wiimote rumble (on/off) - set to on when this element requests a rumble event
bool visible; //!< Visibility of the element. If false, Draw() is skipped
bool selectable; //!< Whether or not this element selectable (can change to SELECTED state)
bool clickable; //!< Whether or not this element is clickable (can change to CLICKED state)
bool holdable; //!< Whether or not this element is holdable (can change to HELD state)
bool drawOverOnlyWhenSelected; //!< Whether or not this element is holdable (can change to HELD state)
float width; //!< Element width
float height; //!< Element height
float xoffset; //!< Element X offset
float yoffset; //!< Element Y offset
float zoffset; //!< Element Z offset
float alpha; //!< Element alpha value (0-255)
float angle; //!< Angle of the object (0-360)
float scaleX; //!< Element scale (1 = 100%)
float scaleY; //!< Element scale (1 = 100%)
float scaleZ; //!< Element scale (1 = 100%)
int32_t alignment; //!< Horizontal element alignment, respective to parent element
int32_t state[5]; //!< Element state (DEFAULT, SELECTED, CLICKED, DISABLED)
int32_t stateChan; //!< Which controller channel is responsible for the last change in state
GuiElement *parentElement; //!< Parent element
//! TODO: Move me to some Animator class
int32_t xoffsetDyn; //!< Element X offset, dynamic (added to xoffset value for animation effects)
int32_t yoffsetDyn; //!< Element Y offset, dynamic (added to yoffset value for animation effects)
float alphaDyn; //!< Element alpha, dynamic (multiplied by alpha value for blending/fading effects)
float scaleDyn; //!< Element scale, dynamic (multiplied by alpha value for blending/fading effects)
int32_t effects; //!< Currently enabled effect(s). 0 when no effects are enabled
int32_t effectAmount; //!< Effect amount. Used by different effects for different purposes
int32_t effectTarget; //!< Effect target amount. Used by different effects for different purposes
int32_t effectsOver; //!< Effects to enable when wiimote cursor is over this element. Copied to effects variable on over event
int32_t effectAmountOver; //!< EffectAmount to set when wiimote cursor is over this element
int32_t effectTargetOver; //!< EffectTarget to set when wiimote cursor is over this element
};

234
src/gui/GuiFrame.cpp Normal file
View File

@ -0,0 +1,234 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "GuiFrame.h"
GuiFrame::GuiFrame(GuiFrame *p) {
parent = p;
width = 0;
height = 0;
dim = false;
if (parent) {
parent->append(this);
}
}
GuiFrame::GuiFrame(float w, float h, GuiFrame *p) {
parent = p;
width = w;
height = h;
dim = false;
if (parent) {
parent->append(this);
}
}
GuiFrame::~GuiFrame() {
closing(this);
if (parent) {
parent->remove(this);
}
}
void GuiFrame::append(GuiElement *e) {
if (e == NULL) {
return;
}
remove(e);
mutex.lock();
elements.push_back(e);
e->setParent(this);
mutex.unlock();
}
void GuiFrame::insert(GuiElement *e, uint32_t index) {
if (e == NULL || (index >= elements.size())) {
return;
}
remove(e);
mutex.lock();
elements.insert(elements.begin() + index, e);
e->setParent(this);
mutex.unlock();
}
void GuiFrame::remove(GuiElement *e) {
if (e == NULL) {
return;
}
mutex.lock();
for (uint32_t i = 0; i < elements.size(); ++i) {
if (e == elements[i]) {
elements.erase(elements.begin() + i);
break;
}
}
mutex.unlock();
}
void GuiFrame::removeAll() {
mutex.lock();
elements.clear();
mutex.unlock();
}
void GuiFrame::close() {
//Application::instance()->pushForDelete(this);
}
void GuiFrame::dimBackground(bool d) {
dim = d;
}
GuiElement *GuiFrame::getGuiElementAt(uint32_t index) const {
if (index >= elements.size()) {
return NULL;
}
return elements[index];
}
uint32_t GuiFrame::getSize() {
return elements.size();
}
void GuiFrame::resetState() {
GuiElement::resetState();
mutex.lock();
for (uint32_t i = 0; i < elements.size(); ++i) {
elements[i]->resetState();
}
mutex.unlock();
}
void GuiFrame::setState(int32_t s, int32_t c) {
GuiElement::setState(s, c);
mutex.lock();
for (uint32_t i = 0; i < elements.size(); ++i) {
elements[i]->setState(s, c);
}
mutex.unlock();
}
void GuiFrame::clearState(int32_t s, int32_t c) {
GuiElement::clearState(s, c);
mutex.lock();
for (uint32_t i = 0; i < elements.size(); ++i) {
elements[i]->clearState(s, c);
}
mutex.unlock();
}
void GuiFrame::setVisible(bool v) {
visible = v;
mutex.lock();
for (uint32_t i = 0; i < elements.size(); ++i) {
elements[i]->setVisible(v);
}
mutex.unlock();
}
int32_t GuiFrame::getSelected() {
// find selected element
int32_t found = -1;
mutex.lock();
for (uint32_t i = 0; i < elements.size(); ++i) {
if (elements[i]->isStateSet(STATE_SELECTED | STATE_OVER)) {
found = i;
break;
}
}
mutex.unlock();
return found;
}
void GuiFrame::draw(CVideo *v) {
if (!this->isVisible() && parentElement) {
return;
}
if (parentElement && dim == true) {
//GXColor dimColor = (GXColor){0, 0, 0, 0x70};
//Menu_DrawRectangle(0, 0, GetZPosition(), screenwidth,screenheight, &dimColor, false, true);
}
mutex.lock();
//! render appended items next frame but allow stop of render if size is reached
uint32_t size = elements.size();
for (uint32_t i = 0; i < size && i < elements.size(); ++i) {
elements[i]->draw(v);
}
mutex.unlock();
}
void GuiFrame::updateEffects() {
if (!this->isVisible() && parentElement) {
return;
}
GuiElement::updateEffects();
mutex.lock();
//! render appended items next frame but allow stop of render if size is reached
uint32_t size = elements.size();
for (uint32_t i = 0; i < size && i < elements.size(); ++i) {
elements[i]->updateEffects();
}
mutex.unlock();
}
void GuiFrame::process() {
if (!this->isVisible() && parentElement) {
return;
}
GuiElement::process();
mutex.lock();
//! render appended items next frame but allow stop of render if size is reached
uint32_t size = elements.size();
for (uint32_t i = 0; i < size && i < elements.size(); ++i) {
elements[i]->process();
}
mutex.unlock();
}
void GuiFrame::update(GuiController *c) {
if (isStateSet(STATE_DISABLED) && parentElement) {
return;
}
mutex.lock();
//! update appended items next frame
uint32_t size = elements.size();
for (uint32_t i = 0; i < size && i < elements.size(); ++i) {
elements[i]->update(c);
}
mutex.unlock();
}

123
src/gui/GuiFrame.h Normal file
View File

@ -0,0 +1,123 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <vector>
#include <mutex>
#include "GuiElement.h"
#include "sigslot.h"
//!Allows GuiElements to be grouped together into a "window"
class GuiFrame : public GuiElement {
public:
//!Constructor
GuiFrame(GuiFrame *parent = 0);
//!\overload
//!\param w Width of window
//!\param h Height of window
GuiFrame(float w, float h, GuiFrame *parent = 0);
//!Destructor
virtual ~GuiFrame();
//!Appends a GuiElement to the GuiFrame
//!\param e The GuiElement to append. If it is already in the GuiFrame, it is removed first
void append(GuiElement *e);
//!Inserts a GuiElement into the GuiFrame at the specified index
//!\param e The GuiElement to insert. If it is already in the GuiFrame, it is removed first
//!\param i Index in which to insert the element
void insert(GuiElement *e, uint32_t i);
//!Removes the specified GuiElement from the GuiFrame
//!\param e GuiElement to be removed
void remove(GuiElement *e);
//!Removes all GuiElements
void removeAll();
//!Bring element to front of the window
void bringToFront(GuiElement *e) {
remove(e);
append(e);
}
//!Returns the GuiElement at the specified index
//!\param index The index of the element
//!\return A pointer to the element at the index, NULL on error (eg: out of bounds)
GuiElement *getGuiElementAt(uint32_t index) const;
//!Returns the size of the list of elements
//!\return The size of the current element list
uint32_t getSize();
//!Sets the visibility of the window
//!\param v visibility (true = visible)
void setVisible(bool v);
//!Resets the window's state to STATE_DEFAULT
void resetState();
//!Sets the window's state
//!\param s State
void setState(int32_t s, int32_t c = -1);
void clearState(int32_t s, int32_t c = -1);
//!Gets the index of the GuiElement inside the window that is currently selected
//!\return index of selected GuiElement
int32_t getSelected();
//!Dim the Window's background
void dimBackground(bool d);
//!Draws all the elements in this GuiFrame
void draw(CVideo *v);
//!Updates the window and all elements contains within
//!Allows the GuiFrame and all elements to respond to the input data specified
//!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD
void update(GuiController *t);
//!virtual Close Window - this will put the object on the delete queue in MainWindow
virtual void close();
//!virtual show window function
virtual void show() {}
//!virtual hide window function
virtual void hide() {}
//!virtual enter main loop function (blocking)
virtual void exec() {}
//!virtual updateEffects which is called by the main loop
virtual void updateEffects();
//!virtual process which is called by the main loop
virtual void process();
//! Signals
//! On Closing
sigslot::signal1<GuiFrame *> closing;
protected:
bool dim; //! Enable/disable dim of a window only
GuiFrame *parent; //!< Parent Window
std::vector<GuiElement *> elements; //!< Contains all elements within the GuiFrame
std::recursive_mutex mutex;
};

87
src/gui/GuiImage.cpp Normal file
View File

@ -0,0 +1,87 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <SDL2/SDL_image.h>
#include <iostream>
#include "GuiImage.h"
#include "../CVideo.h"
#include "../logger.h"
GuiImage::GuiImage(const std::string& path) {
imgSurface = IMG_Load( path.c_str() );
this->width = imgSurface->w;
this->height = imgSurface->h;
}
/**
* Destructor for the GuiImage class.
*/
GuiImage::~GuiImage() {
if(imgSurface){
SDL_FreeSurface(imgSurface);
imgSurface = NULL;
}
if(texture){
SDL_DestroyTexture(texture);
texture = NULL;
}
}
void GuiImage::process(){
auto res = this->getAngle() + 1;
if(res > 360){
res =0;
}
setAngle(res);
}
void GuiImage::draw(CVideo *pVideo) {
if (!this->isVisible()) {
return;
}
if(texture == NULL){
SDL_Surface * optimizedSurface = SDL_ConvertSurfaceFormat( imgSurface, pVideo->getPixelFormat(), 0 );
if(optimizedSurface != NULL){
SDL_FreeSurface(imgSurface);
imgSurface = optimizedSurface;
DEBUG_FUNCTION_LINE("Optimized surface");
}
texture = SDL_CreateTextureFromSurface(pVideo->getRenderer(), imgSurface);
}
float currScaleX = getScaleX();
float currScaleY = getScaleY();
SDL_Rect rect;
rect.x = getLeft();
rect.y = getTop();
rect.w = currScaleX * getWidth();
rect.h = currScaleY * getHeight();
// copy the texture to the rendering context
if(getAngle() == 0){
SDL_RenderCopy(pVideo->getRenderer(), texture, NULL, &rect);
}else{
SDL_RenderCopyEx(pVideo->getRenderer(), texture, NULL, &rect, getAngle(), NULL, SDL_FLIP_NONE);
}
}

42
src/gui/GuiImage.h Normal file
View File

@ -0,0 +1,42 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <SDL2/SDL_render.h>
#include "GuiElement.h"
#include "glm/glm.hpp"
//!Display, manage, and manipulate images in the GUI
class GuiImage : public GuiElement {
public:
//!\overload
//!\param img Pointer to GuiImageData element
GuiImage(const std::string &path);
//!Destructor
virtual ~GuiImage();
//!Constantly called to draw the image
void draw(CVideo *pVideo);
protected:
SDL_Surface *imgSurface = nullptr;
SDL_Texture *texture = nullptr;
virtual void process();
};

78
src/gui/GuiSound.cpp Normal file
View File

@ -0,0 +1,78 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "GuiSound.h"
#include "../logger.h"
GuiSound::GuiSound(const char *filepath) {
Load(filepath);
}
GuiSound::~GuiSound() {
if(music){
Mix_FreeChunk(music);
}
}
bool GuiSound::Load(const char *filepath) {
music = Mix_LoadWAV(filepath);
DEBUG_FUNCTION_LINE("load %s %d", filepath, music);
return music != nullptr;
}
void GuiSound::Play() {
playedOn = Mix_PlayChannel(-1,music, loops);
}
void GuiSound::Stop() {
Pause();
}
void GuiSound::Pause() {
Mix_HaltChannel(playedOn);
}
void GuiSound::Resume() {
Play();
}
bool GuiSound::IsPlaying() {
if(playedOn == -1){
return false;
}
return Mix_Playing(playedOn);
}
void GuiSound::SetVolume(uint32_t vol) {
if(music != nullptr){
Mix_VolumeChunk(music, vol);
}
}
void GuiSound::SetLoop(bool l) {
if(l){
loops = -1;
}else{
loops = 1;
}
}
void GuiSound::Rewind() {
Stop();
}

65
src/gui/GuiSound.h Normal file
View File

@ -0,0 +1,65 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include "GuiElement.h"
#include <SDL2/SDL_mixer.h>
//!Sound conversion and playback. A wrapper for other sound libraries - ASND, libmad, ltremor, etc
class GuiSound : public GuiElement {
public:
//!Constructor
//!\param sound Pointer to the sound data
//!\param filesize Length of sound data
GuiSound(const char *filepath);
//!Destructor
virtual ~GuiSound();
//!Load a file and replace the old one
bool Load(const char *filepath);
//!Start sound playback
void Play();
//!Stop sound playback
void Stop();
//!Pause sound playback
void Pause();
//!Resume sound playback
void Resume();
//!Checks if the sound is currently playing
//!\return true if sound is playing, false otherwise
bool IsPlaying();
//!Rewind the music
void Rewind();
//!Set sound volume
//!\param v Sound volume (0-100)
void SetVolume(uint32_t v);
//!\param l Loop (true to loop)
void SetLoop(bool l);
Mix_Chunk *music;
int32_t loops = 0;
int32_t playedOn = -1;
};

90
src/gui/GuiText.cpp Normal file
View File

@ -0,0 +1,90 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <cstdarg>
#include <SDl2/SDL_surface.h>
#include "GuiText.h"
#include "../CVideo.h"
#include "../logger.h"
/**
* Constructor for the GuiText class.
*/
GuiText::GuiText(const std::string& text, int32_t s, SDL_Color c, TTF_Font* gFont) {
//Render text surface
textSurface = TTF_RenderText_Solid( gFont, text.c_str(), c );
if( textSurface == NULL ) {
DEBUG_FUNCTION_LINE( "Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError() );
}
}
GuiText::~GuiText(){
if(textSurface){
SDL_FreeSurface( textSurface );
textSurface = nullptr;
}
if(textTexture){
SDL_DestroyTexture( textTexture );
textTexture = nullptr;
}
}
/**
* Draw the text on screen
*/
void GuiText::draw(CVideo *pVideo) {
if (!this->isVisible()) {
return;
}
if(textTexture == NULL){
//Create texture from surface pixels
textTexture = SDL_CreateTextureFromSurface( pVideo->getRenderer(), textSurface );
if( textTexture == NULL ) {
DEBUG_FUNCTION_LINE( "Unable to create texture from rendered text! SDL Error: %s\n", SDL_GetError() );
}else{
width = textSurface->w;
height = textSurface->h;
}
if(textSurface){
SDL_FreeSurface( textSurface );
textSurface = nullptr;
}
}
if(!textTexture){
return;
}
SDL_Rect rect;
rect.x = getLeft();
rect.y = getTop();
rect.w = getScaleX() * getWidth();
rect.h = getScaleY() * getHeight();
// copy the texture to the rendering context
if(getAngle() == 0){
SDL_RenderCopy(pVideo->getRenderer(), textTexture, NULL, &rect);
}else{
SDL_RenderCopyEx(pVideo->getRenderer(), textTexture, NULL, &rect, getAngle(), NULL, SDL_FLIP_NONE);
}
}

40
src/gui/GuiText.h Normal file
View File

@ -0,0 +1,40 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include "GuiElement.h"
#include <mutex>
#include <glm/vec4.hpp>
#include <SDL2/SDL_ttf.h>
//!Display, manage, and manipulate text in the GUI
class GuiText : public GuiElement {
public:
//!\param t Text
//!\param s Font size
//!\param c Font color
GuiText(const std::string &t, int32_t s, SDL_Color c, TTF_Font *gFont);
virtual ~GuiText();
virtual void draw(CVideo *pVideo);
protected:
SDL_Surface *textSurface = nullptr;
SDL_Texture *textTexture = nullptr;
};

145
src/gui/GuiTrigger.cpp Normal file
View File

@ -0,0 +1,145 @@
/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <iostream>
#include "GuiElement.h"
#include "GuiController.h"
#include "GuiTrigger.h"
/**
* Constructor for the GuiTrigger class.
*/
GuiTrigger::GuiTrigger()
: chan(CHANNEL_ALL), btns(BUTTON_NONE), bClickEverywhere(false), bHoldEverywhere(false), bSelectionClickEverywhere(false), bLastTouched(false) {
}
GuiTrigger::GuiTrigger(uint32_t ch, uint32_t btn, bool clickEverywhere, bool holdEverywhere, bool selectionClickEverywhere)
: chan(ch), btns(btn), bClickEverywhere(clickEverywhere), bHoldEverywhere(holdEverywhere), bSelectionClickEverywhere(selectionClickEverywhere), bLastTouched(false) {
}
/**
* Destructor for the GuiTrigger class.
*/
GuiTrigger::~GuiTrigger() {
}
/**
* Sets a simple trigger. Requires:
* - Element is selected
* - Trigger button is pressed
*/
void GuiTrigger::setTrigger(uint32_t ch, uint32_t btn) {
chan = ch;
btns = btn;
}
bool GuiTrigger::left(const GuiController *controller) const {
if ((controller->chan & chan) == 0) {
return false;
}
if ((controller->data.buttons_h | controller->data.buttons_d) & (BUTTON_LEFT | STICK_L_LEFT)) {
return true;
}
return false;
}
bool GuiTrigger::right(const GuiController *controller) const {
if ((controller->chan & chan) == 0) {
return false;
}
if ((controller->data.buttons_h | controller->data.buttons_d) & (BUTTON_RIGHT | STICK_L_RIGHT)) {
return true;
}
return false;
}
bool GuiTrigger::up(const GuiController *controller) const {
if ((controller->chan & chan) == 0) {
return false;
}
if ((controller->data.buttons_h | controller->data.buttons_d) & (BUTTON_UP | STICK_L_UP)) {
return true;
}
return false;
}
bool GuiTrigger::down(const GuiController *controller) const {
if ((controller->chan & chan) == 0) {
return false;
}
if ((controller->data.buttons_h | controller->data.buttons_d) & (BUTTON_DOWN | STICK_L_DOWN)) {
return true;
}
return false;
}
int32_t GuiTrigger::clicked(const GuiController *controller) const {
if ((controller->chan & chan) == 0) {
return CLICKED_NONE;
}
int32_t bResult = CLICKED_NONE;
if (controller->data.touched && controller->data.validPointer && (btns & TOUCHED) && !controller->lastData.touched) {
bResult = CLICKED_TOUCH;
}
if (controller->data.buttons_d & btns) {
bResult = CLICKED_BUTTON;
}
return bResult;
}
bool GuiTrigger::held(const GuiController *controller) const {
if ((controller->chan & chan) == 0) {
return false;
}
bool bResult = false;
if (controller->data.touched && (btns & TOUCHED) && controller->data.validPointer && controller->lastData.touched && controller->lastData.validPointer) {
bResult = true;
}
if (controller->data.buttons_h & btns) {
bResult = true;
}
return bResult;
}
bool GuiTrigger::released(const GuiController *controller) const {
if ((controller->chan & chan) == 0) {
return false;
}
if (clicked(controller) || held(controller)) {
return false;
}
bool bResult = false;
if (!controller->data.touched && (btns & TOUCHED) && controller->lastData.touched && controller->lastData.validPointer) {
bResult = true;
}
if (controller->data.buttons_r & btns) {
bResult = true;
}
return bResult;
}

132
src/gui/GuiTrigger.h Normal file
View File

@ -0,0 +1,132 @@
/***************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#pragma once
#include <stdint.h>
class GuiController;
//!Menu input trigger management. Determine if action is neccessary based on input data by comparing controller input data to a specific trigger element.
class GuiTrigger {
public:
enum eClicked {
CLICKED_NONE = 0x00,
CLICKED_TOUCH = 0x01,
CLICKED_BUTTON = 0x02,
};
enum eChannels {
CHANNEL_1 = 0x01,
CHANNEL_2 = 0x02,
CHANNEL_3 = 0x04,
CHANNEL_4 = 0x08,
CHANNEL_5 = 0x10,
CHANNEL_ALL = 0xFF
};
enum eButtons {
BUTTON_NONE = 0x0000,
TOUCHED = 0x80000000,
VPAD_TOUCH = TOUCHED,
BUTTON_Z = 0x20000,
BUTTON_C = 0x10000,
BUTTON_A = 0x8000,
BUTTON_B = 0x4000,
BUTTON_X = 0x2000,
BUTTON_Y = 0x1000,
BUTTON_1 = BUTTON_Y,
BUTTON_2 = BUTTON_X,
BUTTON_LEFT = 0x0800,
BUTTON_RIGHT = 0x0400,
BUTTON_UP = 0x0200,
BUTTON_DOWN = 0x0100,
BUTTON_ZL = 0x0080,
BUTTON_ZR = 0x0040,
BUTTON_L = 0x0020,
BUTTON_R = 0x0010,
BUTTON_PLUS = 0x0008,
BUTTON_MINUS = 0x0004,
BUTTON_HOME = 0x0002,
BUTTON_SYNC = 0x0001,
STICK_R_LEFT = 0x04000000,
STICK_R_RIGHT = 0x02000000,
STICK_R_UP = 0x01000000,
STICK_R_DOWN = 0x00800000,
STICK_L_LEFT = 0x40000000,
STICK_L_RIGHT = 0x20000000,
STICK_L_UP = 0x10000000,
STICK_L_DOWN = 0x08000000,
BUTTON_STICK_L = BUTTON_Z,
BUTTON_STICK_R = BUTTON_C,
};
//!Constructor
GuiTrigger();
//!Constructor
GuiTrigger(uint32_t ch, uint32_t btns, bool clickEverywhere = false, bool holdEverywhere = false, bool selectionClickEverywhere = false);
//!Destructor
virtual ~GuiTrigger();
//!Sets a simple trigger. Requires: element is selected, and trigger button is pressed
void setTrigger(uint32_t ch, uint32_t btns);
void setClickEverywhere(bool b) {
bClickEverywhere = b;
}
void setHoldOnly(bool b) {
bHoldEverywhere = b;
}
void setSelectionClickEverywhere(bool b) {
bSelectionClickEverywhere = b;
}
bool isClickEverywhere() const {
return bClickEverywhere;
}
bool isHoldEverywhere() const {
return bHoldEverywhere;
}
bool isSelectionClickEverywhere() const {
return bSelectionClickEverywhere;
}
bool left(const GuiController *controller) const;
bool right(const GuiController *controller) const;
bool up(const GuiController *controller) const;
bool down(const GuiController *controller) const;
int32_t clicked(const GuiController *controller) const;
bool held(const GuiController *controller) const;
bool released(const GuiController *controller) const;
private:
uint32_t chan;
uint32_t btns;
bool bClickEverywhere;
bool bHoldEverywhere;
bool bSelectionClickEverywhere;
bool bLastTouched;
};

60
src/gui/SDLController.h Normal file
View File

@ -0,0 +1,60 @@
#pragma once
#include <SDL2/SDL_mouse.h>
#include <iostream>
#include <SDL2/SDL_events.h>
#include "GuiController.h"
#include "../logger.h"
#define printButton(chan, x) if(data.buttons_d & x) DEBUG_FUNCTION_LINE("Controller #%d %s", chan, #x)
class SDLController : public GuiController {
public:
SDLController(int32_t channel) : GuiController(channel) {
}
virtual bool update(SDL_Event *e) = 0;
virtual void before() {
lastData = data;
data.buttons_d = 0;
data.buttons_r = 0;
}
virtual void after() {
data.buttons_d |= (data.buttons_h & (~(lastData.buttons_h)));
data.buttons_r |= ((lastData.buttons_h) & (~data.buttons_h));
if (data.buttons_h != 0 || data.buttons_d != 0 || data.buttons_r != 0) {
// DEBUG_FUNCTION_LINE("Controller #%d: h %08X d %08X r %08X", chanIdx, data.buttons_h, data.buttons_d, data.buttons_r);
printButton(chanIdx, GuiTrigger::BUTTON_A);
printButton(chanIdx, GuiTrigger::BUTTON_B);
printButton(chanIdx, GuiTrigger::BUTTON_X);
printButton(chanIdx, GuiTrigger::BUTTON_Y);
printButton(chanIdx, GuiTrigger::BUTTON_STICK_L);
printButton(chanIdx, GuiTrigger::BUTTON_STICK_R);
printButton(chanIdx, GuiTrigger::BUTTON_L);
printButton(chanIdx, GuiTrigger::BUTTON_R);
printButton(chanIdx, GuiTrigger::BUTTON_ZL);
printButton(chanIdx, GuiTrigger::BUTTON_ZR);
printButton(chanIdx, GuiTrigger::BUTTON_PLUS);
printButton(chanIdx, GuiTrigger::BUTTON_MINUS);
printButton(chanIdx, GuiTrigger::BUTTON_LEFT);
printButton(chanIdx, GuiTrigger::BUTTON_UP);
printButton(chanIdx, GuiTrigger::BUTTON_RIGHT);
printButton(chanIdx, GuiTrigger::BUTTON_DOWN);
printButton(chanIdx, GuiTrigger::STICK_L_LEFT);
printButton(chanIdx, GuiTrigger::STICK_L_UP);
printButton(chanIdx, GuiTrigger::STICK_L_RIGHT);
printButton(chanIdx, GuiTrigger::STICK_L_DOWN);
printButton(chanIdx, GuiTrigger::STICK_R_LEFT);
printButton(chanIdx, GuiTrigger::STICK_R_UP);
printButton(chanIdx, GuiTrigger::STICK_R_RIGHT);
printButton(chanIdx, GuiTrigger::STICK_R_DOWN);
printButton(chanIdx, GuiTrigger::TOUCHED);
}
}
};

View File

@ -0,0 +1,58 @@
#pragma once
class SDLControllerJoystick : public SDLController {
public:
SDLControllerJoystick(int32_t channel, SDL_JoystickID joystickId) : SDLController(channel) {
}
virtual bool update(SDL_Event *e) override {
if (e->type == SDL_JOYBUTTONDOWN) {
data.buttons_h |= (1 << e->jbutton.button);
} else if (e->type == SDL_JOYBUTTONUP) {
data.buttons_h &= ~(1 << e->jbutton.button);
} else if (e->type == SDL_JOYHATMOTION) {
auto val = e->jhat.value;
auto hatMask = (GuiTrigger::BUTTON_LEFT | GuiTrigger::BUTTON_UP | GuiTrigger::BUTTON_DOWN | GuiTrigger::BUTTON_RIGHT);
// Remove hat values so we can add the new value.
data.buttons_h &= ~hatMask;
switch (val) {
case SDL_HAT_LEFTUP:
data.buttons_h |= GuiTrigger::BUTTON_LEFT;
data.buttons_h |= GuiTrigger::BUTTON_UP;
break;
case SDL_HAT_LEFT:
data.buttons_h |= GuiTrigger::BUTTON_LEFT;
break;
case SDL_HAT_LEFTDOWN:
data.buttons_h |= GuiTrigger::BUTTON_LEFT;
data.buttons_h |= GuiTrigger::BUTTON_DOWN;
break;
case SDL_HAT_UP:
data.buttons_h |= GuiTrigger::BUTTON_UP;
break;
case SDL_HAT_DOWN:
data.buttons_h |= GuiTrigger::BUTTON_DOWN;
break;
case SDL_HAT_RIGHTUP:
data.buttons_h |= GuiTrigger::BUTTON_RIGHT;
data.buttons_h |= GuiTrigger::BUTTON_UP;
break;
case SDL_HAT_RIGHT:
data.buttons_h |= GuiTrigger::BUTTON_RIGHT;
break;
case SDL_HAT_RIGHTDOWN:
data.buttons_h |= GuiTrigger::BUTTON_RIGHT;
data.buttons_h |= GuiTrigger::BUTTON_DOWN;
break;
}
} else if (e->type == SDL_JOYAXISMOTION) {
//
}
return true;
}
};

View File

@ -0,0 +1,26 @@
#pragma once
class SDLControllerMouse: public SDLController {
public:
SDLControllerMouse(int32_t channel) : SDLController(channel) {
}
virtual bool update(SDL_Event *e) override {
if (e->type == SDL_MOUSEMOTION) {
data.y = e->motion.y;
data.x = e->motion.x;
data.validPointer = true;
} else if (e->type == SDL_MOUSEBUTTONDOWN && e->button.button == SDL_BUTTON_LEFT) {
data.buttons_h |= GuiTrigger::TOUCHED;
} else if (e->type == SDL_MOUSEBUTTONUP && e->button.button == SDL_BUTTON_LEFT) {
data.buttons_h &= ~GuiTrigger::TOUCHED;
}else{
DEBUG_FUNCTION_LINE("Unknown event");
return false;
}
return true;
}
};

View File

@ -0,0 +1,51 @@
#pragma once
#pragma once
#include "SDLController.h"
static GuiTrigger::eButtons vpad_button_map[] = {
GuiTrigger::BUTTON_A,
GuiTrigger::BUTTON_B,
GuiTrigger::BUTTON_X,
GuiTrigger::BUTTON_Y,
GuiTrigger::BUTTON_STICK_L, GuiTrigger::BUTTON_STICK_R,
GuiTrigger::BUTTON_L, GuiTrigger::BUTTON_R,
GuiTrigger::BUTTON_ZL, GuiTrigger::BUTTON_ZR,
GuiTrigger::BUTTON_PLUS, GuiTrigger::BUTTON_MINUS,
GuiTrigger::BUTTON_LEFT, GuiTrigger::BUTTON_UP, GuiTrigger::BUTTON_RIGHT, GuiTrigger::BUTTON_DOWN,
GuiTrigger::STICK_L_LEFT, GuiTrigger::STICK_L_UP, GuiTrigger::STICK_L_RIGHT, GuiTrigger::STICK_L_DOWN,
GuiTrigger::STICK_R_LEFT, GuiTrigger::STICK_R_UP, GuiTrigger::STICK_R_RIGHT, GuiTrigger::STICK_R_DOWN,
};
class SDLControllerWiiUGamepad : public SDLController {
public:
SDLControllerWiiUGamepad(int32_t channel) : SDLController(channel) {
}
virtual bool update(SDL_Event *e) override {
if (e->type == SDL_FINGERMOTION) {
data.y = e->tfinger.y * 720;
data.x = e->tfinger.x * 1280;;
data.validPointer = true;
} else if (e->type == SDL_FINGERUP) {
data.validPointer = false;
data.buttons_h &= ~GuiTrigger::TOUCHED;
} else if (e->type == SDL_FINGERDOWN) {
data.validPointer = true;
data.buttons_h |= GuiTrigger::TOUCHED;
}
if (e->type == SDL_JOYBUTTONDOWN) {
data.buttons_h |= vpad_button_map[e->jbutton.button];
} else if (e->type == SDL_JOYBUTTONUP) {
data.buttons_h &= ~vpad_button_map[e->jbutton.button];
} else {
DEBUG_FUNCTION_LINE("Unknown event");
return false;
}
return true;
}
};

View File

@ -0,0 +1,11 @@
#pragma once
#include "SDLControllerWiiUGamepad.h"
class SDLControllerWiiUProContoller : public SDLControllerWiiUGamepad {
public:
SDLControllerWiiUProContoller(int32_t channel) : SDLControllerWiiUGamepad(channel){
}
};

View File

@ -0,0 +1,106 @@
#pragma once
#include "SDLController.h"
static GuiTrigger::eButtons xbox_button_map[] =
{
GuiTrigger::BUTTON_A,
GuiTrigger::BUTTON_B,
GuiTrigger::BUTTON_X,
GuiTrigger::BUTTON_Y,
GuiTrigger::BUTTON_L,
GuiTrigger::BUTTON_R,
GuiTrigger::BUTTON_MINUS,
GuiTrigger::BUTTON_PLUS,
GuiTrigger::BUTTON_STICK_L,
GuiTrigger::BUTTON_STICK_R,
};
#define getDigitalAxis(axis, targetAxis, value, hold, first, second) \
if(axis == targetAxis){ \
if (value < 0x4000 && value > -0x4000){ \
hold &= ~first; \
hold &= ~second; \
}else if(value < -0x4000){ \
hold |= first; \
hold &= ~second; \
}else if(value > 0x4000){ \
hold |= second; \
hold &= ~first; \
} \
} \
#define getDigitalTrigger(axis, targetAxis, value, hold, first) \
if(axis == targetAxis){ \
if(value > 0){ \
hold |= first; \
}else{ \
hold &= ~first; \
} \
} \
class SDLControllerXboxOne : public SDLController {
public:
SDLControllerXboxOne(int32_t channel) : SDLController(channel) {
}
virtual bool update(SDL_Event *e) override {
if (e->type == SDL_JOYBUTTONDOWN) {
data.buttons_h |= xbox_button_map[e->jbutton.button];
} else if (e->type == SDL_JOYBUTTONUP) {
data.buttons_h &= ~xbox_button_map[e->jbutton.button];
} else if (e->type == SDL_JOYHATMOTION) {
auto val = e->jhat.value;
auto hatMask = (GuiTrigger::BUTTON_LEFT | GuiTrigger::BUTTON_UP | GuiTrigger::BUTTON_DOWN | GuiTrigger::BUTTON_RIGHT);
// Remove hat values so we can add the new values.
data.buttons_h &= ~hatMask;
switch (val) {
case SDL_HAT_LEFTUP:
data.buttons_h |= GuiTrigger::BUTTON_LEFT;
data.buttons_h |= GuiTrigger::BUTTON_UP;
break;
case SDL_HAT_LEFT:
data.buttons_h |= GuiTrigger::BUTTON_LEFT;
break;
case SDL_HAT_LEFTDOWN:
data.buttons_h |= GuiTrigger::BUTTON_LEFT;
data.buttons_h |= GuiTrigger::BUTTON_DOWN;
break;
case SDL_HAT_UP:
data.buttons_h |= GuiTrigger::BUTTON_UP;
break;
case SDL_HAT_DOWN:
data.buttons_h |= GuiTrigger::BUTTON_DOWN;
break;
case SDL_HAT_RIGHTUP:
data.buttons_h |= GuiTrigger::BUTTON_RIGHT;
data.buttons_h |= GuiTrigger::BUTTON_UP;
break;
case SDL_HAT_RIGHT:
data.buttons_h |= GuiTrigger::BUTTON_RIGHT;
break;
case SDL_HAT_RIGHTDOWN:
data.buttons_h |= GuiTrigger::BUTTON_RIGHT;
data.buttons_h |= GuiTrigger::BUTTON_DOWN;
break;
}
} else if (e->type == SDL_JOYAXISMOTION) {
getDigitalTrigger(e->jaxis.axis, 2, e->jaxis.value, data.buttons_h, GuiTrigger::BUTTON_ZL);
getDigitalTrigger(e->jaxis.axis, 5, e->jaxis.value, data.buttons_h, GuiTrigger::BUTTON_ZR);
getDigitalAxis(e->jaxis.axis, 0, e->jaxis.value, data.buttons_h, GuiTrigger::STICK_L_LEFT, GuiTrigger::STICK_L_RIGHT);
getDigitalAxis(e->jaxis.axis, 1, e->jaxis.value, data.buttons_h, GuiTrigger::STICK_L_UP, GuiTrigger::STICK_L_DOWN);
getDigitalAxis(e->jaxis.axis, 3, e->jaxis.value, data.buttons_h, GuiTrigger::STICK_R_LEFT, GuiTrigger::STICK_R_RIGHT);
getDigitalAxis(e->jaxis.axis, 4, e->jaxis.value, data.buttons_h, GuiTrigger::STICK_R_UP, GuiTrigger::STICK_R_DOWN);
} else {
DEBUG_FUNCTION_LINE("Unknown event");
return false;
}
return true;
}
};

2433
src/gui/sigslot.h Normal file

File diff suppressed because it is too large Load Diff

32
src/logger.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#ifdef __WIIU__
#include <whb/log.h>
#include <whb/log_cafe.h>
#include <whb/log_udp.h>
#include <whb/log.h>
#endif
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
#ifdef __WIIU__
#define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
} while (0)
#else
#define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \
printf("[%23s]%30s@L%04d: " FMT "\n",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
} while (0)
#endif
#ifdef __cplusplus
}
#endif

237
src/main.cpp Normal file
View File

@ -0,0 +1,237 @@
#include <SDL2/SDL.h>
#include "CVideo.h"
#include "gui/GuiFrame.h"
#include "gui/GuiImage.h"
#include "gui/GuiButton.h"
#include "gui/GuiController.h"
#include "gui/SDLController.h"
#include "MainWindow.h"
#include "logger.h"
#include "gui/SDLControllerJoystick.h"
#include "gui/SDLControllerMouse.h"
#include "gui/SDLControllerWiiUGamepad.h"
#include "gui/SDLControllerXboxOne.h"
#include "gui/SDLControllerWiiUProContoller.h"
#include <stdio.h>
#include <fcntl.h>
#include <map>
#if defined _WIN32
#include <windows.h>
#endif
#ifdef __WIIU__
#include <whb/log.h>
#include <whb/log_cafe.h>
#include <whb/log_udp.h>
#include <proc_ui/procui.h>
bool CheckRunning(){
switch(ProcUIProcessMessages(true))
{
case PROCUI_STATUS_EXITING:
{
return false;
}
case PROCUI_STATUS_RELEASE_FOREGROUND:
{
ProcUIDrawDoneRelease();
break;
}
case PROCUI_STATUS_IN_FOREGROUND:
{
break;
}
case PROCUI_STATUS_IN_BACKGROUND:
default:
break;
}
return true;
}
#endif
void proccessEvents();
bool addJoystick(int deviceId, std::map<GuiTrigger::eChannels, SDLController *> &controllerList, std::map<int32_t, GuiTrigger::eChannels>& map);
GuiTrigger::eChannels increaseChannel(GuiTrigger::eChannels channel);
void removeJoystick(int32_t which, std::map<GuiTrigger::eChannels, SDLController *> &controllerList, std::map<int32_t, GuiTrigger::eChannels>& joystickToChannel);
int main(int argc, char *args[]) {
CVideo *video = new CVideo();
#if defined _WIN32
// Create the Console
AllocConsole();
// Create Console Output Handle
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
int hCrt = _open_osfhandle((intptr_t) handle_out, _O_TEXT);
FILE *hf_out = _fdopen(hCrt, "w");
setvbuf(hf_out, NULL, _IONBF, 1);
*stdout = *hf_out;
// Create Console Input Handle
HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE);
hCrt = _open_osfhandle((intptr_t) handle_in, _O_TEXT);
FILE *hf_in = _fdopen(hCrt, "r");
setvbuf(hf_in, NULL, _IONBF, 128);
*stdin = *hf_in;
#elif __WIIU__
WHBLogUdpInit();
#endif
GuiFrame *frame = new MainWindow(video->getWidth(), video->getHeight());
std::map<GuiTrigger::eChannels, SDLController*> controllerList;
std::map<int32_t , GuiTrigger::eChannels> joystickToChannel;
#if defined _WIN32
controllerList[GuiTrigger::CHANNEL_1] = new SDLControllerMouse(GuiTrigger::CHANNEL_1);
DEBUG_FUNCTION_LINE("Add mouse");
#endif
while (true) {
#ifdef __WIIU__
if(!CheckRunning()){
exit(0);
break;
}
#endif
//! Read out inputs
for( auto const& [channel, controller] : controllerList ){
controller->before();
}
bool quit = false;
SDL_Event e;
while (SDL_PollEvent(&e)) {
SDL_JoystickID jId = -1;
if(e.type == SDL_JOYDEVICEADDED) {
addJoystick(e.jdevice.which, controllerList, joystickToChannel);
}else if(e.type == SDL_JOYDEVICEREMOVED) {
auto j = SDL_JoystickFromInstanceID(e.jdevice.which);
if (j) {
removeJoystick(e.jdevice.which, controllerList, joystickToChannel);
SDL_JoystickClose(j);
}
}else if (e.type == SDL_FINGERDOWN || e.type == SDL_FINGERUP || e.type == SDL_FINGERMOTION){
controllerList[GuiTrigger::CHANNEL_1]->update(&e);
} else if (e.type == SDL_MOUSEBUTTONDOWN || e.type == SDL_MOUSEBUTTONUP || e.type == SDL_MOUSEMOTION){
controllerList[GuiTrigger::CHANNEL_1]->update(&e);
} else if (e.type == SDL_JOYAXISMOTION) {
jId = e.jaxis.which;
} else if (e.type == SDL_JOYHATMOTION) {
jId = e.jhat.which;
}else if (e.type == SDL_JOYBUTTONDOWN || e.type == SDL_JOYBUTTONUP) {
jId = e.jbutton.which;
} else if (e.type == SDL_QUIT || (e.type == SDL_KEYUP && e.key.keysym.sym == SDLK_ESCAPE)) {
quit = true;
break;
}
if(jId != -1){
if(joystickToChannel.find(jId) != joystickToChannel.end()){
controllerList[joystickToChannel[jId]]->update(&e);
}
}
}
if(quit){
break;
}
for( auto const& [joypad, controller] : controllerList ){
controller->after();
frame->update(controller);
}
frame->process();
// clear the screen
SDL_RenderClear(video->getRenderer());
frame->draw(video);
frame->updateEffects();
// flip the backbuffer
// this means that everything that we prepared behind the screens is actually shown
SDL_RenderPresent(video->getRenderer());
}
delete frame;
return 0;
}
void removeJoystick(int32_t instanceId, std::map<GuiTrigger::eChannels, SDLController *> &controllerList, std::map<int32_t, GuiTrigger::eChannels>& joystickToChannel) {
auto channel = joystickToChannel[instanceId];
delete controllerList[channel];
controllerList.erase(channel);
joystickToChannel.erase(instanceId);
DEBUG_FUNCTION_LINE("Removed joystick: %d", instanceId);
}
bool addJoystick(int deviceId, std::map<GuiTrigger::eChannels, SDLController *> &controllerList, std::map<int32_t, GuiTrigger::eChannels>& joystickToChannel) {
auto joystick = SDL_JoystickOpen(deviceId);
if (joystick == NULL){
DEBUG_FUNCTION_LINE("SDL_JoystickOpen failed: %s\n", SDL_GetError());
return false;
}
auto instanceId = SDL_JoystickInstanceID(joystick);
if(std::string("WiiU Gamepad").compare(SDL_JoystickName(joystick)) == 0){
controllerList[GuiTrigger::CHANNEL_1] = new SDLControllerWiiUGamepad(GuiTrigger::CHANNEL_1);
joystickToChannel[instanceId] = GuiTrigger::CHANNEL_1;
}else {
bool successfully_added = false;
auto channel = GuiTrigger::CHANNEL_2;
while(channel != GuiTrigger::CHANNEL_ALL){
if(controllerList.find(channel) == controllerList.end()) {
if (std::string(SDL_JoystickName(joystick)).find("Xbox") != std::string::npos){
controllerList[channel] = new SDLControllerXboxOne(channel);
}else if(std::string(SDL_JoystickName(joystick)).find("WiiU Pro Controller") != std::string::npos) {
controllerList[channel] = new SDLControllerWiiUProContoller(channel);
}else{
controllerList[channel] = new SDLControllerJoystick(channel, instanceId);
}
joystickToChannel[instanceId] = channel;
successfully_added = true;
break;
}
channel = increaseChannel(channel);
}
if(!successfully_added){
DEBUG_FUNCTION_LINE("Failed to add joystick. Closing it now");
SDL_JoystickClose(joystick);
return false;
}
}
DEBUG_FUNCTION_LINE("Added joystick %s", SDL_JoystickName(joystick));
return true;
}
GuiTrigger::eChannels increaseChannel(GuiTrigger::eChannels channel) {
switch(channel){
case GuiTrigger::CHANNEL_1:
return GuiTrigger::CHANNEL_2;
case GuiTrigger::CHANNEL_2:
return GuiTrigger::CHANNEL_3;
case GuiTrigger::CHANNEL_3:
return GuiTrigger::CHANNEL_4;
case GuiTrigger::CHANNEL_4:
return GuiTrigger::CHANNEL_5;
}
return GuiTrigger::CHANNEL_ALL;
}
void proccessEvents() {
int res = 0;
}