Directly use files from libgui

This commit is contained in:
Maschell 2024-07-27 14:25:01 +02:00
parent 485d339c51
commit 69c3327ad5
95 changed files with 14750 additions and 129 deletions

View File

@ -1,5 +1,3 @@
FROM wiiuenv/devkitppc:20211229
COPY --from=wiiuenv/libgui:20220109 /artifacts $DEVKITPRO
FROM ghcr.io/wiiu-env/devkitppc:20240704
WORKDIR project

View File

@ -25,8 +25,11 @@ SOURCES := src \
src/gui \
src/menu \
src/resources \
src/sounds \
src/system \
src/utils
src/utils \
src/video \
src/video/shaders
DATA := data \
data/images \
data/sounds \
@ -46,7 +49,7 @@ CXXFLAGS := $(CFLAGS)
ASFLAGS := -g $(ARCH)
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map)
LIBS := -lgui -lfreetype -lgd -lpng -ljpeg -lz -lmad -lvorbisidec -logg -lbz2 -lwut
LIBS := -lfreetype -lgd -lpng -ljpeg -lz -lmad -lvorbisidec -logg -lbz2 -lwut
#-------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level
@ -105,7 +108,7 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD))
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#-------------------------------------------------------------------------------

View File

@ -25,8 +25,8 @@
#include <gui/VPadController.h>
#include <gui/WPadController.h>
#include "resources/Resources.h"
#include <gui/sounds/SoundHandler.hpp>
#include <gui/memory.h>
#include <sounds/SoundHandler.hpp>
#include "system/memory.h"
#include "utils/logger.h"
#include "utils/AsyncExecutor.h"
#include <thread>

View File

@ -18,7 +18,7 @@
#define _APPLICATION_H
#include "menu/MainWindow.h"
#include <gui/video/CVideo.h>
#include <video/CVideo.h>
#include "system/CThread.h"
// forward declaration

143
src/StorageUtils.cpp Normal file
View File

@ -0,0 +1,143 @@
#include <cstdlib>
#include <malloc.h>
#include "utils/logger.h"
#include "StorageUtils.h"
#include <coreinit/thread.h>
#include <coreinit/title.h>
#include <nn/acp/save.h>
#include <nn/spm.h>
#include <nsysuhs/uhs.h>
#include <sysapp/title.h>
static void InitEmptyExternalStorage() {
DEBUG_FUNCTION_LINE("Fallback to empty ExtendedStorage");
nn::spm::VolumeId empty{};
nn::spm::SetDefaultExtendedStorageVolumeId(empty);
nn::spm::StorageIndex storageIndex = 0;
nn::spm::SetExtendedStorage(&storageIndex);
}
static int numberUSBStorageDevicesConnected() {
DEBUG_FUNCTION_LINE("Check if USB Storage is connected");
auto *handle = (UhsHandle *) memalign(0x40, sizeof(UhsHandle));
if (!handle) {
return -1;
}
memset(handle, 0, sizeof(UhsHandle));
auto *config = (UhsConfig *) memalign(0x40, sizeof(UhsConfig));
if (!config) {
free(handle);
return -2;
}
memset(config, 0, sizeof(UhsConfig));
config->controller_num = 0;
uint32_t size = 5120;
void *buffer = memalign(0x40, size);
if (!buffer) {
free(handle);
free(config);
return -3;
}
memset(buffer, 0, size);
config->buffer = buffer;
config->buffer_size = size;
if (UhsClientOpen(handle, config) != UHS_STATUS_OK) {
DEBUG_FUNCTION_LINE("UhsClient failed");
free(handle);
free(config);
free(buffer);
return -4;
}
UhsInterfaceProfile profiles[10];
UhsInterfaceFilter filter = {
.match_params = MATCH_ANY};
UHSStatus result;
if ((result = UhsQueryInterfaces(handle, &filter, profiles, 10)) <= UHS_STATUS_OK) {
DEBUG_FUNCTION_LINE("UhsQueryInterfaces failed");
UhsClientClose(handle);
free(handle);
free(config);
free(buffer);
return -5;
}
auto found = 0;
for (int i = 0; i < (int) result; i++) {
if (profiles[i].if_desc.bInterfaceClass == USBCLASS_STORAGE) {
DEBUG_FUNCTION_LINE("Found USBCLASS_STORAGE");
found++;
}
}
UhsClientClose(handle);
free(handle);
free(config);
free(buffer);
return found;
}
void initExternalStorage() {
if (OSGetTitleID() == _SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_MII_MAKER)) {
// nn::spm functions always call OSFatal when they fail, so we make sure have permission to use
// the lib before actually using it.
return;
}
int connectedStorage = 0;
if ((connectedStorage = numberUSBStorageDevicesConnected()) <= 0) {
nn::spm::Initialize();
InitEmptyExternalStorage();
nn::spm::Finalize();
return;
}
DEBUG_FUNCTION_LINE("Connected StorageDevices = %d", connectedStorage);
nn::spm::Initialize();
nn::spm::StorageListItem items[0x20];
int tries = 0;
bool found = false;
while (tries < 1200) { // Wait up to 20 seconds, like the Wii U Menu
int32_t numItems = nn::spm::GetStorageList(items, 0x20);
DEBUG_FUNCTION_LINE("Number of items: %d", numItems);
for (int32_t i = 0; i < numItems; i++) {
if (items[i].type == nn::spm::STORAGE_TYPE_WFS) {
nn::spm::StorageInfo info{};
if (nn::spm::GetStorageInfo(&info, &items[i].index) == 0) {
DEBUG_FUNCTION_LINE("Using %s for extended storage", info.path);
nn::spm::SetExtendedStorage(&items[i].index);
ACPMountExternalStorage();
nn::spm::SetDefaultExtendedStorageVolumeId(info.volumeId);
found = true;
break;
}
}
}
if (found || (connectedStorage == numItems)) {
DEBUG_FUNCTION_LINE("Found all expected items, breaking.");
break;
}
OSSleepTicks(OSMillisecondsToTicks(16));
tries++;
}
if (!found) {
DEBUG_FUNCTION_LINE("USB Storage is connected but either it doesn't have a WFS partition or we ran into a timeout.");
InitEmptyExternalStorage();
}
nn::spm::Finalize();
}

3
src/StorageUtils.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
void initExternalStorage();

View File

@ -4,6 +4,7 @@
#include <whb/log_module.h>
#include "utils/logger.h"
#include "Application.h"
#include "StorageUtils.h"
int32_t main(int32_t argc, char **argv) {
bool moduleInit;
@ -14,8 +15,11 @@ int32_t main(int32_t argc, char **argv) {
cafeInit = WHBLogCafeInit();
udpInit = WHBLogUdpInit();
}
DEBUG_FUNCTION_LINE("Starting launchiine " LAUNCHIINE_VERSION "");
initExternalStorage();
DEBUG_FUNCTION_LINE("Start main application");
Application::instance()->exec();

View File

@ -1,13 +1,13 @@
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <fs/CFile.hpp>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
CFile::CFile() {
iFd = -1;
mem_file = nullptr;
mem_file = NULL;
filesize = 0;
pos = 0;
}
@ -54,8 +54,9 @@ int32_t CFile::open(const std::string &filepath, eOpenTypes mode) {
//! the .data sections which is needed for a normal application to re-init
//! this will be added with launching as RPX
iFd = ::open(filepath.c_str(), openMode);
if (iFd < 0)
if (iFd < 0) {
return iFd;
}
filesize = ::lseek(iFd, 0, SEEK_END);
@ -74,11 +75,12 @@ int32_t CFile::open(const uint8_t *mem, int32_t size) {
}
void CFile::close() {
if (iFd >= 0)
if (iFd >= 0) {
::close(iFd);
}
iFd = -1;
mem_file = nullptr;
mem_file = NULL;
filesize = 0;
pos = 0;
}
@ -86,20 +88,23 @@ void CFile::close() {
int32_t CFile::read(uint8_t *ptr, size_t size) {
if (iFd >= 0) {
int32_t ret = ::read(iFd, ptr, size);
if (ret > 0)
if (ret > 0) {
pos += ret;
}
return ret;
}
int32_t readsize = size;
if (readsize > (int64_t) (filesize - pos))
if (readsize > (int64_t) (filesize - pos)) {
readsize = filesize - pos;
}
if (readsize <= 0)
if (readsize <= 0) {
return readsize;
}
if (mem_file != nullptr) {
if (mem_file != NULL) {
memcpy(ptr, mem_file + pos, readsize);
pos += readsize;
return readsize;
@ -113,8 +118,9 @@ int32_t CFile::write(const uint8_t *ptr, size_t size) {
size_t done = 0;
while (done < size) {
int32_t ret = ::write(iFd, ptr, size - done);
if (ret <= 0)
if (ret <= 0) {
return ret;
}
ptr += ret;
done += ret;
@ -144,10 +150,11 @@ int32_t CFile::seek(long int offset, int32_t origin) {
pos = newPos;
}
if (iFd >= 0)
if (iFd >= 0) {
ret = ::lseek(iFd, pos, SEEK_SET);
}
if (mem_file != nullptr) {
if (mem_file != NULL) {
if (pos > filesize) {
pos = filesize;
}
@ -171,5 +178,3 @@ int32_t CFile::fwrite(const char *format, ...) {
return result;
}

View File

@ -1,10 +1,10 @@
#ifndef CFILE_HPP_
#define CFILE_HPP_
#include <stdio.h>
#include <string>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <unistd.h>
#include <wut_types.h>
@ -30,11 +30,13 @@ public:
int32_t open(const uint8_t *memory, int32_t memsize);
BOOL isOpen() const {
if (iFd >= 0)
if (iFd >= 0) {
return true;
}
if (mem_file)
if (mem_file) {
return true;
}
return false;
}

569
src/gui/FreeTypeGX.cpp Normal file
View File

@ -0,0 +1,569 @@
/*
* FreeTypeGX is a wrapper class for libFreeType which renders a compiled
* FreeType parsable font so a GX texture for Wii homebrew development.
* Copyright (C) 2008 Armin Tamzarian
* Modified by Dimok, 2015 for WiiU GX2
*
* This file is part of FreeTypeGX.
*
* FreeTypeGX is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FreeTypeGX 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FreeTypeGX. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gui/FreeTypeGX.h>
#include <video/CVideo.h>
#include <video/shaders/Texture2DShader.h>
using namespace std;
#define ALIGN4(x) (((x) + 3) & ~3)
/**
* Default constructor for the FreeTypeGX class.
*/
FreeTypeGX::FreeTypeGX(const uint8_t *fontBuffer, FT_Long bufferSize, bool lastFace) {
int32_t faceIndex = 0;
GX2InitSampler(&ftSampler, GX2_TEX_CLAMP_MODE_CLAMP_BORDER, GX2_TEX_XY_FILTER_MODE_LINEAR);
FT_Init_FreeType(&ftLibrary);
faceMutex.lock();
if (lastFace) {
FT_New_Memory_Face(ftLibrary, (FT_Byte *) fontBuffer, bufferSize, -1, &ftFace);
faceIndex = ftFace->num_faces - 1; // Use the last face
FT_Done_Face(ftFace);
ftFace = NULL;
}
FT_New_Memory_Face(ftLibrary, (FT_Byte *) fontBuffer, bufferSize, faceIndex, &ftFace);
ftKerningEnabled = FT_HAS_KERNING(ftFace);
faceMutex.unlock();
}
/**
* Default destructor for the FreeTypeGX class.
*/
FreeTypeGX::~FreeTypeGX() {
unloadFont();
faceMutex.lock();
FT_Done_Face(ftFace);
faceMutex.unlock();
FT_Done_FreeType(ftLibrary);
}
/**
* Convert a short char string to a wide char string.
*
* This routine converts a supplied short character string into a wide character string.
* Note that it is the user's responsibility to clear the returned buffer once it is no longer needed.
*
* @param strChar Character string to be converted.
* @return Wide character representation of supplied character string.
*/
wchar_t *FreeTypeGX::charToWideChar(const char *strChar) {
if (!strChar) { return NULL; }
size_t len = strlen(strChar) + 1;
wchar_t *strWChar = new (std::nothrow) wchar_t[len];
if (!strWChar) { return NULL; }
size_t bt = mbstowcs(strWChar, strChar, len);
if (bt == (size_t) -1) {
return NULL;
}
if (bt < --len) {
strWChar[bt] = 0;
}
return strWChar;
}
char *FreeTypeGX::wideCharToUTF8(const wchar_t *strChar) {
if (!strChar) {
return NULL;
}
size_t len = 0;
wchar_t wc;
for (size_t i = 0; strChar[i]; ++i) {
wc = strChar[i];
if (wc < 0x80) {
++len;
} else if (wc < 0x800) {
len += 2;
} else if (wc < 0x10000) {
len += 3;
} else {
len += 4;
}
}
char *pOut = new (std::nothrow) char[len];
if (!pOut) {
return NULL;
}
size_t n = 0;
for (size_t i = 0; strChar[i]; ++i) {
wc = strChar[i];
if (wc < 0x80) {
pOut[n++] = (char) wc;
} else if (wc < 0x800) {
pOut[n++] = (char) ((wc >> 6) | 0xC0);
pOut[n++] = (char) ((wc & 0x3F) | 0x80);
} else if (wc < 0x10000) {
pOut[n++] = (char) ((wc >> 12) | 0xE0);
pOut[n++] = (char) (((wc >> 6) & 0x3F) | 0x80);
pOut[n++] = (char) ((wc & 0x3F) | 0x80);
} else {
pOut[n++] = (char) (((wc >> 18) & 0x07) | 0xF0);
pOut[n++] = (char) (((wc >> 12) & 0x3F) | 0x80);
pOut[n++] = (char) (((wc >> 6) & 0x3F) | 0x80);
pOut[n++] = (char) ((wc & 0x3F) | 0x80);
}
}
pOut[n] = '\0';
return pOut;
}
/**
* Clears all loaded font glyph data.
*
* This routine clears all members of the font map structure and frees all allocated memory back to the system.
*/
void FreeTypeGX::unloadFont() {
map<int16_t, ftGX2Data>::iterator itr;
map<wchar_t, ftgxCharData>::iterator itr2;
fontDataMutex.lock();
for (itr = fontData.begin(); itr != fontData.end(); itr++) {
for (itr2 = itr->second.ftgxCharMap.begin(); itr2 != itr->second.ftgxCharMap.end(); itr2++) {
if (itr2->second.texture) {
if (itr2->second.texture->surface.image) {
free(itr2->second.texture->surface.image);
}
delete itr2->second.texture;
itr2->second.texture = NULL;
}
}
}
fontData.clear();
fontDataMutex.unlock();
}
/**
* Caches the given font glyph in the instance font texture buffer.
*
* This routine renders and stores the requested glyph's bitmap and relevant information into its own quickly addressible
* structure within an instance-specific map.
*
* @param charCode The requested glyph's character code.
* @return A pointer to the allocated font structure.
*/
ftgxCharData *FreeTypeGX::cacheGlyphData(wchar_t charCode, int16_t pixelSize) {
fontDataMutex.lock();
auto itr = fontData.find(pixelSize);
if (itr != fontData.end()) {
auto itr2 = itr->second.ftgxCharMap.find(charCode);
if (itr2 != itr->second.ftgxCharMap.end()) {
// Used cached value;
fontDataMutex.unlock();
return &itr2->second;
}
}
ftGX2Data *ftData = &fontData[pixelSize];
faceMutex.lock();
FT_Set_Pixel_Sizes(ftFace, 0, pixelSize);
ftData->ftgxAlign.ascender = (int16_t) ftFace->size->metrics.ascender >> 6;
ftData->ftgxAlign.descender = (int16_t) ftFace->size->metrics.descender >> 6;
FT_UInt gIndex;
uint16_t textureWidth = 0, textureHeight = 0;
gIndex = FT_Get_Char_Index(ftFace, (FT_ULong) charCode);
if (gIndex != 0 && FT_Load_Glyph(ftFace, gIndex, FT_LOAD_DEFAULT | FT_LOAD_RENDER) == 0) {
if (ftFace->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
FT_Bitmap *glyphBitmap = &ftFace->glyph->bitmap;
textureWidth = ALIGN4(glyphBitmap->width);
textureHeight = ALIGN4(glyphBitmap->rows);
if (textureWidth == 0) {
textureWidth = 4;
}
if (textureHeight == 0) {
textureHeight = 4;
}
ftgxCharData *charData = &ftData->ftgxCharMap[charCode];
charData->renderOffsetX = (int16_t) ftFace->glyph->bitmap_left;
charData->glyphAdvanceX = (uint16_t) (ftFace->glyph->advance.x >> 6);
charData->glyphAdvanceY = (uint16_t) (ftFace->glyph->advance.y >> 6);
charData->glyphIndex = (uint32_t) gIndex;
charData->renderOffsetY = (int16_t) ftFace->glyph->bitmap_top;
charData->renderOffsetMax = (int16_t) ftFace->glyph->bitmap_top;
charData->renderOffsetMin = (int16_t) glyphBitmap->rows - ftFace->glyph->bitmap_top;
int16_t oldMax = ftData->ftgxAlign.max;
ftData->ftgxAlign.max = charData->renderOffsetMax > oldMax ? charData->renderOffsetMax : oldMax;
int16_t oldMin = ftData->ftgxAlign.min;
ftData->ftgxAlign.min = charData->renderOffsetMin > oldMin ? charData->renderOffsetMin : oldMin;
//! Initialize texture
charData->texture = new GX2Texture;
if (charData->texture) {
GX2InitTexture(charData->texture, textureWidth, textureHeight, 1, 0, GX2_SURFACE_FORMAT_UNORM_R5_G5_B5_A1, GX2_SURFACE_DIM_TEXTURE_2D, GX2_TILE_MODE_LINEAR_ALIGNED);
if (!loadGlyphData(glyphBitmap, charData)) {
delete charData->texture;
ftData->ftgxCharMap.erase(charCode);
charData = NULL;
}
} else {
charData = NULL;
}
faceMutex.unlock();
fontDataMutex.unlock();
return charData;
}
}
faceMutex.unlock();
fontDataMutex.unlock();
return NULL;
}
/**
* Locates each character in this wrapper's configured font face and proccess them.
*
* This routine locates each character in the configured font face and renders the glyph's bitmap.
* Each bitmap and relevant information is loaded into its own quickly addressible structure within an instance-specific map.
*/
uint16_t FreeTypeGX::cacheGlyphDataComplete(int16_t pixelSize) {
uint32_t i = 0;
FT_UInt gIndex;
faceMutex.lock();
FT_ULong charCode = FT_Get_First_Char(ftFace, &gIndex);
while (gIndex != 0) {
if (cacheGlyphData(charCode, pixelSize) != NULL) { ++i; }
charCode = FT_Get_Next_Char(ftFace, charCode, &gIndex);
}
faceMutex.unlock();
return (uint16_t) (i);
}
/**
* Loads the rendered bitmap into the relevant structure's data buffer.
*
* This routine does a simple byte-wise copy of the glyph's rendered 8-bit grayscale bitmap into the structure's buffer.
* Each byte is converted from the bitmap's intensity value into the a uint32_t RGBA value.
*
* @param bmp A pointer to the most recently rendered glyph's bitmap.
* @param charData A pointer to an allocated ftgxCharData structure whose data represent that of the last rendered glyph.
*/
bool FreeTypeGX::loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData) {
charData->texture->surface.image = (uint8_t *) memalign(charData->texture->surface.alignment, charData->texture->surface.imageSize);
if (!charData->texture->surface.image) {
return false;
}
memset(charData->texture->surface.image, 0x00, charData->texture->surface.imageSize);
uint8_t *src = (uint8_t *) bmp->buffer;
uint16_t *dst = (uint16_t *) charData->texture->surface.image;
uint32_t x, y;
for (y = 0; y < bmp->rows; y++) {
for (x = 0; x < bmp->width; x++) {
uint8_t intensity = src[y * bmp->width + x] >> 3;
dst[y * charData->texture->surface.pitch + x] = intensity ? ((intensity << 11) | (intensity << 6) | (intensity << 1) | 1) : 0;
}
}
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_TEXTURE, charData->texture->surface.image, charData->texture->surface.imageSize);
return true;
}
/**
* Determines the x offset of the rendered string.
*
* This routine calculates the x offset of the rendered string based off of a supplied positional format parameter.
*
* @param width Current pixel width of the string.
* @param format Positional format of the string.
*/
int16_t FreeTypeGX::getStyleOffsetWidth(uint16_t width, uint16_t format) {
if (format & FTGX_JUSTIFY_LEFT) {
return 0;
} else if (format & FTGX_JUSTIFY_CENTER) {
return -(width >> 1);
} else if (format & FTGX_JUSTIFY_RIGHT) {
return -width;
}
return 0;
}
/**
* Determines the y offset of the rendered string.
*
* This routine calculates the y offset of the rendered string based off of a supplied positional format parameter.
*
* @param offset Current pixel offset data of the string.
* @param format Positional format of the string.
*/
int16_t FreeTypeGX::getStyleOffsetHeight(int16_t format, uint16_t pixelSize) {
fontDataMutex.lock();
auto itr = fontData.find(pixelSize);
if (itr == fontData.end()) {
fontDataMutex.unlock();
return 0;
}
int16_t res = 0;
switch (format & FTGX_ALIGN_MASK) {
case FTGX_ALIGN_TOP:
res = itr->second.ftgxAlign.descender;
break;
case FTGX_ALIGN_MIDDLE:
default:
res = (itr->second.ftgxAlign.ascender + itr->second.ftgxAlign.descender + 1) >> 1;
break;
case FTGX_ALIGN_BOTTOM:
res = itr->second.ftgxAlign.ascender;
break;
case FTGX_ALIGN_BASELINE:
res = 0;
break;
case FTGX_ALIGN_GLYPH_TOP:
res = itr->second.ftgxAlign.max;
break;
case FTGX_ALIGN_GLYPH_MIDDLE:
res = (itr->second.ftgxAlign.max + itr->second.ftgxAlign.min + 1) >> 1;
break;
case FTGX_ALIGN_GLYPH_BOTTOM:
res = itr->second.ftgxAlign.min;
break;
}
fontDataMutex.unlock();
return res;
}
/**
* Processes the supplied text string and prints the results at the specified coordinates.
*
* This routine processes each character of the supplied text string, loads the relevant preprocessed bitmap buffer,
* a texture from said buffer, and loads the resultant texture into the EFB.
*
* @param x Screen X coordinate at which to output the text.
* @param y Screen Y coordinate at which to output the text. Note that this value corresponds to the text string origin and not the top or bottom of the glyphs.
* @param text NULL terminated string to output.
* @param color Optional color to apply to the text characters. If not specified default value is ftgxWhite: (GXColor){0xff, 0xff, 0xff, 0xff}
* @param textStyle Flags which specify any styling which should be applied to the rendered string.
* @return The number of characters printed.
*/
uint16_t FreeTypeGX::drawText(CVideo *video, int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, const glm::vec4 &color, uint16_t textStyle, uint16_t textWidth, const float &textBlur, const float &colorBlurIntensity,
const glm::vec4 &blurColor, const float &superSamplingScale) {
if (!text) { return 0; }
uint16_t fullTextWidth = (textWidth > 0) ? textWidth : getWidth(text, pixelSize);
uint16_t x_pos = x, printed = 0;
uint16_t x_offset = 0, y_offset = 0;
FT_Vector pairDelta;
if (textStyle & FTGX_JUSTIFY_MASK) {
x_offset = getStyleOffsetWidth(fullTextWidth, textStyle);
}
if (textStyle & FTGX_ALIGN_MASK) {
y_offset = getStyleOffsetHeight(textStyle, pixelSize);
}
int32_t i = 0;
while (text[i]) {
ftgxCharData *glyphData = cacheGlyphData(text[i], pixelSize);
if (glyphData != NULL) {
if (ftKerningEnabled && i > 0) {
fontDataMutex.lock();
faceMutex.lock();
FT_Get_Kerning(ftFace, fontData[pixelSize].ftgxCharMap[text[i - 1]].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta);
faceMutex.unlock();
fontDataMutex.unlock();
x_pos += (pairDelta.x >> 6);
}
copyTextureToFramebuffer(video, glyphData->texture, x_pos + glyphData->renderOffsetX + x_offset, y + glyphData->renderOffsetY - y_offset, z, color, textBlur, colorBlurIntensity, blurColor, superSamplingScale);
x_pos += glyphData->glyphAdvanceX;
++printed;
}
++i;
}
return printed;
}
/**
* Processes the supplied string and return the width of the string in pixels.
*
* This routine processes each character of the supplied text string and calculates the width of the entire string.
* Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function.
*
* @param text NULL terminated string to calculate.
* @return The width of the text string in pixels.
*/
uint16_t FreeTypeGX::getWidth(const wchar_t *text, int16_t pixelSize) {
if (!text) { return 0; }
uint16_t strWidth = 0;
int32_t i = 0;
while (text[i]) {
strWidth += getCharWidth(text[i], pixelSize, i > 0 ? text[i - 1] : 0);
++i;
}
return strWidth;
}
/**
* Single char width
*/
uint16_t FreeTypeGX::getCharWidth(const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar) {
uint16_t strWidth = 0;
ftgxCharData *glyphData = cacheGlyphData(wChar, pixelSize);
if (glyphData != NULL) {
if (ftKerningEnabled && prevChar != 0x0000) {
FT_Vector pairDelta;
faceMutex.lock();
fontDataMutex.lock();
FT_Get_Kerning(ftFace, fontData[pixelSize].ftgxCharMap[prevChar].glyphIndex, glyphData->glyphIndex, FT_KERNING_DEFAULT, &pairDelta);
fontDataMutex.unlock();
faceMutex.unlock();
strWidth += pairDelta.x >> 6;
}
strWidth += glyphData->glyphAdvanceX;
}
return strWidth;
}
/**
* Processes the supplied string and return the height of the string in pixels.
*
* This routine processes each character of the supplied text string and calculates the height of the entire string.
* Note that if precaching of the entire font set is not enabled any uncached glyph will be cached after the call to this function.
*
* @param text NULL terminated string to calculate.
* @return The height of the text string in pixels.
*/
uint16_t FreeTypeGX::getHeight(const wchar_t *text, int16_t pixelSize) {
if (text == NULL) {
return 0;
}
int16_t strMax = 0, strMin = 0;
int32_t i = 0;
while (text[i]) {
ftgxCharData *glyphData = cacheGlyphData(text[i], pixelSize);
if (glyphData != NULL) {
strMax = glyphData->renderOffsetMax > strMax ? glyphData->renderOffsetMax : strMax;
strMin = glyphData->renderOffsetMin > strMin ? glyphData->renderOffsetMin : strMin;
}
++i;
}
return strMax + strMin;
}
/**
* Copies the supplied texture quad to the EFB.
*
* This routine uses the in-built GX quad builder functions to define the texture bounds and location on the EFB target.
*
* @param texObj A pointer to the glyph's initialized texture object.
* @param texWidth The pixel width of the texture object.
* @param texHeight The pixel height of the texture object.
* @param screenX The screen X coordinate at which to output the rendered texture.
* @param screenY The screen Y coordinate at which to output the rendered texture.
* @param color Color to apply to the texture.
*/
void FreeTypeGX::copyTextureToFramebuffer(CVideo *pVideo, GX2Texture *texture, int16_t x, int16_t y, int16_t z, const glm::vec4 &color, const float &defaultBlur, const float &blurIntensity, const glm::vec4 &blurColor,
const float &superSamplingScale) {
static const float imageAngle = 0.0f;
static const float blurScale = (2.0f);
float offsetLeft = blurScale * (1.0f / superSamplingScale) * ((float) x + 0.5f * (float) texture->surface.width) * (float) pVideo->getWidthScaleFactor();
float offsetTop = blurScale * (1.0f / superSamplingScale) * ((float) y - 0.5f * (float) texture->surface.height) * (float) pVideo->getHeightScaleFactor();
float widthScale = blurScale * (1.0f / superSamplingScale) * (float) texture->surface.width * pVideo->getWidthScaleFactor();
float heightScale = blurScale * (1.0f / superSamplingScale) * (float) texture->surface.height * pVideo->getHeightScaleFactor();
glm::vec3 positionOffsets(offsetLeft, offsetTop, (float) z);
//! blur doubles due to blur we have to scale the texture
glm::vec3 scaleFactor(widthScale, heightScale, 1.0f);
glm::vec3 blurDirection;
blurDirection[2] = 1.0f;
Texture2DShader::instance()->setShaders();
Texture2DShader::instance()->setAttributeBuffer();
Texture2DShader::instance()->setAngle(imageAngle);
Texture2DShader::instance()->setOffset(positionOffsets);
Texture2DShader::instance()->setScale(scaleFactor);
Texture2DShader::instance()->setTextureAndSampler(texture, &ftSampler);
if (blurIntensity > 0.0f) {
//! glow blur color
Texture2DShader::instance()->setColorIntensity(blurColor);
//! glow blur horizontal
blurDirection[0] = blurIntensity;
blurDirection[1] = 0.0f;
Texture2DShader::instance()->setBlurring(blurDirection);
Texture2DShader::instance()->draw();
//! glow blur vertical
blurDirection[0] = 0.0f;
blurDirection[1] = blurIntensity;
Texture2DShader::instance()->setBlurring(blurDirection);
Texture2DShader::instance()->draw();
}
//! set text color
Texture2DShader::instance()->setColorIntensity(color);
//! blur horizontal
blurDirection[0] = defaultBlur;
blurDirection[1] = 0.0f;
Texture2DShader::instance()->setBlurring(blurDirection);
Texture2DShader::instance()->draw();
//! blur vertical
blurDirection[0] = 0.0f;
blurDirection[1] = defaultBlur;
Texture2DShader::instance()->setBlurring(blurDirection);
Texture2DShader::instance()->draw();
}

163
src/gui/FreeTypeGX.h Normal file
View File

@ -0,0 +1,163 @@
/*
* FreeTypeGX is a wrapper class for libFreeType which renders a compiled
* FreeType parsable font into a GX texture for Wii homebrew development.
* Copyright (C) 2008 Armin Tamzarian
* Modified by Dimok, 2015 for WiiU GX2
*
* This file is part of FreeTypeGX.
*
* FreeTypeGX is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FreeTypeGX 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FreeTypeGX. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <ft2build.h>
#include <string>
#include FT_FREETYPE_H
#include FT_BITMAP_H
#include <malloc.h>
#include <map>
#include <mutex>
#include <string.h>
#include <wchar.h>
#include <gui/gx2_ext.h>
#include <gx2/sampler.h>
#include <gx2/texture.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
/*! \struct ftgxCharData_
*
* Font face character glyph relevant data structure.
*/
typedef struct ftgxCharData_ {
int16_t renderOffsetX; /**< Texture X axis bearing offset. */
uint16_t glyphAdvanceX; /**< Character glyph X coordinate advance in pixels. */
uint16_t glyphAdvanceY; /**< Character glyph Y coordinate advance in pixels. */
uint32_t glyphIndex; /**< Charachter glyph index in the font face. */
int16_t renderOffsetY; /**< Texture Y axis bearing offset. */
int16_t renderOffsetMax; /**< Texture Y axis bearing maximum value. */
int16_t renderOffsetMin; /**< Texture Y axis bearing minimum value. */
GX2Texture *texture;
} ftgxCharData;
/*! \struct ftgxDataOffset_
*
* Offset structure which hold both a maximum and minimum value.
*/
typedef struct ftgxDataOffset_ {
int16_t ascender; /**< Maximum data offset. */
int16_t descender; /**< Minimum data offset. */
int16_t max; /**< Maximum data offset. */
int16_t min; /**< Minimum data offset. */
} ftgxDataOffset;
typedef struct ftgxCharData_ ftgxCharData;
typedef struct ftgxDataOffset_ ftgxDataOffset;
#define _TEXT(t) L##t /**< Unicode helper macro. */
#define FTGX_NULL 0x0000
#define FTGX_JUSTIFY_LEFT 0x0001
#define FTGX_JUSTIFY_CENTER 0x0002
#define FTGX_JUSTIFY_RIGHT 0x0004
#define FTGX_JUSTIFY_MASK 0x000f
#define FTGX_ALIGN_TOP 0x0010
#define FTGX_ALIGN_MIDDLE 0x0020
#define FTGX_ALIGN_BOTTOM 0x0040
#define FTGX_ALIGN_BASELINE 0x0080
#define FTGX_ALIGN_GLYPH_TOP 0x0100
#define FTGX_ALIGN_GLYPH_MIDDLE 0x0200
#define FTGX_ALIGN_GLYPH_BOTTOM 0x0400
#define FTGX_ALIGN_MASK 0x0ff0
#define FTGX_STYLE_UNDERLINE 0x1000
#define FTGX_STYLE_STRIKE 0x2000
#define FTGX_STYLE_MASK 0xf000
/**< Constant color value used only to sanitize Doxygen documentation. */
static const GX2ColorF32 ftgxWhite = (GX2ColorF32){
1.0f, 1.0f, 1.0f, 1.0f};
//! forward declaration
class CVideo;
/*! \class FreeTypeGX
* \brief Wrapper class for the libFreeType library with GX rendering.
* \author Armin Tamzarian
* \version 0.2.4
*
* FreeTypeGX acts as a wrapper class for the libFreeType library. It supports precaching of transformed glyph data into
* a specified texture format. Rendering of the data to the EFB is accomplished through the application of high performance
* GX texture functions resulting in high throughput of string rendering.
*/
class FreeTypeGX {
private:
FT_Library ftLibrary; /**< FreeType FT_Library instance. */
FT_Face ftFace; /**< FreeType reusable FT_Face typographic object. */
bool ftKerningEnabled; /**< Flag indicating the availability of font kerning data. */
uint8_t vertexIndex; /**< Vertex format descriptor index. */
GX2Sampler ftSampler;
std::recursive_mutex faceMutex;
std::recursive_mutex fontDataMutex;
typedef struct _ftGX2Data {
ftgxDataOffset ftgxAlign;
std::map<wchar_t, ftgxCharData> ftgxCharMap;
} ftGX2Data;
std::map<int16_t, ftGX2Data> fontData; /**< Map which holds the glyph data structures for the corresponding characters in one size. */
int16_t getStyleOffsetWidth(uint16_t width, uint16_t format);
int16_t getStyleOffsetHeight(int16_t format, uint16_t pixelSize);
void unloadFont();
ftgxCharData *cacheGlyphData(wchar_t charCode, int16_t pixelSize);
uint16_t cacheGlyphDataComplete(int16_t pixelSize);
bool loadGlyphData(FT_Bitmap *bmp, ftgxCharData *charData);
void copyTextureToFramebuffer(CVideo *pVideo, GX2Texture *tex, int16_t screenX, int16_t screenY, int16_t screenZ, const glm::vec4 &color, const float &textBlur, const float &colorBlurIntensity, const glm::vec4 &blurColor,
const float &superSamplingScale);
public:
FreeTypeGX(const uint8_t *fontBuffer, FT_Long bufferSize, bool lastFace = false);
~FreeTypeGX();
uint16_t drawText(CVideo *pVideo, int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, const glm::vec4 &color,
uint16_t textStyling, uint16_t textWidth, const float &textBlur, const float &colorBlurIntensity, const glm::vec4 &blurColor, const float &superSamplingScale);
uint16_t getWidth(const wchar_t *text, int16_t pixelSize);
uint16_t getCharWidth(const wchar_t wChar, int16_t pixelSize, const wchar_t prevChar = 0x0000);
uint16_t getHeight(const wchar_t *text, int16_t pixelSize);
static wchar_t *charToWideChar(const char *p);
static char *wideCharToUTF8(const wchar_t *strChar);
};

40
src/gui/GameBgImage.cpp Normal file
View File

@ -0,0 +1,40 @@
#include <gui/GameBgImage.h>
#include <video/CVideo.h>
#include <video/shaders/Shader3D.h>
GameBgImage::GameBgImage(const std::string &filename, GuiImageData *preloadImage)
: GuiImageAsync(filename, preloadImage) {
identity = glm::mat4(1.0f);
alphaFadeOut = glm::vec4(1.0f, 0.075f, 5.305f, 2.0f);
}
GameBgImage::~GameBgImage() {
}
void GameBgImage::draw(CVideo *pVideo) {
if (!getImageData() || !getImageData()->getTexture()) {
return;
}
//! first setup 2D GUI positions
float currPosX = getCenterX();
float currPosY = getCenterY();
float currPosZ = getDepth();
float currScaleX = getScaleX() * (float) getWidth() * pVideo->getWidthScaleFactor();
float currScaleY = getScaleY() * (float) getHeight() * pVideo->getHeightScaleFactor();
float currScaleZ = getScaleZ() * (float) getWidth() * pVideo->getDepthScaleFactor();
glm::mat4 m_modelView = glm::translate(identity, glm::vec3(currPosX, currPosY, currPosZ));
m_modelView = glm::scale(m_modelView, glm::vec3(currScaleX, currScaleY, currScaleZ));
Shader3D::instance()->setShaders();
Shader3D::instance()->setProjectionMtx(identity);
Shader3D::instance()->setViewMtx(identity);
Shader3D::instance()->setModelViewMtx(m_modelView);
Shader3D::instance()->setTextureAndSampler(getImageData()->getTexture(), getImageData()->getSampler());
Shader3D::instance()->setAlphaFadeOut(alphaFadeOut);
Shader3D::instance()->setDistanceFadeOut(0.0f);
Shader3D::instance()->setColorIntensity(glm::vec4(1.0f, 1.0f, 1.0f, getAlpha()));
Shader3D::instance()->setAttributeBuffer();
Shader3D::instance()->draw();
}

24
src/gui/GameBgImage.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef _GAME_BG_IMAGE_H_
#define _GAME_BG_IMAGE_H_
#include <gui/GuiImageAsync.h>
#include <video/shaders/Shader3D.h>
class GameBgImage : public GuiImageAsync {
public:
GameBgImage(const std::string &filename, GuiImageData *preloadImage);
virtual ~GameBgImage();
void setAlphaFadeOut(const glm::vec4 &a) {
alphaFadeOut = a;
}
void draw(CVideo *pVideo) override;
private:
glm::mat4 identity;
glm::vec4 alphaFadeOut;
};
#endif // _GAME_BG_IMAGE_H_

View File

@ -1,9 +1,9 @@
#include "GameIcon.h"
#include "GameIconModel.h"
#include "Application.h"
#include <gui/video/CVideo.h>
#include <gui/video/shaders/Shader3D.h>
#include <gui/video/shaders/ShaderFractalColor.h>
#include <video/CVideo.h>
#include <video/shaders/Shader3D.h>
#include <video/shaders/ShaderFractalColor.h>
#include "utils/utils.h"
#include "utils/logger.h"

View File

@ -2,7 +2,7 @@
#define _GAME_ICON_H_
#include <gui/GuiImageAsync.h>
#include <gui/video/shaders/Shader3D.h>
#include <video/shaders/Shader3D.h>
class GameIcon : public GuiImage {
public:

104
src/gui/GridBackground.cpp Normal file
View File

@ -0,0 +1,104 @@
#include "utils/utils.h"
#include <gui/GridBackground.h>
#include <video/CVideo.h>
#include <video/shaders/Shader3D.h>
static const float bgRepeat = 1000.0f;
static const float bgTexRotate = 39.0f;
GridBackground::GridBackground(GuiImageData *img)
: GuiImage(img) {
colorIntensity = glm::vec4(1.0f, 1.0f, 1.0f, 0.9f);
alphaFadeOut = glm::vec4(0.0f);
distanceFadeOut = 0.15f;
vtxCount = 4;
//! texture and vertex coordinates
float *m_posVtxs = (float *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, vtxCount * Shader3D::cuVertexAttrSize);
float *m_texCoords = (float *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, vtxCount * Shader3D::cuTexCoordAttrSize);
if (m_posVtxs) {
int32_t i = 0;
m_posVtxs[i++] = -1.0f;
m_posVtxs[i++] = 0.0f;
m_posVtxs[i++] = 1.0f;
m_posVtxs[i++] = 1.0f;
m_posVtxs[i++] = 0.0f;
m_posVtxs[i++] = 1.0f;
m_posVtxs[i++] = 1.0f;
m_posVtxs[i++] = 0.0f;
m_posVtxs[i++] = -1.0f;
m_posVtxs[i++] = -1.0f;
m_posVtxs[i++] = 0.0f;
m_posVtxs[i++] = -1.0f;
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, m_posVtxs, vtxCount * Shader3D::cuVertexAttrSize);
}
if (m_texCoords) {
glm::vec2 texCoordVec[4];
texCoordVec[0][0] = -0.5f * bgRepeat;
texCoordVec[0][1] = 0.5f * bgRepeat;
texCoordVec[1][0] = 0.5f * bgRepeat;
texCoordVec[1][1] = 0.5f * bgRepeat;
texCoordVec[2][0] = 0.5f * bgRepeat;
texCoordVec[2][1] = -0.5f * bgRepeat;
texCoordVec[3][0] = -0.5f * bgRepeat;
texCoordVec[3][1] = -0.5f * bgRepeat;
const float cosRot = cosf(DegToRad(bgTexRotate));
const float sinRot = sinf(DegToRad(bgTexRotate));
glm::mat2 texRotateMtx({cosRot, -sinRot,
sinRot, cosRot});
for (int32_t i = 0; i < 4; i++) {
texCoordVec[i] = texRotateMtx * texCoordVec[i];
m_texCoords[i * 2 + 0] = texCoordVec[i][0];
m_texCoords[i * 2 + 1] = texCoordVec[i][1];
}
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, m_texCoords, vtxCount * Shader3D::cuTexCoordAttrSize);
}
//! assign to internal variables which are const but oh well
posVtxs = m_posVtxs;
texCoords = m_texCoords;
}
GridBackground::~GridBackground() {
//! remove image so it can not be drawn anymore from this point on
imageData = nullptr;
//! main image vertexes
if (posVtxs) {
free((void *) posVtxs);
posVtxs = NULL;
}
if (texCoords) {
free((void *) texCoords);
texCoords = NULL;
}
}
void GridBackground::drawModel(CVideo *pVideo, const glm::mat4 &modelView) {
//! first setup 2D GUI positions
float currScaleX = bgRepeat * scaleX * (float) getWidth() * pVideo->getWidthScaleFactor();
float currScaleY = 1.0f;
float currScaleZ = bgRepeat * scaleZ * (float) getHeight() * pVideo->getDepthScaleFactor();
m_modelView = glm::scale(modelView, glm::vec3(currScaleX, currScaleY, currScaleZ));
colorIntensity[3] = getAlpha();
Shader3D::instance()->setShaders();
Shader3D::instance()->setTextureAndSampler(imageData->getTexture(), imageData->getSampler());
Shader3D::instance()->setProjectionMtx(pVideo->getProjectionMtx());
Shader3D::instance()->setViewMtx(pVideo->getViewMtx());
Shader3D::instance()->setModelViewMtx(m_modelView);
Shader3D::instance()->setDistanceFadeOut(distanceFadeOut);
Shader3D::instance()->setAlphaFadeOut(alphaFadeOut);
Shader3D::instance()->setColorIntensity(colorIntensity);
Shader3D::instance()->setAttributeBuffer(vtxCount, posVtxs, texCoords);
Shader3D::instance()->draw(GX2_PRIMITIVE_MODE_QUADS, vtxCount);
}

33
src/gui/GridBackground.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef _GRID_BACKGROUND_H_
#define _GRID_BACKGROUND_H_
#include <gui/GuiImage.h>
class GridBackground : public GuiImage {
public:
GridBackground(GuiImageData *imgData);
virtual ~GridBackground();
void setColorIntensity(const glm::vec4 &color) {
colorIntensity = color;
}
const glm::vec4 &getColorIntensity() const {
return colorIntensity;
}
void setDistanceFadeOut(const float &a) {
distanceFadeOut = a;
}
void drawModel(CVideo *pVideo, const glm::mat4 &modelView);
private:
glm::mat4 m_modelView;
glm::vec4 colorIntensity;
glm::vec4 alphaFadeOut;
float distanceFadeOut;
};
#endif // _GRID_BACKGROUND_H_

43
src/gui/Gui.h Normal file
View File

@ -0,0 +1,43 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef __GUI_H
#define __GUI_H
#include <gui/FreeTypeGX.h>
#include <gui/GameBgImage.h>
#include <gui/GridBackground.h>
#include <gui/GuiButton.h>
#include <gui/GuiCheckBox.h>
#include <gui/GuiController.h>
#include <gui/GuiDragListener.h>
#include <gui/GuiElement.h>
#include <gui/GuiFrame.h>
#include <gui/GuiImage.h>
#include <gui/GuiImageAsync.h>
#include <gui/GuiImageData.h>
#include <gui/GuiParticleImage.h>
#include <gui/GuiScrollbar.h>
#include <gui/GuiSelectBox.h>
#include <gui/GuiSound.h>
#include <gui/GuiSwitch.h>
#include <gui/GuiText.h>
#include <gui/GuiToggle.h>
#include <gui/GuiTrigger.h>
#include <gui/VPadController.h>
#include <gui/WPadController.h>
#endif

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 <gui/GuiButton.h>
#include <gui/GuiController.h>
#include <gui/GuiTrigger.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]);
}
}
}
}

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

@ -0,0 +1,135 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef GUI_BUTTON_H_
#define GUI_BUTTON_H_
#include <gui/GuiController.h>
#include <gui/GuiElement.h>
#include <gui/GuiImage.h>
#include <gui/GuiSound.h>
#include <gui/GuiText.h>
#include <gui/GuiTrigger.h>
#include <gui/gx2_ext.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) override;
//!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;
};
#endif

68
src/gui/GuiCheckBox.cpp Normal file
View File

@ -0,0 +1,68 @@
/****************************************************************************
* Copyright (C) 2016,2017 Maschell
*
* 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 <gui/GuiCheckBox.h>
#include <gui/GuiImage.h>
#include <gui/GuiImageData.h>
/**
* Constructor for the GuiCheckBox class.
*/
GuiCheckBox::GuiCheckBox(GuiImage *background, bool checked, float width, float height)
: GuiToggle(checked, width, height) {
setImageBackground(background);
}
/**
* Destructor for the GuiCheckBox class.
*/
GuiCheckBox::~GuiCheckBox() {
}
void GuiCheckBox::setImageBackground(GuiImage *img) {
backgroundImg = img;
if (img) {
img->setParent(this);
}
}
void GuiCheckBox::setImageSelected(GuiImage *img) {
selectedImg = img;
if (img) {
img->setParent(this);
}
}
void GuiCheckBox::setImageHighlighted(GuiImage *img) {
highlightedImg = img;
if (img) {
img->setParent(this);
}
setIconOver(img);
}
void GuiCheckBox::update(GuiController *c) {
if (bChanged) {
if (selected) {
GuiButton::setImage(selectedImg);
} else {
GuiButton::setImage(backgroundImg);
}
bChanged = false;
}
GuiToggle::update(c);
}

48
src/gui/GuiCheckBox.h Normal file
View File

@ -0,0 +1,48 @@
/****************************************************************************
* Copyright (C) 2016,2017 Maschell
*
* 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/>.
****************************************************************************/
#ifndef GUI_CHECKBOX_H_
#define GUI_CHECKBOX_H_
#include <gui/GuiImage.h>
#include <gui/GuiImageData.h>
#include <gui/GuiToggle.h>
//!A simple CheckBox
class GuiCheckBox : public GuiToggle {
public:
//!Constructor
//!\param checked Checked
GuiCheckBox(GuiImage *background, bool checked, float width = 0.0f, float height = 0.0f);
//!Destructor
virtual ~GuiCheckBox();
void setImageBackground(GuiImage *img);
void setImageSelected(GuiImage *img);
void setImageHighlighted(GuiImage *img);
protected:
GuiImage *backgroundImg = NULL;
GuiImage *selectedImg = NULL;
GuiImage *highlightedImg = NULL;
void update(GuiController *c);
};
#endif

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

@ -0,0 +1,73 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef GUI_CONTROLLER_H_
#define GUI_CONTROLLER_H_
#include <gui/GuiTrigger.h>
#include <string.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() {}
virtual bool update(int32_t width, int32_t height) = 0;
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;
};
#endif

View File

@ -0,0 +1,80 @@
/****************************************************************************
* Copyright (C) 2016 Maschell
* based on GuiButton by 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 <gui/GuiController.h>
#include <gui/GuiDragListener.h>
/**
* Constructor for the GuiDragListener class.
*/
GuiDragListener::GuiDragListener(float w, float h) {
width = w;
height = h;
for (int32_t i = 0; i < iMaxGuiTriggers; i++) {
trigger[i] = NULL;
}
}
/**
* Destructor for the GuiDragListener class.
*/
GuiDragListener::~GuiDragListener() {
}
void GuiDragListener::setState(int32_t i, int32_t c) {
GuiElement::setState(i, c);
}
void GuiDragListener::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 GuiDragListener::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;
}
for (int32_t i = 0; i < iMaxGuiTriggers; i++) {
if (!trigger[i]) {
continue;
}
bool isHeld = trigger[i]->held(c);
if (isHeld && this->isInside(c->data.x, c->data.y)) {
int32_t dx = c->data.x - c->lastData.x;
int32_t dy = c->data.y - c->lastData.y;
if (dx == 0 && dy == 0) { continue; }
dragged(this, c, trigger[i], dx, dy);
}
}
}

54
src/gui/GuiDragListener.h Normal file
View File

@ -0,0 +1,54 @@
/****************************************************************************
* Copyright (C) 2016 Maschell
*
* 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/>.
****************************************************************************/
#ifndef GUI_DRAG_LISTENER_H_
#define GUI_DRAG_LISTENER_H_
#include <gui/GuiButton.h>
#include <gui/GuiController.h>
#include <gui/GuiElement.h>
#include <gui/GuiTrigger.h>
class GuiDragListener : public GuiElement {
public:
//!Constructor
//!\param w Width
//!\param h Height
GuiDragListener(float w, float h);
//!Destructor
virtual ~GuiDragListener();
void setState(int32_t i, int32_t c);
//!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);
//!Constantly called to allow the GuiDragListener 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::signal5<GuiDragListener *, const GuiController *, GuiTrigger *, int32_t, int32_t> dragged;
protected:
static const int32_t iMaxGuiTriggers = 10;
GuiTrigger *trigger[iMaxGuiTriggers]; //!< GuiTriggers (input actions) that this element responds to
};
#endif

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

@ -0,0 +1,289 @@
/****************************************************************************
* 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 <gui/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_CENTER | ALIGN_MIDDLE);
}
/**
* 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);
}
}
}

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

@ -0,0 +1,610 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef GUI_ELEMENT_H_
#define GUI_ELEMENT_H_
#include <string>
#include <vector>
#include <malloc.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wchar.h>
#include <gui/gx2_ext.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <gui/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
};
#endif

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 <gui/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();
}

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

@ -0,0 +1,127 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef GUI_FRAME_H_
#define GUI_FRAME_H_
#include <gui/GuiElement.h>
#include <gui/sigslot.h>
#include <mutex>
#include <vector>
//!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) override;
//!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;
};
#endif

View File

@ -21,7 +21,7 @@
#include <coreinit/cache.h>
#include "common/common.h"
#include "Application.h"
#include <gui/video/CVideo.h>
#include <video/CVideo.h>
#include "utils/logger.h"
#include "gui/GameIcon.h"

View File

@ -36,7 +36,7 @@ public:
void update(GuiController *t);
void draw(CVideo *pVideo);
void draw(CVideo *pVideo) override;
void process();

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

@ -0,0 +1,270 @@
/****************************************************************************
* 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 "utils/utils.h"
#include <gui/GuiImage.h>
#include <video/CVideo.h>
#include <video/shaders/ColorShader.h>
#include <video/shaders/Texture2DShader.h>
static const float fPiDiv180 = ((float) M_PI / 180.0f);
GuiImage::GuiImage(GuiImageData *img) {
if (img && img->getTexture()) {
width = img->getWidth();
height = img->getHeight();
}
internalInit(width, height);
imageData = img;
}
GuiImage::GuiImage(int32_t w, int32_t h, const GX2Color &c, int32_t type) {
internalInit(w, h);
imgType = type;
colorCount = ColorShader::cuColorVtxsSize / ColorShader::cuColorAttrSize;
colorVtxs = (uint8_t *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, colorCount * ColorShader::cuColorAttrSize);
if (colorVtxs) {
for (uint32_t i = 0; i < colorCount; i++) {
setImageColor(c, i);
}
}
}
GuiImage::GuiImage(int32_t w, int32_t h, const GX2Color *c, uint32_t color_count, int32_t type) {
internalInit(w, h);
imgType = type;
colorCount = ColorShader::cuColorVtxsSize / ColorShader::cuColorAttrSize;
if (colorCount < color_count) {
colorCount = color_count;
}
colorVtxs = (uint8_t *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, colorCount * ColorShader::cuColorAttrSize);
if (colorVtxs) {
for (uint32_t i = 0; i < colorCount; i++) {
// take the last as reference if not enough colors defined
int32_t idx = (i < color_count) ? i : (color_count - 1);
setImageColor(c[idx], i);
}
}
}
/**
* Destructor for the GuiImage class.
*/
GuiImage::~GuiImage() {
if (colorVtxs) {
free(colorVtxs);
colorVtxs = NULL;
}
}
void GuiImage::internalInit(int32_t w, int32_t h) {
imageData = NULL;
width = w;
height = h;
tileHorizontal = -1;
tileVertical = -1;
imgType = IMAGE_TEXTURE;
colorVtxsDirty = false;
colorVtxs = NULL;
colorCount = 0;
posVtxs = NULL;
texCoords = NULL;
vtxCount = 4;
primitive = GX2_PRIMITIVE_MODE_QUADS;
imageAngle = 0.0f;
blurDirection = glm::vec3(0.0f);
positionOffsets = glm::vec3(0.0f);
scaleFactor = glm::vec3(1.0f);
colorIntensity = glm::vec4(1.0f);
}
void GuiImage::setImageData(GuiImageData *img) {
imageData = img;
width = 0;
height = 0;
if (img && img->getTexture()) {
width = img->getWidth();
height = img->getHeight();
}
imgType = IMAGE_TEXTURE;
}
GX2Color GuiImage::getPixel(int32_t x, int32_t y) {
if (!imageData || this->getWidth() <= 0 || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight()) {
return (GX2Color){
0, 0, 0, 0};
}
uint32_t pitch = imageData->getTexture()->surface.pitch;
uint32_t *imagePtr = (uint32_t *) imageData->getTexture()->surface.image;
uint32_t color_u32 = imagePtr[y * pitch + x];
GX2Color color;
color.r = (color_u32 >> 24) & 0xFF;
color.g = (color_u32 >> 16) & 0xFF;
color.b = (color_u32 >> 8) & 0xFF;
color.a = (color_u32 >> 0) & 0xFF;
return color;
}
void GuiImage::setPixel(int32_t x, int32_t y, const GX2Color &color) {
if (!imageData || this->getWidth() <= 0 || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight()) {
return;
}
uint32_t pitch = imageData->getTexture()->surface.pitch;
uint32_t *imagePtr = (uint32_t *) imageData->getTexture()->surface.image;
imagePtr[y * pitch + x] = (color.r << 24) | (color.g << 16) | (color.b << 8) | (color.a << 0);
}
void GuiImage::setImageColor(const GX2Color &c, int32_t idx) {
if (!colorVtxs) {
return;
}
if (idx >= 0 && idx < (int32_t) colorCount) {
colorVtxs[(idx << 2) + 0] = c.r;
colorVtxs[(idx << 2) + 1] = c.g;
colorVtxs[(idx << 2) + 2] = c.b;
colorVtxs[(idx << 2) + 3] = c.a;
colorVtxsDirty = true;
} else if (colorVtxs) {
for (uint32_t i = 0; i < (ColorShader::cuColorVtxsSize / sizeof(uint8_t)); i += 4) {
colorVtxs[i + 0] = c.r;
colorVtxs[i + 1] = c.g;
colorVtxs[i + 2] = c.b;
colorVtxs[i + 3] = c.a;
}
colorVtxsDirty = true;
}
}
void GuiImage::setSize(int32_t w, int32_t h) {
width = w;
height = h;
}
void GuiImage::setPrimitiveVertex(int32_t prim, const float *posVtx, const float *texCoord, uint32_t vtxcount) {
primitive = prim;
vtxCount = vtxcount;
posVtxs = posVtx;
texCoords = texCoord;
if (imgType == IMAGE_COLOR) {
uint8_t *newColorVtxs = (uint8_t *) memalign(0x40, ColorShader::cuColorAttrSize * vtxCount);
for (uint32_t i = 0; i < vtxCount; i++) {
int32_t newColorIdx = (i << 2);
int32_t colorIdx = (i < colorCount) ? (newColorIdx) : ((colorCount - 1) << 2);
newColorVtxs[newColorIdx + 0] = colorVtxs[colorIdx + 0];
newColorVtxs[newColorIdx + 1] = colorVtxs[colorIdx + 1];
newColorVtxs[newColorIdx + 2] = colorVtxs[colorIdx + 2];
newColorVtxs[newColorIdx + 3] = colorVtxs[colorIdx + 3];
}
free(colorVtxs);
colorVtxs = newColorVtxs;
colorCount = vtxCount;
colorVtxsDirty = true;
}
}
void GuiImage::draw(CVideo *pVideo) {
if (!this->isVisible() || tileVertical == 0 || tileHorizontal == 0) {
return;
}
float currScaleX = getScaleX();
float currScaleY = getScaleY();
positionOffsets[0] = getCenterX() * pVideo->getWidthScaleFactor() * 2.0f;
positionOffsets[1] = getCenterY() * pVideo->getHeightScaleFactor() * 2.0f;
positionOffsets[2] = getDepth() * pVideo->getDepthScaleFactor() * 2.0f;
scaleFactor[0] = currScaleX * getWidth() * pVideo->getWidthScaleFactor();
scaleFactor[1] = currScaleY * getHeight() * pVideo->getHeightScaleFactor();
scaleFactor[2] = getScaleZ();
//! add other colors intensities parameters
colorIntensity[3] = getAlpha();
//! angle of the object
imageAngle = DegToRad(getAngle());
// if(image && tileHorizontal > 0 && tileVertical > 0)
// {
// for(int32_t n=0; n<tileVertical; n++)
// for(int32_t i=0; i<tileHorizontal; i++)
// {
// if(bUnCut)
// Menu_DrawImg(image, width, height, format, currLeft+width*i, currTop+width*n, currZ, imageangle, currScaleX, currScaleY, currAlpha);
// else
// Menu_DrawImgCut(image, width, height, format, currLeft+width*i, currTop+width*n, currZ, imageangle, currScaleX, currScaleY, currAlpha, cutBoundsRect.x1(), cutBoundsRect.x2(), cutBoundsRect.y1(), cutBoundsRect.y2());
// }
// }
// else if(image && tileHorizontal > 0)
// {
// for(int32_t i=0; i<tileHorizontal; i++)
// {
// int32_t widthTile = (imageangle == 90 || imageangle == 270) ? height : width;
// if(bUnCut)
// Menu_DrawImg(image, width, height, format, currLeft+widthTile*i, currTop, currZ, imageangle, currScaleX, currScaleY, currAlpha);
// else
// Menu_DrawImgCut(image, width, height, format, currLeft+widthTile*i, currTop, currZ, imageangle, currScaleX, currScaleY, currAlpha, cutBoundsRect.x1(), cutBoundsRect.x2(), cutBoundsRect.y1(), cutBoundsRect.y2());
// }
// }
// else if(image && tileVertical > 0)
// {
// for(int32_t i=0; i<tileVertical; i++)
// {
// if(bUnCut)
// Menu_DrawImg(image, width, height, format, currLeft, currTop+height*i, currZ, imageangle, currScaleX, currScaleY, currAlpha);
// else
// Menu_DrawImgCut(image, width, height, format, currLeft, currTop+height*i, currZ, imageangle, currScaleX, currScaleY, currAlpha, cutBoundsRect.x1(), cutBoundsRect.x2(), cutBoundsRect.y1(), cutBoundsRect.y2());
// }
// }
if (colorVtxsDirty && colorVtxs) {
//! flush color vertex only on main GX2 thread
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, colorVtxs, colorCount * ColorShader::cuColorAttrSize);
colorVtxsDirty = false;
}
if (imgType == IMAGE_COLOR && colorVtxs) {
ColorShader::instance()->setShaders();
ColorShader::instance()->setAttributeBuffer(colorVtxs, posVtxs, vtxCount);
ColorShader::instance()->setAngle(imageAngle);
ColorShader::instance()->setOffset(positionOffsets);
ColorShader::instance()->setScale(scaleFactor);
ColorShader::instance()->setColorIntensity(colorIntensity);
ColorShader::instance()->draw(primitive, vtxCount);
} else if (imageData) {
Texture2DShader::instance()->setShaders();
Texture2DShader::instance()->setAttributeBuffer(texCoords, posVtxs, vtxCount);
Texture2DShader::instance()->setAngle(imageAngle);
Texture2DShader::instance()->setOffset(positionOffsets);
Texture2DShader::instance()->setScale(scaleFactor);
Texture2DShader::instance()->setColorIntensity(colorIntensity);
Texture2DShader::instance()->setBlurring(blurDirection);
Texture2DShader::instance()->setTextureAndSampler(imageData->getTexture(), imageData->getSampler());
Texture2DShader::instance()->draw(primitive, vtxCount);
}
}

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

@ -0,0 +1,127 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef GUI_IMAGE_H_
#define GUI_IMAGE_H_
#include <gui/GuiElement.h>
#include <gui/GuiImageData.h>
#include <gui/gx2_ext.h>
#include <video/shaders/Shader.h>
//!Display, manage, and manipulate images in the GUI
class GuiImage : public GuiElement {
public:
enum ImageTypes {
IMAGE_TEXTURE,
IMAGE_COLOR
};
//!\overload
//!\param img Pointer to GuiImageData element
explicit GuiImage(GuiImageData *img);
//!\overload
//!Creates an image filled with the specified color
//!\param w Image width
//!\param h Image height
//!\param c Array with 4 x image color (BL, BR, TL, TR)
GuiImage(int32_t w, int32_t h, const GX2Color &c, int32_t imgType = IMAGE_COLOR);
GuiImage(int32_t w, int32_t h, const GX2Color *c, uint32_t colorCount = 1, int32_t imgType = IMAGE_COLOR);
//!Destructor
~GuiImage() override;
//!Sets the number of times to draw the image horizontally
//!\param t Number of times to draw the image
void setTileHorizontal(int32_t t) {
tileHorizontal = t;
}
//!Sets the number of times to draw the image vertically
//!\param t Number of times to draw the image
void setTileVertical(int32_t t) {
tileVertical = t;
}
//!Constantly called to draw the image
void draw(CVideo *pVideo) override;
//!Gets the image data
//!\return pointer to image data
[[nodiscard]] GuiImageData *getImageData() const {
return imageData;
}
//!Sets up a new image using the GuiImageData object specified
//!\param img Pointer to GuiImageData object
void setImageData(GuiImageData *img);
//!Gets the pixel color at the specified coordinates of the image
//!\param x X coordinate
//!\param y Y coordinate
GX2Color getPixel(int32_t x, int32_t y);
//!Sets the pixel color at the specified coordinates of the image
//!\param x X coordinate
//!\param y Y coordinate
//!\param color Pixel color
void setPixel(int32_t x, int32_t y, const GX2Color &color);
//!Change ImageColor
void setImageColor(const GX2Color &c, int32_t idx = -1);
//!Change ImageColor
void setSize(int32_t w, int32_t h);
void setPrimitiveVertex(int32_t prim, const float *pos, const float *tex, uint32_t count);
void setBlurDirection(uint8_t dir, float value) {
if (dir < 2) {
blurDirection[dir] = value;
}
}
void setColorIntensity(const glm::vec4 &col) {
colorIntensity = col;
}
protected:
void internalInit(int32_t w, int32_t h);
int32_t imgType; //!< Type of image data (IMAGE_TEXTURE, IMAGE_COLOR, IMAGE_DATA)
GuiImageData *imageData; //!< Poiner to image data. May be shared with GuiImageData data
int32_t tileHorizontal; //!< Number of times to draw (tile) the image horizontally
int32_t tileVertical; //!< Number of times to draw (tile) the image vertically
//! Internally used variables for rendering
uint8_t *colorVtxs;
uint32_t colorCount;
bool colorVtxsDirty;
glm::vec3 positionOffsets;
glm::vec3 scaleFactor;
glm::vec4 colorIntensity;
float imageAngle;
glm::vec3 blurDirection;
const float *posVtxs;
const float *texCoords;
uint32_t vtxCount;
int32_t primitive;
};
#endif

173
src/gui/GuiImageAsync.cpp Normal file
View File

@ -0,0 +1,173 @@
/****************************************************************************
* 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 "../fs/CFile.hpp"
#include <gui/GuiImageAsync.h>
#include <unistd.h>
std::vector<GuiImageAsync *> GuiImageAsync::imageQueue;
CThread *GuiImageAsync::pThread = NULL;
std::recursive_mutex *GuiImageAsync::pMutex = NULL;
uint32_t GuiImageAsync::threadRefCounter = 0;
bool GuiImageAsync::bExitRequested = false;
GuiImageAsync *GuiImageAsync::pInUse = NULL;
GuiImageAsync::GuiImageAsync(const uint8_t *imageBuffer, const uint32_t &imageBufferSize, GuiImageData *preloadImg)
: GuiImage(preloadImg), imgData(NULL), imgBuffer(imageBuffer), imgBufferSize(imageBufferSize) {
threadInit();
threadAddImage(this);
}
GuiImageAsync::GuiImageAsync(const std::string &file, GuiImageData *preloadImg)
: GuiImage(preloadImg), imgData(NULL), filename(file), imgBuffer(NULL), imgBufferSize(0) {
threadInit();
threadAddImage(this);
}
GuiImageAsync::~GuiImageAsync() {
threadRemoveImage(this);
while (pInUse == this)
OSSleepTicks(OSMicrosecondsToTicks(1000));
if (imgData) {
delete imgData;
}
//threadExit();
}
void GuiImageAsync::threadAddImage(GuiImageAsync *Image) {
pMutex->lock();
imageQueue.push_back(Image);
pMutex->unlock();
pThread->resumeThread();
}
void GuiImageAsync::threadRemoveImage(GuiImageAsync *image) {
pMutex->lock();
for (uint32_t i = 0; i < imageQueue.size(); ++i) {
if (imageQueue[i] == image) {
imageQueue.erase(imageQueue.begin() + i);
break;
}
}
pMutex->unlock();
}
void GuiImageAsync::clearQueue() {
pMutex->lock();
imageQueue.clear();
pMutex->unlock();
}
void GuiImageAsync::guiImageAsyncThread(CThread *thread, void *arg) {
while (!bExitRequested) {
if (imageQueue.empty() && !bExitRequested) {
pThread->suspendThread();
}
if (!imageQueue.empty() && !bExitRequested) {
pMutex->lock();
pInUse = imageQueue.front();
imageQueue.erase(imageQueue.begin());
pMutex->unlock();
if (!pInUse) {
continue;
}
if (pInUse->imgBuffer && pInUse->imgBufferSize) {
pInUse->imgData = new GuiImageData(pInUse->imgBuffer, pInUse->imgBufferSize);
} else {
uint8_t *buffer = NULL;
uint64_t bufferSize = 0;
CFile file(pInUse->filename, CFile::ReadOnly);
if (file.isOpen()) {
uint64_t filesize = file.size();
buffer = (uint8_t *) malloc(filesize);
if (buffer != NULL) {
uint32_t blocksize = 0x4000;
uint32_t done = 0;
int32_t readBytes = 0;
while (done < filesize) {
if (done + blocksize > filesize) {
blocksize = filesize - done;
}
readBytes = file.read(buffer + done, blocksize);
if (readBytes <= 0) {
break;
}
done += readBytes;
}
if (done == filesize) {
bufferSize = filesize;
} else {
free(buffer);
}
}
file.close();
}
if (buffer != NULL && bufferSize > 0) {
pInUse->imgData = new GuiImageData(buffer, bufferSize, GX2_TEX_CLAMP_MODE_MIRROR);
//! free original image buffer which is converted to texture now and not needed anymore
free(buffer);
}
}
if (pInUse->imgData) {
if (pInUse->imgData->getTexture()) {
pInUse->width = pInUse->imgData->getWidth();
pInUse->height = pInUse->imgData->getHeight();
pInUse->imageData = pInUse->imgData;
} else {
delete pInUse->imgData;
pInUse->imgData = NULL;
}
}
pInUse->imageLoaded(pInUse);
pInUse = NULL;
}
}
}
void GuiImageAsync::threadInit() {
if (pThread == NULL) {
bExitRequested = false;
pMutex = new std::recursive_mutex();
pThread = CThread::create(GuiImageAsync::guiImageAsyncThread, NULL, CThread::eAttributeAffCore1 | CThread::eAttributePinnedAff, 10);
pThread->resumeThread();
}
++threadRefCounter;
}
void GuiImageAsync::threadExit() {
if (threadRefCounter) {
--threadRefCounter;
}
if (/*(threadRefCounter == 0) &&*/ (pThread != NULL)) {
bExitRequested = true;
delete pThread;
delete pMutex;
pThread = NULL;
pMutex = NULL;
}
}

66
src/gui/GuiImageAsync.h Normal file
View File

@ -0,0 +1,66 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef _GUIIMAGEASYNC_H_
#define _GUIIMAGEASYNC_H_
#include <gui/GuiImage.h>
#include <system/CThread.h>
#include <mutex>
#include <vector>
class GuiImageAsync : public GuiImage {
public:
GuiImageAsync(const uint8_t *imageBuffer, const uint32_t &imageBufferSize, GuiImageData *preloadImg);
GuiImageAsync(const std::string &filename, GuiImageData *preloadImg);
virtual ~GuiImageAsync();
static void clearQueue();
static void removeFromQueue(GuiImageAsync *image) {
threadRemoveImage(image);
}
//! don't forget to LOCK GUI if using this asynchron call
sigslot::signal1<GuiImageAsync *> imageLoaded;
static void threadExit();
private:
static void threadInit();
GuiImageData *imgData;
std::string filename;
const uint8_t *imgBuffer;
const uint32_t imgBufferSize;
static void guiImageAsyncThread(CThread *thread, void *arg);
static void threadAddImage(GuiImageAsync *Image);
static void threadRemoveImage(GuiImageAsync *Image);
static std::vector<GuiImageAsync *> imageQueue;
static CThread *pThread;
static std::recursive_mutex *pMutex;
static uint32_t threadRefCounter;
static GuiImageAsync *pInUse;
static bool bExitRequested;
};
#endif /*_GUIIMAGEASYNC_H_*/

191
src/gui/GuiImageData.cpp Normal file
View File

@ -0,0 +1,191 @@
/****************************************************************************
* 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 <gui/GuiImageData.h>
#include "system/memory.h"
#include <malloc.h>
#include <stdint.h>
#include <string.h>
/**
* Constructor for the GuiImageData class.
*/
GuiImageData::GuiImageData() {
texture = NULL;
sampler = NULL;
memoryType = eMemTypeMEM2;
}
/**
* Constructor for the GuiImageData class.
*/
GuiImageData::GuiImageData(const uint8_t *img, int32_t imgSize, GX2TexClampMode textureClamp, GX2SurfaceFormat textureFormat) {
texture = NULL;
sampler = NULL;
loadImage(img, imgSize, textureClamp, textureFormat);
}
/**
* Destructor for the GuiImageData class.
*/
GuiImageData::~GuiImageData() {
releaseData();
}
void GuiImageData::releaseData(void) {
if (texture) {
if (texture->surface.image) {
switch (memoryType) {
default:
case eMemTypeMEM2:
free(texture->surface.image);
break;
case eMemTypeMEM1:
MEM1_free(texture->surface.image);
break;
case eMemTypeMEMBucket:
MEMBucket_free(texture->surface.image);
break;
}
}
delete texture;
texture = NULL;
}
if (sampler) {
delete sampler;
sampler = NULL;
}
}
void GuiImageData::loadImage(const uint8_t *img, int32_t imgSize, GX2TexClampMode textureClamp, GX2SurfaceFormat textureFormat) {
if (!img || (imgSize < 8)) {
return;
}
releaseData();
gdImagePtr gdImg = 0;
if (img[0] == 0xFF && img[1] == 0xD8) {
//! not needed for now therefore comment out to safe ELF size
//! if needed uncomment, adds 200 kb to the ELF size
// IMAGE_JPEG
gdImg = gdImageCreateFromJpegPtr(imgSize, (uint8_t *) img);
} else if (img[0] == 'B' && img[1] == 'M') {
// IMAGE_BMP
gdImg = gdImageCreateFromBmpPtr(imgSize, (uint8_t *) img);
} else if (img[0] == 0x89 && img[1] == 'P' && img[2] == 'N' && img[3] == 'G') {
// IMAGE_PNG
gdImg = gdImageCreateFromPngPtr(imgSize, (uint8_t *) img);
}
//!This must be last since it can also intefere with outher formats
else if (img[0] == 0x00) {
// Try loading TGA image
gdImg = gdImageCreateFromTgaPtr(imgSize, (uint8_t *) img);
}
if (gdImg == 0) {
return;
}
uint32_t width = (gdImageSX(gdImg));
uint32_t height = (gdImageSY(gdImg));
//! Initialize texture
texture = new GX2Texture;
GX2InitTexture(texture, width, height, 1, 0, textureFormat, GX2_SURFACE_DIM_TEXTURE_2D, GX2_TILE_MODE_LINEAR_ALIGNED);
//! if this fails something went horribly wrong
if (texture->surface.imageSize == 0) {
delete texture;
texture = NULL;
gdImageDestroy(gdImg);
return;
}
//! allocate memory for the surface
memoryType = eMemTypeMEM2;
texture->surface.image = memalign(texture->surface.alignment, texture->surface.imageSize);
//! try MEM1 on failure
if (!texture->surface.image) {
memoryType = eMemTypeMEM1;
texture->surface.image = MEM1_alloc(texture->surface.imageSize, texture->surface.alignment);
}
//! try MEM bucket on failure
if (!texture->surface.image) {
memoryType = eMemTypeMEMBucket;
texture->surface.image = MEMBucket_alloc(texture->surface.imageSize, texture->surface.alignment);
}
//! check if memory is available for image
if (!texture->surface.image) {
gdImageDestroy(gdImg);
delete texture;
texture = NULL;
return;
}
//! set mip map data pointer
texture->surface.mipmaps = NULL;
//! convert image to texture
switch (textureFormat) {
default:
case GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8:
gdImageToUnormR8G8B8A8(gdImg, (uint32_t *) texture->surface.image, texture->surface.width, texture->surface.height, texture->surface.pitch);
break;
case GX2_SURFACE_FORMAT_UNORM_R5_G6_B5:
gdImageToUnormR5G6B5(gdImg, (uint16_t *) texture->surface.image, texture->surface.width, texture->surface.height, texture->surface.pitch);
break;
}
//! free memory of image as its not needed anymore
gdImageDestroy(gdImg);
//! invalidate the memory
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_TEXTURE, texture->surface.image, texture->surface.imageSize);
//! initialize the sampler
sampler = new GX2Sampler;
GX2InitSampler(sampler, textureClamp, GX2_TEX_XY_FILTER_MODE_LINEAR);
}
void GuiImageData::gdImageToUnormR8G8B8A8(gdImagePtr gdImg, uint32_t *imgBuffer, uint32_t width, uint32_t height, uint32_t pitch) {
for (uint32_t y = 0; y < height; ++y) {
for (uint32_t x = 0; x < width; ++x) {
uint32_t pixel = gdImageGetPixel(gdImg, x, y);
uint8_t a = 254 - 2 * ((uint8_t) gdImageAlpha(gdImg, pixel));
if (a == 254) { a++; }
uint8_t r = gdImageRed(gdImg, pixel);
uint8_t g = gdImageGreen(gdImg, pixel);
uint8_t b = gdImageBlue(gdImg, pixel);
imgBuffer[y * pitch + x] = (r << 24) | (g << 16) | (b << 8) | (a);
}
}
}
//! TODO: figure out why this seems to not work correct yet
void GuiImageData::gdImageToUnormR5G6B5(gdImagePtr gdImg, uint16_t *imgBuffer, uint32_t width, uint32_t height, uint32_t pitch) {
for (uint32_t y = 0; y < height; ++y) {
for (uint32_t x = 0; x < width; ++x) {
uint32_t pixel = gdImageGetPixel(gdImg, x, y);
uint8_t r = gdImageRed(gdImg, pixel);
uint8_t g = gdImageGreen(gdImg, pixel);
uint8_t b = gdImageBlue(gdImg, pixel);
imgBuffer[y * pitch + x] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
}
}
}

91
src/gui/GuiImageData.h Normal file
View File

@ -0,0 +1,91 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef GUI_IMAGEDATA_H_
#define GUI_IMAGEDATA_H_
#include <gd.h>
#include <gui/GuiElement.h>
#include <gui/gx2_ext.h>
#include <gx2/texture.h>
class GuiImageData : public GuiElement {
public:
//!Constructor
GuiImageData();
//!\param img Image data
//!\param imgSize The image size
GuiImageData(const uint8_t *img, int32_t imgSize, GX2TexClampMode textureClamp = GX2_TEX_CLAMP_MODE_CLAMP, GX2SurfaceFormat textureFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8);
//!Destructor
virtual ~GuiImageData();
//!Load image from buffer
//!\param img Image data
//!\param imgSize The image size
void loadImage(const uint8_t *img, int32_t imgSize, GX2TexClampMode textureClamp = GX2_TEX_CLAMP_MODE_CLAMP, GX2SurfaceFormat textureFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8);
//! getter functions
virtual const GX2Texture *getTexture() const {
return texture;
};
virtual const GX2Sampler *getSampler() const {
return sampler;
};
//!Gets the image width
//!\return image width
float getWidth() override {
if (texture) {
return texture->surface.width;
} else {
return 0;
}
};
//!Gets the image height
//!\return image height
float getHeight() override {
if (texture) {
return texture->surface.height;
} else {
return 0;
}
};
//! release memory of the image data
void releaseData();
private:
void gdImageToUnormR8G8B8A8(gdImagePtr gdImg, uint32_t *imgBuffer, uint32_t width, uint32_t height, uint32_t pitch);
void gdImageToUnormR5G6B5(gdImagePtr gdImg, uint16_t *imgBuffer, uint32_t width, uint32_t height, uint32_t pitch);
GX2Texture *texture;
GX2Sampler *sampler;
enum eMemoryTypes {
eMemTypeMEM2,
eMemTypeMEM1,
eMemTypeMEMBucket
};
uint8_t memoryType;
};
#endif

View File

@ -0,0 +1,124 @@
/****************************************************************************
* 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 "utils/utils.h"
#include <gui/GuiParticleImage.h>
#include <video/CVideo.h>
#include <video/shaders/ColorShader.h>
#define CIRCLE_VERTEX_COUNT 36
static inline float getRandZeroToOneF32() {
return (rand() % 10000) * 0.0001f;
}
static inline float getRandMinusOneToOneF32() {
return getRandZeroToOneF32() * 2.0f - 1.0f;
}
GuiParticleImage::GuiParticleImage(int32_t w, int32_t h, uint32_t particleCount, float minRadius, float maxRadius, float minSpeed, float maxSpeed)
: GuiImage(NULL) {
width = w;
height = h;
imgType = IMAGE_COLOR;
this->minRadius = minRadius;
this->maxRadius = maxRadius;
this->minSpeed = minSpeed;
this->maxSpeed = maxSpeed;
posVertexs = (float *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ColorShader::cuVertexAttrSize * CIRCLE_VERTEX_COUNT);
colorVertexs = (uint8_t *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ColorShader::cuColorAttrSize * CIRCLE_VERTEX_COUNT);
for (uint32_t i = 0; i < CIRCLE_VERTEX_COUNT; i++) {
posVertexs[i * 3 + 0] = cosf(DegToRad(i * 360.0f / CIRCLE_VERTEX_COUNT));
posVertexs[i * 3 + 1] = sinf(DegToRad(i * 360.0f / CIRCLE_VERTEX_COUNT));
posVertexs[i * 3 + 2] = 0.0f;
colorVertexs[i * 4 + 0] = 0xff;
colorVertexs[i * 4 + 1] = 0xff;
colorVertexs[i * 4 + 2] = 0xff;
colorVertexs[i * 4 + 3] = 0xff;
}
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, posVertexs, ColorShader::cuVertexAttrSize * CIRCLE_VERTEX_COUNT);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, colorVertexs, ColorShader::cuColorAttrSize * CIRCLE_VERTEX_COUNT);
particles.resize(particleCount);
for (uint32_t i = 0; i < particleCount; i++) {
particles[i].position.x = getRandMinusOneToOneF32() * getWidth() * 0.5f;
particles[i].position.y = getRandMinusOneToOneF32() * getHeight() * 0.5f;
particles[i].position.z = 0.0f;
particles[i].colors = glm::vec4(1.0f, 1.0f, 1.0f, (getRandZeroToOneF32() * 0.6f) + 0.05f);
particles[i].radius = getRandZeroToOneF32() * (maxRadius - minRadius) + minRadius;
particles[i].speed = (getRandZeroToOneF32() * (maxSpeed - minSpeed)) + minSpeed;
particles[i].direction = getRandMinusOneToOneF32();
}
}
GuiParticleImage::~GuiParticleImage() {
free(posVertexs);
free(colorVertexs);
}
void GuiParticleImage::draw(CVideo *pVideo) {
if (!this->isVisible()) {
return;
}
float currScaleX = getScaleX();
float currScaleY = getScaleY();
positionOffsets[2] = getDepth() * pVideo->getDepthScaleFactor() * 2.0f;
scaleFactor[2] = getScaleZ();
//! add other colors intensities parameters
colorIntensity[3] = getAlpha();
for (uint32_t i = 0; i < particles.size(); ++i) {
if (particles[i].position.y > (getHeight() * 0.5f + 30.0f)) {
particles[i].position.x = getRandMinusOneToOneF32() * getWidth() * 0.5f;
particles[i].position.y = -getHeight() * 0.5f - 30.0f;
particles[i].colors = glm::vec4(1.0f, 1.0f, 1.0f, (getRandZeroToOneF32() * 0.6f) + 0.05f);
particles[i].radius = getRandZeroToOneF32() * (maxRadius - minRadius) + minRadius;
particles[i].speed = (getRandZeroToOneF32() * (maxSpeed - minSpeed)) + minSpeed;
particles[i].direction = getRandMinusOneToOneF32();
}
if (particles[i].position.x < (-getWidth() * 0.5f - 50.0f)) {
particles[i].position.x = -particles[i].position.x;
}
particles[i].direction += getRandMinusOneToOneF32() * 0.03f;
particles[i].position.x += particles[i].speed * particles[i].direction;
particles[i].position.y += particles[i].speed;
positionOffsets[0] = (getCenterX() + particles[i].position.x) * pVideo->getWidthScaleFactor() * 2.0f;
positionOffsets[1] = (getCenterY() + particles[i].position.y) * pVideo->getHeightScaleFactor() * 2.0f;
scaleFactor[0] = currScaleX * particles[i].radius * pVideo->getWidthScaleFactor();
scaleFactor[1] = currScaleY * particles[i].radius * pVideo->getHeightScaleFactor();
ColorShader::instance()->setShaders();
ColorShader::instance()->setAttributeBuffer(colorVertexs, posVertexs, CIRCLE_VERTEX_COUNT);
ColorShader::instance()->setAngle(0.0f);
ColorShader::instance()->setOffset(positionOffsets);
ColorShader::instance()->setScale(scaleFactor);
ColorShader::instance()->setColorIntensity(colorIntensity * particles[i].colors);
ColorShader::instance()->draw(GX2_PRIMITIVE_MODE_TRIANGLE_FAN, CIRCLE_VERTEX_COUNT);
}
}

View File

@ -0,0 +1,50 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef _GUI_PARTICLE_IMAGE_H_
#define _GUI_PARTICLE_IMAGE_H_
#include <gui/GuiImage.h>
class GuiParticleImage : public GuiImage, public sigslot::has_slots<> {
public:
GuiParticleImage(int32_t w, int32_t h, uint32_t particleCount, float minRadius, float maxRadius, float minSpeed, float maxSpeed);
virtual ~GuiParticleImage();
void draw(CVideo *pVideo) override;
private:
float *posVertexs;
uint8_t *colorVertexs;
float minRadius;
float maxRadius;
float minSpeed;
float maxSpeed;
typedef struct {
glm::vec3 position;
glm::vec4 colors;
float radius;
float speed;
float direction;
} Particle;
std::vector<Particle> particles;
};
#endif // _GUI_ICON_GRID_H_

221
src/gui/GuiScrollbar.cpp Normal file
View File

@ -0,0 +1,221 @@
/***************************************************************************
* Copyright (C) 2011
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
***************************************************************************/
#include "utils/utils.h"
#include <gui/GuiScrollbar.h>
GuiScrollbar::GuiScrollbar(int32_t h)
: touchTrigger(GuiTrigger::CHANNEL_1, GuiTrigger::VPAD_TOUCH), wpadTouchTrigger(GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5, GuiTrigger::BUTTON_A) {
SelItem = 0;
SelInd = 0;
PageSize = 0;
EntrieCount = 0;
SetScrollSpeed(15);
ScrollState = 0;
listChanged.connect(this, &GuiScrollbar::setScrollboxPosition);
height = h;
arrowUpBtn = new GuiButton(50, 50);
arrowUpBtn->setParent(this);
arrowUpBtn->setAlignment(ALIGN_CENTER | ALIGN_TOP);
arrowUpBtn->setPosition(0, 0);
arrowUpBtn->setTrigger(&touchTrigger, 0);
arrowUpBtn->setTrigger(&wpadTouchTrigger, 1);
arrowUpBtn->setEffectGrow();
arrowUpBtn->clicked.connect(this, &GuiScrollbar::OnUpButtonClick);
arrowDownBtn = new GuiButton(50, 50);
arrowDownBtn->setParent(this);
arrowDownBtn->setAlignment(ALIGN_CENTER | ALIGN_BOTTOM);
arrowDownBtn->setPosition(0, 0);
arrowDownBtn->setTrigger(&touchTrigger, 0);
arrowDownBtn->setTrigger(&wpadTouchTrigger, 1);
arrowDownBtn->setEffectGrow();
arrowDownBtn->clicked.connect(this, &GuiScrollbar::OnDownButtonClick);
scrollbarBoxBtn = new GuiButton(50, height);
scrollbarBoxBtn->setParent(this);
scrollbarBoxBtn->setAlignment(ALIGN_CENTER | ALIGN_TOP);
scrollbarBoxBtn->setPosition(0, MaxHeight);
scrollbarBoxBtn->setHoldable(true);
scrollbarBoxBtn->setTrigger(&touchTrigger, 0);
scrollbarBoxBtn->setTrigger(&wpadTouchTrigger, 1);
scrollbarBoxBtn->setEffectGrow();
scrollbarBoxBtn->held.connect(this, &GuiScrollbar::OnBoxButtonHold);
}
GuiScrollbar::~GuiScrollbar() {
delete arrowUpBtn;
delete arrowDownBtn;
delete scrollbarBoxBtn;
}
void GuiScrollbar::ScrollOneUp() {
if (SelItem == 0 && SelInd > 0) {
// move list up by 1
--SelInd;
} else if (SelInd + SelItem > 0) {
--SelItem;
}
}
void GuiScrollbar::ScrollOneDown() {
if (SelInd + SelItem + 1 < EntrieCount) {
if (SelItem == PageSize - 1) {
// move list down by 1
SelInd++;
} else {
SelItem++;
}
}
}
void GuiScrollbar::OnUpButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) {
if (ScrollState < ScrollSpeed) {
return;
}
ScrollOneUp();
ScrollState = 0;
listChanged(SelItem, SelInd);
}
void GuiScrollbar::OnDownButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) {
if (ScrollState < ScrollSpeed) {
return;
}
ScrollOneDown();
ScrollState = 0;
listChanged(SelItem, SelInd);
}
void GuiScrollbar::OnBoxButtonHold(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) {
if (EntrieCount == 0) {
return;
}
if (!controller->data.validPointer) {
return;
}
int32_t y = controller->data.y - this->getCenterY();
int32_t positionWiimote = LIMIT(y - MinHeight, 0, MaxHeight - MinHeight);
int32_t newSelected = (EntrieCount - 1) - (int32_t) ((float) positionWiimote / (float) (MaxHeight - MinHeight) * (float) (EntrieCount - 1));
int32_t diff = newSelected - SelInd - SelItem;
if (newSelected <= 0) {
SelItem = 0;
SelInd = 0;
} else if (newSelected >= EntrieCount - 1) {
SelItem = (PageSize - 1 < EntrieCount - 1) ? PageSize - 1 : EntrieCount - 1;
SelInd = EntrieCount - PageSize;
} else if (newSelected < PageSize && SelInd == 0 && diff < 0) {
SelItem = std::max(SelItem + diff, (int32_t) 0);
} else if (EntrieCount - newSelected < PageSize && SelInd == EntrieCount - PageSize && diff > 0) {
SelItem = std::min(SelItem + diff, PageSize - 1);
} else {
SelInd = LIMIT(SelInd + diff, 0, ((EntrieCount - PageSize < 0) ? 0 : EntrieCount - PageSize));
}
ScrollState = 0;
listChanged(SelItem, SelInd);
}
void GuiScrollbar::SetPageSize(int32_t size) {
if (PageSize == size) {
return;
}
PageSize = size;
listChanged(SelItem, SelInd);
}
void GuiScrollbar::SetSelectedItem(int32_t pos) {
if (SelItem == pos) {
return;
}
SelItem = LIMIT(pos, 0, EntrieCount - 1);
listChanged(SelItem, SelInd);
}
void GuiScrollbar::SetSelectedIndex(int32_t pos) {
if (SelInd == pos) {
return;
}
SelInd = pos;
listChanged(SelItem, SelInd);
}
void GuiScrollbar::SetEntrieCount(int32_t cnt) {
if (EntrieCount == cnt) {
return;
}
EntrieCount = cnt;
listChanged(SelItem, SelInd);
}
void GuiScrollbar::setScrollboxPosition(int32_t SelItem, int32_t SelInd) {
int32_t position = MaxHeight - (MaxHeight - MinHeight) * (SelInd + SelItem) / (EntrieCount - 1);
if (position < MinHeight || (SelInd + SelItem >= EntrieCount - 1)) {
position = MinHeight;
} else if (position > MaxHeight || (SelInd + SelItem) == 0) {
position = MaxHeight;
}
scrollbarBoxBtn->setPosition(0, position);
}
void GuiScrollbar::draw(CVideo *video) {
if (scrollbarLineImage) {
scrollbarLineImage->draw(video);
}
arrowUpBtn->draw(video);
arrowDownBtn->draw(video);
scrollbarBoxBtn->draw(video);
updateEffects();
}
void GuiScrollbar::update(GuiController *t) {
if (this->isStateSet(STATE_DISABLED)) {
return;
}
arrowUpBtn->update(t);
arrowDownBtn->update(t);
scrollbarBoxBtn->update(t);
++ScrollState;
}

150
src/gui/GuiScrollbar.h Normal file
View File

@ -0,0 +1,150 @@
/***************************************************************************
* Copyright (C) 2011
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
***************************************************************************/
#ifndef GUI_SCROLLBAR_HPP_
#define GUI_SCROLLBAR_HPP_
#include <gui/GuiButton.h>
#include <gui/GuiElement.h>
class GuiScrollbar : public GuiElement, public sigslot::has_slots<> {
public:
GuiScrollbar(int32_t height);
virtual ~GuiScrollbar();
void ScrollOneUp();
void ScrollOneDown();
int32_t GetSelectedItem() {
return SelItem;
}
int32_t GetSelectedIndex() {
return SelInd;
}
void draw(CVideo *video) override;
void update(GuiController *t);
//! Signals
sigslot::signal2<int32_t, int32_t> listChanged;
//! Slots
void SetScrollSpeed(int32_t speed) {
ScrollSpeed = speed;
};
void SetPageSize(int32_t size);
void SetRowSize(int32_t size);
void SetSelectedItem(int32_t pos);
void SetSelectedIndex(int32_t pos);
void SetEntrieCount(int32_t cnt);
void setSoundClick(GuiSound *snd) {
clickSound = snd;
arrowUpBtn->setSoundClick(snd);
arrowDownBtn->setSoundClick(snd);
}
void setImageScrollbarLine(GuiImage *img) {
if (img) {
scrollbarLineImage = img;
scrollbarLineImage->setParent(this);
scrollbarLineImage->setParent(this);
scrollbarLineImage->setAlignment(ALIGN_CENTER | ALIGN_MIDDLE);
scrollbarLineImage->setPosition(0, 0);
}
}
void setImageArrowDown(GuiImage *img) {
if (img) {
arrowDownImage = img;
arrowDownBtn->setSize(img->getWidth(), img->getHeight());
arrowDownBtn->setImage(img);
}
}
void setImageArrowUp(GuiImage *img) {
if (img) {
arrowUpImage = img;
arrowUpBtn->setSize(img->getWidth(), img->getHeight());
arrowUpBtn->setImage(img);
}
}
void setImageScrollbarBox(GuiImage *img) {
if (img) {
scrollbarBoxImage = img;
scrollbarBoxBtn->setSize(img->getWidth(), height);
scrollbarBoxBtn->setImage(img);
width = img->getWidth();
MaxHeight = height * 0.5f - (img ? (img->getHeight() * 0.5f) : 0) - (arrowUpImage ? arrowUpImage->getHeight() : 0);
MinHeight = -height * 0.5f + (img ? (img->getHeight() * 0.5f) : 0) + (arrowDownImage ? arrowDownImage->getHeight() : 0);
}
}
protected:
void setScrollboxPosition(int32_t SelItem, int32_t SelInd);
void OnUpButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger);
void OnDownButtonClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger);
void OnBoxButtonHold(GuiButton *button, const GuiController *controller, GuiTrigger *trigger);
uint32_t ScrollState;
uint16_t ScrollSpeed;
int32_t MinHeight;
int32_t MaxHeight;
int32_t SelItem;
int32_t SelInd;
int32_t PageSize;
int32_t EntrieCount;
int32_t pressedChan;
GuiButton *arrowUpBtn;
GuiButton *arrowDownBtn;
GuiButton *scrollbarBoxBtn;
GuiSound *clickSound = NULL;
GuiImage *scrollbarLineImage = NULL;
GuiImage *arrowDownImage = NULL;
GuiImage *arrowUpImage = NULL;
GuiImage *scrollbarBoxImage = NULL;
GuiTrigger touchTrigger;
GuiTrigger wpadTouchTrigger;
};
#endif

289
src/gui/GuiSelectBox.cpp Normal file
View File

@ -0,0 +1,289 @@
/****************************************************************************
* Copyright (C) 2016 Maschell
*
* 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 <string>
#include <vector>
#include <gui/GuiImage.h>
#include <gui/GuiImageData.h>
#include <gui/GuiSelectBox.h>
#include <gui/GuiTrigger.h>
/**
* Constructor for the GuiCheckBox class.
*/
GuiSelectBox::GuiSelectBox(GuiImage *background, std::string caption, float width, float height, GuiFrame *parent)
: GuiFrame(width, height, parent), selected(0), captionText(caption), topValueButton(0, 0), touchTrigger(GuiTrigger::CHANNEL_1, GuiTrigger::VPAD_TOUCH),
wpadTouchTrigger(GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5, GuiTrigger::BUTTON_A), buttonATrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_A, true),
buttonBTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_B, true), buttonUpTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_UP | GuiTrigger::STICK_L_UP, true),
buttonDownTrigger(GuiTrigger::CHANNEL_ALL, GuiTrigger::BUTTON_DOWN | GuiTrigger::STICK_L_DOWN, true), DPADButtons(0, 0) {
setImageTopBackground(background);
showValues = false;
bChanged = false;
bSelectedChanged = false;
opened = false;
topValueText.setFontSize(32);
topValueText.setAlignment(ALIGN_LEFT);
topValueText.setPosition(10, -7);
topValueButton.setLabel(&topValueText);
topValueButton.setTrigger(&touchTrigger);
topValueButton.setTrigger(&wpadTouchTrigger);
topValueButton.clicked.connect(this, &GuiSelectBox::OnTopValueClicked);
valuesFrame.setState(STATE_HIDDEN);
DPADButtons.setTrigger(&buttonBTrigger);
DPADButtons.setTrigger(&buttonATrigger);
DPADButtons.setTrigger(&buttonDownTrigger);
DPADButtons.setTrigger(&buttonUpTrigger);
DPADButtons.clicked.connect(this, &GuiSelectBox::OnDPADClick);
DPADButtons.setState(STATE_DISABLE_INPUT);
append(&DPADButtons);
append(&valuesFrame);
append(&topValueButton);
showValues = false;
bChanged = true;
}
void GuiSelectBox::setSize(float width, float height) {
GuiFrame::setSize(width, height);
topValueButton.setSize(width, height);
}
void GuiSelectBox::OnValueClicked(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) {
for (uint32_t i = 0; i < valueButtons.size(); ++i) {
if (valueButtons[i].valueButton == button) {
selected = i;
SelectValue(i);
break;
}
}
}
void GuiSelectBox::SelectValue(uint32_t value) {
if (value < valueButtons.size()) {
const wchar_t *w_text = valueButtons[value].valueButtonText->getText();
std::wstring ws(w_text);
std::string text(ws.begin(), ws.end());
topValueText.setText(text.c_str());
std::string real_value = buttonToValue[valueButtons[value].valueButton];
if (real_value.compare(std::string()) == 0) { real_value = "<error>"; }
valueChanged(this, real_value);
ShowHideValues(false);
}
}
void GuiSelectBox::OnTopValueClicked(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) {
ShowHideValues(!showValues);
}
void GuiSelectBox::ShowHideValues(bool showhide) {
showValues = showhide;
bChanged = true;
}
void GuiSelectBox::OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) {
if (opened == true) {
if (trigger == &buttonATrigger) {
//! do not auto launch when wiimote is pointing to screen and presses A
if ((controller->chan & (GuiTrigger::CHANNEL_2 | GuiTrigger::CHANNEL_3 | GuiTrigger::CHANNEL_4 | GuiTrigger::CHANNEL_5)) && controller->data.validPointer) {
return;
}
SelectValue(selected);
} else if (trigger == &buttonBTrigger) {
if (button == &DPADButtons) {
ShowHideValues(false);
} else {
}
} else if (trigger == &buttonUpTrigger) {
if (selected > 0) { selected--; }
bSelectedChanged = true;
} else if (trigger == &buttonDownTrigger) {
selected++;
if (selected >= valueButtons.size()) { selected = valueButtons.size() - 1; }
bSelectedChanged = true;
}
}
}
void GuiSelectBox::Init(std::map<std::string, std::string> values, int32_t valueID) {
if ((uint32_t) valueID >= values.size()) {
valueID = 0;
}
selected = valueID;
bSelectedChanged = true;
DeleteValueData();
if (valueImageData == NULL || valueSelectedImageData == NULL || valueHighlightedImageData == NULL) {
return;
}
valueButtons.resize(values.size());
int32_t i = 0;
float imgScale = 1.0f;
std::map<std::string, std::string>::iterator itr;
for (itr = values.begin(); itr != values.end(); itr++) {
if (i == valueID) {
topValueText.setText(itr->first.c_str());
}
valueButtons[i].valueButtonImg = new GuiImage(valueImageData);
valueButtons[i].valueButtonCheckedImg = new GuiImage(valueSelectedImageData);
valueButtons[i].valueButtonHighlightedImg = new GuiImage(valueHighlightedImageData);
valueButtons[i].valueButton = new GuiButton(valueButtons[i].valueButtonImg->getWidth() * imgScale, valueButtons[i].valueButtonImg->getHeight() * imgScale);
valueButtons[i].valueButtonText = new GuiText(itr->first.c_str(), 32, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
valueButtons[i].valueButtonText->setMaxWidth(valueButtons[i].valueButtonImg->getWidth() * imgScale - 20.0f, GuiText::WRAP);
valueButtons[i].valueButtonText->setPosition(0, 0);
valueButtons[i].valueButtonImg->setScale(imgScale);
valueButtons[i].valueButtonCheckedImg->setScale(imgScale);
valueButtons[i].valueButton->setImage(valueButtons[i].valueButtonImg);
valueButtons[i].valueButton->setIconOver(valueButtons[i].valueButtonHighlightedImg);
valueButtons[i].valueButton->setTrigger(&touchTrigger);
valueButtons[i].valueButton->setTrigger(&wpadTouchTrigger);
valueButtons[i].valueButton->clicked.connect(this, &GuiSelectBox::OnValueClicked);
valueButtons[i].valueButton->setSoundClick(buttonClickSound);
valueButtons[i].valueButton->setLabel(valueButtons[i].valueButtonText);
//valueButtons[i].valueButton->setState(STATE_HIDDEN); //Wont get disabled soon enough
buttonToValue[valueButtons[i].valueButton] = itr->second;
float topHeight = 0;
if (topBackgroundImg != NULL) {
topHeight = topBackgroundImg->getHeight();
}
int32_t ypos = (((valueButtons[i].valueButtonImg->getHeight() * getScale()) * (i)) + (topHeight - 5) * getScale()) * -1.0f;
valueButtons[i].valueButton->setPosition(0, ypos);
valuesFrame.append(valueButtons[i].valueButton);
i++;
}
//Collapse the thing!
showValues = false;
bChanged = true;
}
void GuiSelectBox::DeleteValueData() {
for (uint32_t i = 0; i < valueButtons.size(); ++i) {
valuesFrame.remove(valueButtons[i].valueButton);
delete valueButtons[i].valueButtonImg;
delete valueButtons[i].valueButtonCheckedImg;
delete valueButtons[i].valueButtonHighlightedImg;
delete valueButtons[i].valueButton;
delete valueButtons[i].valueButtonText;
}
buttonToValue.clear();
valueButtons.clear();
}
/**
* Destructor for the GuiButton class.
*/
GuiSelectBox::~GuiSelectBox() {
DeleteValueData();
bChanged = false;
selected = 0;
showValues = false;
}
void GuiSelectBox::setState(int32_t s, int32_t c) {
GuiElement::setState(s, c);
}
void GuiSelectBox::OnValueCloseEffectFinish(GuiElement *element) {
valuesFrame.effectFinished.disconnect(this);
}
float GuiSelectBox::getTopValueHeight() {
if (topBackgroundImg == NULL) {
return 0.0f;
}
return topBackgroundImg->getHeight();
}
float GuiSelectBox::getTopValueWidth() {
if (topBackgroundImg == NULL) {
return 0.0f;
}
return topBackgroundImg->getWidth();
}
float GuiSelectBox::getHeight() {
return getTopValueHeight();
}
float GuiSelectBox::getWidth() {
return getTopValueWidth();
}
void GuiSelectBox::OnValueOpenEffectFinish(GuiElement *element) {
valuesFrame.effectFinished.disconnect(this);
opened = true;
}
void GuiSelectBox::update(GuiController *c) {
if (bChanged) {
showhide(this, showValues);
if (showValues) {
for (uint32_t i = 0; i < valueButtons.size(); ++i) { //TODO: only set when it really changed
if (i == selected) {
valueButtons[i].valueButton->setImage(valueButtons[i].valueButtonCheckedImg);
} else {
valueButtons[i].valueButton->setImage(valueButtons[i].valueButtonImg);
}
}
valuesFrame.clearState(STATE_HIDDEN);
DPADButtons.clearState(STATE_DISABLE_INPUT);
valuesFrame.setEffect(EFFECT_FADE, 10, 255);
valuesFrame.effectFinished.connect(this, &GuiSelectBox::OnValueCloseEffectFinish);
} else {
opened = false;
valuesFrame.setState(STATE_HIDDEN);
DPADButtons.setState(STATE_DISABLE_INPUT);
valuesFrame.setEffect(EFFECT_FADE, -10, 0);
valuesFrame.effectFinished.connect(this, &GuiSelectBox::OnValueOpenEffectFinish);
}
bChanged = false;
}
if (bSelectedChanged) {
for (uint32_t i = 0; i < valueButtons.size(); ++i) {
if (i == selected) {
valueButtons[i].valueButton->setState(STATE_SELECTED);
} else {
valueButtons[i].valueButton->clearState(STATE_SELECTED);
}
}
}
topValueButton.setState(getState());
GuiFrame::update(c);
}

139
src/gui/GuiSelectBox.h Normal file
View File

@ -0,0 +1,139 @@
/****************************************************************************
* Copyright (C) 2016 Maschell
*
* 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/>.
****************************************************************************/
#ifndef GUI_SELECTBOX_H_
#define GUI_SELECTBOX_H_
#include <gui/Gui.h>
#include <gui/GuiImage.h>
#include <gui/GuiImageData.h>
//!A simple CheckBox
class GuiSelectBox : public GuiFrame, public sigslot::has_slots<> {
public:
//!Constructor
//!\param checked Checked
GuiSelectBox(GuiImage *background, std::string caption, float width = 0.0f, float height = 0.0f, GuiFrame *parent = 0);
//!Destructor
virtual ~GuiSelectBox();
sigslot::signal2<GuiSelectBox *, std::string> valueChanged;
sigslot::signal2<GuiSelectBox *, bool> showhide;
void setImageTopBackground(GuiImage *img) {
topBackgroundImg = img;
topValueButton.setImage(img);
}
void setImageTopHighlighted(GuiImage *img) {
topHighlightedImg = img;
topValueButton.setIconOver(img);
}
void setImageValueBackground(GuiImageData *img) {
valueImageData = img;
}
void setImageValueHighlighted(GuiImageData *img) {
valueHighlightedImageData = img;
}
void setImageValueSelected(GuiImageData *img) {
valueSelectedImageData = img;
}
void setSoundClick(GuiSound *snd) {
buttonClickSound = snd;
topValueButton.setSoundClick(snd);
}
void OnTopValueClicked(GuiButton *button, const GuiController *controller, GuiTrigger *trigger);
void Init(std::map<std::string, std::string> values, int32_t valueID);
void setState(int32_t s, int32_t c = -1);
virtual void setSize(float width, float height);
virtual float getTopValueHeight();
virtual float getTopValueWidth();
virtual float getHeight();
virtual float getWidth();
protected:
void DeleteValueData();
void update(GuiController *c);
void OnValueClicked(GuiButton *button, const GuiController *controller, GuiTrigger *trigger);
void OnDPADClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger);
void OnValueOpenEffectFinish(GuiElement *element);
void OnValueCloseEffectFinish(GuiElement *element);
void ShowHideValues(bool showhide);
void SelectValue(uint32_t value);
uint32_t selected;
bool bChanged;
bool bSelectedChanged;
bool showValues;
bool opened;
std::string captionText;
GuiFrame valuesFrame;
GuiImage *topBackgroundImg = NULL;
GuiImage *topHighlightedImg = NULL;
GuiButton topValueButton;
GuiImageData *valueImageData = NULL;
GuiImageData *valueSelectedImageData = NULL;
GuiImageData *valueHighlightedImageData = NULL;
GuiText topValueText;
GuiTrigger touchTrigger;
GuiTrigger wpadTouchTrigger;
GuiTrigger buttonATrigger;
GuiTrigger buttonBTrigger;
GuiTrigger buttonLeftTrigger;
GuiTrigger buttonRightTrigger;
GuiTrigger buttonUpTrigger;
GuiTrigger buttonDownTrigger;
GuiButton DPADButtons;
GuiSound *buttonClickSound;
typedef struct {
GuiImage *valueButtonImg;
GuiImage *valueButtonCheckedImg;
GuiImage *valueButtonHighlightedImg;
GuiButton *valueButton;
GuiText *valueButtonText;
} SelectBoxValueButton;
std::map<GuiButton *, std::string> buttonToValue;
std::vector<SelectBoxValueButton> valueButtons;
};
#endif

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

@ -0,0 +1,180 @@
/****************************************************************************
* 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 <gui/GuiSound.h>
#include <sounds/SoundHandler.hpp>
#include <stdio.h>
#include <string.h>
#include <string>
GuiSound::GuiSound(const char *filepath) {
voice = -1;
Load(filepath);
}
GuiSound::GuiSound(const uint8_t *snd, int32_t length) {
voice = -1;
Load(snd, length);
}
GuiSound::~GuiSound() {
if (voice >= 0) {
SoundHandler::instance()->RemoveDecoder(voice);
}
}
bool GuiSound::Load(const char *filepath) {
if (voice >= 0) {
SoundHandler::instance()->RemoveDecoder(voice);
voice = -1;
}
//! find next free decoder
for (int32_t i = 0; i < MAX_DECODERS; i++) {
SoundDecoder *decoder = SoundHandler::instance()->getDecoder(i);
if (decoder == NULL) {
SoundHandler::instance()->AddDecoder(i, filepath);
decoder = SoundHandler::instance()->getDecoder(i);
if (decoder) {
voice = i;
SoundHandler::instance()->ThreadSignal();
}
break;
}
}
if (voice < 0) {
return false;
}
return true;
}
bool GuiSound::Load(const uint8_t *snd, int32_t len) {
if (voice >= 0) {
SoundHandler::instance()->RemoveDecoder(voice);
voice = -1;
}
if (!snd) {
return false;
}
//! find next free decoder
for (int32_t i = 0; i < MAX_DECODERS; i++) {
SoundDecoder *decoder = SoundHandler::instance()->getDecoder(i);
if (decoder == NULL) {
SoundHandler::instance()->AddDecoder(i, snd, len);
decoder = SoundHandler::instance()->getDecoder(i);
if (decoder) {
voice = i;
SoundHandler::instance()->ThreadSignal();
}
break;
}
}
if (voice < 0) {
return false;
}
return true;
}
void GuiSound::Play() {
Stop();
Voice *v = SoundHandler::instance()->getVoice(voice);
if (v) {
v->setState(Voice::STATE_START);
}
}
void GuiSound::Stop() {
Voice *v = SoundHandler::instance()->getVoice(voice);
if (v) {
if ((v->getState() != Voice::STATE_STOP) && (v->getState() != Voice::STATE_STOPPED)) {
v->setState(Voice::STATE_STOP);
}
while (v->getState() != Voice::STATE_STOPPED)
OSSleepTicks(OSMicrosecondsToTicks(1000));
}
SoundDecoder *decoder = SoundHandler::instance()->getDecoder(voice);
if (decoder) {
decoder->Lock();
decoder->Rewind();
decoder->ClearBuffer();
SoundHandler::instance()->ThreadSignal();
decoder->Unlock();
}
}
void GuiSound::Pause() {
if (!IsPlaying()) {
return;
}
Voice *v = SoundHandler::instance()->getVoice(voice);
if (v) {
v->setState(Voice::STATE_STOP);
}
}
void GuiSound::Resume() {
if (IsPlaying()) {
return;
}
Voice *v = SoundHandler::instance()->getVoice(voice);
if (v) {
v->setState(Voice::STATE_START);
}
}
bool GuiSound::IsPlaying() {
Voice *v = SoundHandler::instance()->getVoice(voice);
if (v) {
return v->getState() == Voice::STATE_PLAYING;
}
return false;
}
void GuiSound::SetVolume(uint32_t vol) {
if (vol > 100) {
vol = 100;
}
uint32_t volumeConv = ((0x8000 * vol) / 100) << 16;
Voice *v = SoundHandler::instance()->getVoice(voice);
if (v) {
v->setVolume(volumeConv);
}
}
void GuiSound::SetLoop(bool l) {
SoundDecoder *decoder = SoundHandler::instance()->getDecoder(voice);
if (decoder) {
decoder->SetLoop(l);
}
}
void GuiSound::Rewind() {
Stop();
}

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

@ -0,0 +1,71 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef GUI_SOUND_H_
#define GUI_SOUND_H_
#include <gui/GuiElement.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);
GuiSound(const uint8_t *sound, int32_t length);
//!Destructor
virtual ~GuiSound();
//!Load a file and replace the old one
bool Load(const char *filepath);
//!Load a file and replace the old one
bool Load(const uint8_t *snd, int32_t len);
//!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);
protected:
int32_t voice; //!< Currently assigned ASND voice channel
};
#endif

80
src/gui/GuiSwitch.cpp Normal file
View File

@ -0,0 +1,80 @@
/****************************************************************************
* Copyright (C) 2016,2017 Maschell
*
* 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 <gui/GuiImage.h>
#include <gui/GuiImageData.h>
#include <gui/GuiSwitch.h>
/**
* Constructor for the GuiSwitch class.
*/
GuiSwitch::GuiSwitch(GuiImage *background, bool checked, float w, float h)
: GuiToggle(checked, w, h) {
setImageBackground(background);
}
/**
* Destructor for the GuiSwitch class.
*/
GuiSwitch::~GuiSwitch() {
}
void GuiSwitch::setImageBackground(GuiImage *img) {
backgroundImg = img;
if (img) {
img->setParent(this);
}
setImage(img);
}
void GuiSwitch::setImageOn(GuiImage *img) {
onImg = img;
if (img) {
img->setParent(this);
img->setAlignment(ALIGN_RIGHT);
}
}
void GuiSwitch::setImageOff(GuiImage *img) {
offImg = img;
if (img) {
img->setParent(this);
img->setAlignment(ALIGN_LEFT);
}
}
void GuiSwitch::setImageHighlighted(GuiImage *img) {
highlightedImg = img;
setIconOver(img);
}
void GuiSwitch::draw(CVideo *v) {
if (!this->isVisible()) {
return;
}
GuiToggle::draw(v);
if (getValue()) {
if (onImg != NULL) {
onImg->draw(v);
}
} else {
if (offImg != NULL) {
offImg->draw(v);
}
}
}

51
src/gui/GuiSwitch.h Normal file
View File

@ -0,0 +1,51 @@
/****************************************************************************
* Copyright (C) 2016,2017 Maschell
*
* 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/>.
****************************************************************************/
#ifndef GUI_SWTICH_H_
#define GUI_SWTICH_H_
#include <gui/GuiImage.h>
#include <gui/GuiImageData.h>
#include <gui/GuiToggle.h>
//!A simple switch
class GuiSwitch : public GuiToggle {
public:
//!Constructor
//!\param checked Checked
GuiSwitch(GuiImage *background, bool checked, float w = 0.0f, float h = 0.0f);
//!Destructor
virtual ~GuiSwitch();
void setImageBackground(GuiImage *img);
void setImageOn(GuiImage *img);
void setImageOff(GuiImage *img);
void setImageHighlighted(GuiImage *img);
protected:
GuiImage *backgroundImg = NULL;
GuiImage *onImg = NULL;
GuiImage *offImg = NULL;
GuiImage *highlightedImg = NULL;
void draw(CVideo *v) override;
};
#endif

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

@ -0,0 +1,704 @@
/****************************************************************************
* 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 <gui/FreeTypeGX.h>
#include <gui/GuiText.h>
#include <video/CVideo.h>
FreeTypeGX *GuiText::presentFont = NULL;
int32_t GuiText::presetSSAA = 2;
int32_t GuiText::presetSize = 28;
int32_t GuiText::presetMaxWidth = 0xFFFF;
int32_t GuiText::presetAlignment = ALIGN_CENTER | ALIGN_MIDDLE;
GX2ColorF32 GuiText::presetColor = (GX2ColorF32){
1.0f, 1.0f, 1.0f, 1.0f};
#define TEXT_SCROLL_DELAY 6
#define TEXT_SCROLL_INITIAL_DELAY 10
#define MAX_LINES_TO_DRAW 10
/**
* Constructor for the GuiText class.
*/
GuiText::GuiText() {
text = NULL;
currentSize = presetSize;
color = glm::vec4(presetColor.r, presetColor.g, presetColor.b, presetColor.a);
alpha = presetColor.a;
alignment = presetAlignment;
maxWidth = presetMaxWidth;
internalSSAA = presetSSAA;
wrapMode = 0;
font = presentFont;
linestodraw = MAX_LINES_TO_DRAW;
textScrollPos = 0;
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
textScrollDelay = TEXT_SCROLL_DELAY;
defaultBlur = 4.0f;
blurGlowIntensity = 0.0f;
blurAlpha = 0.0f;
blurGlowColor = glm::vec4(0.0f);
width = 0;
height = 0;
}
GuiText::GuiText(const char *t, int32_t s, const glm::vec4 &c) {
text = NULL;
currentSize = s;
color = c;
alpha = c[3];
alignment = ALIGN_CENTER | ALIGN_MIDDLE;
maxWidth = presetMaxWidth;
internalSSAA = presetSSAA;
wrapMode = 0;
font = presentFont;
linestodraw = MAX_LINES_TO_DRAW;
textScrollPos = 0;
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
textScrollDelay = TEXT_SCROLL_DELAY;
defaultBlur = 4.0f;
blurGlowIntensity = 0.0f;
blurAlpha = 0.0f;
blurGlowColor = glm::vec4(0.0f);
width = 0;
height = 0;
if (t) {
textMutex.lock();
text = FreeTypeGX::charToWideChar(t);
textMutex.unlock();
}
}
GuiText::GuiText(const wchar_t *t, int32_t s, const glm::vec4 &c) {
text = NULL;
currentSize = s;
color = c;
alpha = c[3];
alignment = ALIGN_CENTER | ALIGN_MIDDLE;
maxWidth = presetMaxWidth;
internalSSAA = presetSSAA;
wrapMode = 0;
font = presentFont;
linestodraw = MAX_LINES_TO_DRAW;
textScrollPos = 0;
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
textScrollDelay = TEXT_SCROLL_DELAY;
defaultBlur = 4.0f;
blurGlowIntensity = 0.0f;
blurAlpha = 0.0f;
blurGlowColor = glm::vec4(0.0f);
width = 0;
height = 0;
if (t) {
textMutex.lock();
text = new (std::nothrow) wchar_t[wcslen(t) + 1];
if (!text) {
textMutex.unlock();
return;
}
wcscpy(text, t);
textMutex.unlock();
}
}
/**
* Constructor for the GuiText class, uses presets
*/
GuiText::GuiText(const char *t) {
text = NULL;
currentSize = presetSize;
color = glm::vec4(presetColor.r, presetColor.g, presetColor.b, presetColor.a);
alpha = presetColor.a;
alignment = presetAlignment;
maxWidth = presetMaxWidth;
internalSSAA = presetSSAA;
wrapMode = 0;
font = presentFont;
linestodraw = MAX_LINES_TO_DRAW;
textScrollPos = 0;
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
textScrollDelay = TEXT_SCROLL_DELAY;
defaultBlur = 4.0f;
blurGlowIntensity = 0.0f;
blurAlpha = 0.0f;
blurGlowColor = glm::vec4(0.0f);
width = 0;
height = 0;
if (t) {
textMutex.lock();
text = FreeTypeGX::charToWideChar(t);
textMutex.unlock();
}
}
/**
* Destructor for the GuiText class.
*/
GuiText::~GuiText() {
textMutex.lock();
if (text) {
delete[] text;
}
text = NULL;
textMutex.unlock();
clearDynamicText();
}
void GuiText::setText(const char *t) {
textMutex.lock();
if (text) {
delete[] text;
}
text = NULL;
clearDynamicText();
textScrollPos = 0;
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
if (t) {
text = FreeTypeGX::charToWideChar(t);
}
textMutex.unlock();
}
void GuiText::setTextf(const char *format, ...) {
if (!format) {
setText((char *) NULL);
return;
}
int32_t max_len = strlen(format) + 8192;
char *tmp = new (std::nothrow) char[max_len];
va_list va;
va_start(va, format);
if ((vsnprintf(tmp, max_len, format, va) >= 0) && tmp) {
setText(tmp);
}
va_end(va);
if (tmp) {
delete[] tmp;
}
}
void GuiText::setText(const wchar_t *t) {
textMutex.lock();
if (text) {
delete[] text;
}
text = NULL;
clearDynamicText();
textScrollPos = 0;
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
if (t) {
text = new (std::nothrow) wchar_t[wcslen(t) + 1];
if (!text) {
textMutex.unlock();
return;
}
wcscpy(text, t);
}
textMutex.unlock();
}
void GuiText::clearDynamicText() {
textMutex.lock();
for (uint32_t i = 0; i < textDyn.size(); i++) {
if (textDyn[i]) {
delete[] textDyn[i];
}
}
textDyn.clear();
textDynWidth.clear();
textMutex.unlock();
}
void GuiText::setPresets(int32_t sz, const glm::vec4 &c, int32_t w, int32_t a) {
presetSize = sz;
presetColor = (GX2ColorF32){
(float) c.r / 255.0f, (float) c.g / 255.0f, (float) c.b / 255.0f, (float) c.a / 255.0f};
presetMaxWidth = w;
presetAlignment = a;
}
void GuiText::setPresetFont(FreeTypeGX *f) {
presentFont = f;
}
void GuiText::setFontSize(int32_t s) {
currentSize = s;
}
void GuiText::setMaxWidth(int32_t width, int32_t w) {
maxWidth = width;
wrapMode = w;
if (w == SCROLL_HORIZONTAL) {
textScrollPos = 0;
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
textScrollDelay = TEXT_SCROLL_DELAY;
}
clearDynamicText();
}
void GuiText::setColor(const glm::vec4 &c) {
color = c;
alpha = c[3];
}
void GuiText::setBlurGlowColor(float blur, const glm::vec4 &c) {
blurGlowColor = c;
blurGlowIntensity = blur;
blurAlpha = c[3];
}
int32_t GuiText::getTextWidth(int32_t ind) {
textMutex.lock();
int32_t res;
if (ind < 0 || ind >= (int32_t) textDyn.size()) {
res = this->getTextWidth();
} else {
res = font->getWidth(textDyn[ind], currentSize);
}
textMutex.unlock();
return res;
}
//!Get the Horizontal Size of Text
int32_t GuiText::getTextWidth() {
textMutex.lock();
auto res = font->getWidth(text, currentSize);
res = res > maxWidth && maxWidth > 0 ? maxWidth : res;
textMutex.unlock();
return res;
}
float GuiText::getTextHeight() {
textMutex.lock();
if (wrapMode == GuiText::WRAP && textDyn.empty()) {
if (maxWidth > 0 && font->getWidth(text, currentSize)) {
wrapText();
}
}
auto res = textDyn.empty() ? getLineHeight() : getLineHeight() * textDyn.size();
textMutex.unlock();
return res;
}
const wchar_t *GuiText::getDynText(int32_t ind) {
textMutex.lock();
const wchar_t *result;
if (ind < 0 || ind >= (int32_t) textDyn.size()) {
result = text;
} else {
result = textDyn[ind];
}
textMutex.unlock();
return result;
}
/**
* Change font
*/
bool GuiText::setFont(FreeTypeGX *f) {
if (!f) {
return false;
}
font = f;
return true;
}
std::string GuiText::toUTF8(void) const {
textMutex.lock();
if (!text) {
textMutex.unlock();
return std::string();
}
char *pUtf8 = FreeTypeGX::wideCharToUTF8(text);
textMutex.unlock();
if (!pUtf8) {
return std::string();
}
std::string strOutput(pUtf8);
delete[] pUtf8;
return strOutput;
}
void GuiText::makeDottedText() {
textMutex.lock();
int32_t pos = textDyn.size();
textDyn.resize(pos + 1);
int32_t i = 0, currentWidth = 0;
textDyn[pos] = new (std::nothrow) wchar_t[maxWidth];
if (!textDyn[pos]) {
textDyn.resize(pos);
textMutex.unlock();
return;
}
while (text[i]) {
currentWidth += font->getCharWidth(text[i], currentSize, i > 0 ? text[i - 1] : 0);
if (currentWidth >= maxWidth && i > 2) {
textDyn[pos][i - 2] = '.';
textDyn[pos][i - 1] = '.';
textDyn[pos][i] = '.';
i++;
break;
}
textDyn[pos][i] = text[i];
i++;
}
textDyn[pos][i] = 0;
textMutex.unlock();
}
void GuiText::scrollText(uint32_t frameCount) {
textMutex.lock();
if (textDyn.size() == 0) {
int32_t pos = textDyn.size();
int32_t i = 0, currentWidth = 0;
textDyn.resize(pos + 1);
textDyn[pos] = new (std::nothrow) wchar_t[maxWidth];
if (!textDyn[pos]) {
textDyn.resize(pos);
textMutex.unlock();
return;
}
while (text[i] && currentWidth < maxWidth) {
textDyn[pos][i] = text[i];
currentWidth += font->getCharWidth(text[i], currentSize, i > 0 ? text[i - 1] : 0);
++i;
}
textDyn[pos][i] = 0;
textMutex.unlock();
return;
}
if (frameCount % textScrollDelay != 0) {
textMutex.unlock();
return;
}
if (textScrollInitialDelay) {
--textScrollInitialDelay;
textMutex.unlock();
return;
}
int32_t stringlen = wcslen(text);
++textScrollPos;
if (textScrollPos > stringlen) {
textScrollPos = 0;
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
}
int32_t ch = textScrollPos;
int32_t pos = textDyn.size() - 1;
if (!textDyn[pos]) {
textDyn[pos] = new (std::nothrow) wchar_t[maxWidth];
}
if (!textDyn[pos]) {
textDyn.resize(pos);
textMutex.unlock();
return;
}
int32_t i = 0, currentWidth = 0;
while (currentWidth < maxWidth) {
if (ch > stringlen - 1) {
textDyn[pos][i++] = ' ';
currentWidth += font->getCharWidth(L' ', currentSize, ch > 0 ? text[ch - 1] : 0);
textDyn[pos][i++] = ' ';
currentWidth += font->getCharWidth(L' ', currentSize, L' ');
textDyn[pos][i++] = ' ';
currentWidth += font->getCharWidth(L' ', currentSize, L' ');
ch = 0;
if (currentWidth >= maxWidth) {
break;
}
}
textDyn[pos][i] = text[ch];
currentWidth += font->getCharWidth(text[ch], currentSize, ch > 0 ? text[ch - 1] : 0);
++ch;
++i;
}
textDyn[pos][i] = 0;
textMutex.unlock();
}
void GuiText::wrapText() {
textMutex.lock();
if (!text || textDyn.size() > 0) {
textMutex.unlock();
return;
}
int32_t i = 0;
int32_t ch = 0;
int32_t linenum = 0;
int32_t lastSpace = -1;
int32_t lastSpaceIndex = -1;
int32_t currentWidth = 0;
while (text[ch] && linenum < linestodraw) {
if (linenum >= (int32_t) textDyn.size()) {
textDyn.resize(linenum + 1);
textDyn[linenum] = new (std::nothrow) wchar_t[maxWidth];
if (!textDyn[linenum]) {
textDyn.resize(linenum);
break;
}
}
textDyn[linenum][i] = text[ch];
textDyn[linenum][i + 1] = 0;
currentWidth += font->getCharWidth(text[ch], currentSize, ch > 0 ? text[ch - 1] : 0x0000);
if (currentWidth >= maxWidth || (text[ch] == '\n')) {
if (text[ch] == '\n') {
lastSpace = -1;
lastSpaceIndex = -1;
} else if (lastSpace >= 0) {
textDyn[linenum][lastSpaceIndex] = 0; // discard space, and everything after
ch = lastSpace; // go backwards to the last space
lastSpace = -1; // we have used this space
lastSpaceIndex = -1;
}
if (linenum + 1 == linestodraw && text[ch + 1] != 0x0000) {
if (i < 2) {
i = 2;
}
textDyn[linenum][i - 2] = '.';
textDyn[linenum][i - 1] = '.';
textDyn[linenum][i] = '.';
textDyn[linenum][i + 1] = 0;
}
currentWidth = 0;
++linenum;
i = -1;
}
if (text[ch] == ' ' && i >= 0) {
lastSpace = ch;
lastSpaceIndex = i;
}
++ch;
++i;
}
textMutex.unlock();
}
/**
* We need to redefine this, because we don't want to use our width.
*/
float GuiText::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;
} 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;
}
return pCenterX;
}
/**
* We need to redefine this, because we don't want to use our height.
*/
float GuiText::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;
} 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;
}
return pCenterY;
}
/**
* Draw the text on screen
*/
void GuiText::draw(CVideo *pVideo) {
textMutex.lock();
if (!text) {
textMutex.unlock();
return;
}
if (!isVisible()) {
textMutex.unlock();
return;
}
color[3] = getAlpha();
blurGlowColor[3] = blurAlpha * getAlpha();
auto internalRenderingScale = internalSSAA == 0 ? 1 : internalSSAA << 1;
int32_t normal_size = currentSize * getScale();
int32_t internalRenderingSize = normal_size * internalRenderingScale;
auto textWidth = font->getWidth(text, normal_size);
float x_pos = getCenterX() * internalRenderingScale;
float y_pos = getCenterY() * internalRenderingScale;
if (alignment & ALIGN_TOP) {
y_pos -= getLineHeight() * getScale() * internalRenderingScale;
} else if (alignment & ALIGN_BOTTOM) {
y_pos += getLineHeight() * getScale() * internalRenderingScale;
}
if (maxWidth > 0 && maxWidth <= textWidth) {
if (wrapMode == DOTTED) { // text dotted
if (textDyn.size() == 0) {
makeDottedText();
}
if (textDynWidth.size() != textDyn.size()) {
textDynWidth.resize(textDyn.size());
for (uint32_t i = 0; i < textDynWidth.size(); i++) {
textDynWidth[i] = font->getWidth(textDyn[i], internalRenderingSize);
}
}
if (textDyn.size() > 0) {
font->drawText(pVideo, x_pos, y_pos, getDepth(), textDyn[textDyn.size() - 1], internalRenderingSize, color, alignment, textDynWidth[textDyn.size() - 1], defaultBlur, blurGlowIntensity, blurGlowColor, internalRenderingScale);
}
textMutex.unlock();
return;
} else if (wrapMode == SCROLL_HORIZONTAL) {
scrollText(pVideo->getFrameCount());
if (textDyn.size() > 0) {
font->drawText(pVideo, x_pos, y_pos, getDepth(), textDyn[textDyn.size() - 1], internalRenderingSize, color, alignment, maxWidth * internalRenderingScale * getScale(), defaultBlur, blurGlowIntensity, blurGlowColor,
internalRenderingScale);
}
textMutex.unlock();
return;
} else if (wrapMode == WRAP) {
if (textDyn.size() == 0) {
wrapText();
}
if (textDynWidth.size() != textDyn.size()) {
textDynWidth.resize(textDyn.size());
for (uint32_t i = 0; i < textDynWidth.size(); i++) {
textDynWidth[i] = font->getWidth(textDyn[i], internalRenderingSize);
}
}
float voffset = 0.0f;
if (alignment & ALIGN_MIDDLE) {
voffset = (float) (((int32_t) getLineHeight() * (textDyn.size() - 1)) >> 1) * internalRenderingScale;
}
float y_offset = 0.0f;
for (uint32_t i = 0; i < textDyn.size(); i++) {
font->drawText(pVideo, x_pos, y_pos + y_offset + voffset, getDepth(), textDyn[i], internalRenderingSize, color, alignment, textDynWidth[i], defaultBlur, blurGlowIntensity, blurGlowColor, internalRenderingScale);
y_offset -= getLineHeight() * getScale() * internalRenderingScale;
}
textMutex.unlock();
return;
}
}
auto newTextWidth = font->getWidth(text, internalRenderingSize);
font->drawText(pVideo, x_pos, y_pos, getDepth(), text, internalRenderingSize, color, alignment, newTextWidth, defaultBlur, blurGlowIntensity, blurGlowColor, internalRenderingScale);
textMutex.unlock();
}

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

@ -0,0 +1,213 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef GUI_TEXT_H_
#define GUI_TEXT_H_
#include <gui/GuiElement.h>
#include <mutex>
//!Forward declaration
class FreeTypeGX;
//!Display, manage, and manipulate text in the GUI
class GuiText : public GuiElement {
public:
//!Constructor
GuiText();
//!\param t Text
//!\param s Font size
//!\param c Font color
GuiText(const char *t, int32_t s, const glm::vec4 &c);
//!\overload
//!\param t Text
//!\param s Font size
//!\param c Font color
GuiText(const wchar_t *t, int32_t s, const glm::vec4 &c);
//!\overload
//!\Assumes SetPresets() has been called to setup preferred text attributes
//!\param t Text
GuiText(const char *t);
//!Destructor
virtual ~GuiText();
//!Sets the text of the GuiText element
//!\param t Text
virtual void setText(const char *t);
virtual void setText(const wchar_t *t);
virtual void setTextf(const char *format, ...) __attribute__((format(printf, 2, 3)));
//!Sets up preset values to be used by GuiText(t)
//!Useful when printing multiple text elements, all with the same attributes set
//!\param sz Font size
//!\param c Font color
//!\param w Maximum width of texture image (for text wrapping)
//!\param wrap Wrapmode when w>0
//!\param a Text alignment
static void setPresets(int32_t sz, const glm::vec4 &c, int32_t w, int32_t a);
static void setPresetFont(FreeTypeGX *font);
//!Sets the font size
//!\param s Font size
void setFontSize(int32_t s);
//!Sets the maximum width of the drawn texture image
//!If the text exceeds this, it is wrapped to the next line
//!\param w Maximum width
//!\param m WrapMode
void setMaxWidth(int32_t w = 0, int32_t m = WRAP);
//!Sets the font color
//!\param c Font color
void setColor(const glm::vec4 &c);
void setBlurGlowColor(float blurIntensity, const glm::vec4 &c);
void setTextBlur(float blur) {
defaultBlur = blur;
}
//!Get the original text as char
virtual const wchar_t *getText() const {
return text;
}
virtual std::string toUTF8(void) const;
//!Get the Horizontal Size of Text
int32_t getTextWidth();
int32_t getTextWidth(int32_t ind);
//!Get the max textwidth
int32_t getTextMaxWidth() {
return maxWidth;
}
float getLineHeight() {
return (float) currentSize;
}
float getTextHeight();
void setSSAA(int32_t ssaa) {
this->internalSSAA = ssaa;
};
//!Get fontsize
int32_t getFontSize() {
return currentSize;
};
//!Set max lines to draw
void setLinesToDraw(int32_t l) {
linestodraw = l;
}
//!Get current Textline (for position calculation)
const wchar_t *getDynText(int32_t ind = 0);
virtual const wchar_t *getTextLine(int32_t ind) {
return getDynText(ind);
};
//!Change the font
bool setFont(FreeTypeGX *font);
//! virtual function used in child classes
virtual int32_t getStartWidth() {
return 0;
};
//!Constantly called to draw the text
void draw(CVideo *pVideo) override;
virtual float getWidth() {
return getTextWidth();
}
virtual float getHeight() {
return getTextHeight();
}
virtual void setSize(float w, float h) {
//! We calculate the size based on the text.
this->width = 0;
this->height = 0;
}
virtual float getCenterY(void);
virtual float getCenterX(void);
//! text enums
enum {
WRAP,
DOTTED,
SCROLL_HORIZONTAL,
SCROLL_NONE
};
protected:
static FreeTypeGX *presentFont;
static int32_t presetSSAA;
static int32_t presetSize;
static int32_t presetMaxWidth;
static float presetInternalRenderingScale;
static int32_t presetAlignment;
static GX2ColorF32 presetColor;
//!Clear the dynamic text
void clearDynamicText();
//!Create a dynamic dotted text if the text is too long
void makeDottedText();
//!Scroll the text once
void scrollText(uint32_t frameCount);
//!Wrap the text to several lines
void wrapText();
mutable std::recursive_mutex textMutex;
wchar_t *text;
std::vector<wchar_t *> textDyn;
std::vector<uint16_t> textDynWidth;
int32_t wrapMode; //!< Wrapping toggle
int32_t textScrollPos; //!< Current starting index of text string for scrolling
int32_t textScrollInitialDelay; //!< Delay to wait before starting to scroll
int32_t textScrollDelay; //!< Scrolling speed
int32_t maxWidth; //!< Maximum width of the generated text object (for text wrapping)
FreeTypeGX *font;
int32_t currentSize;
int32_t linestodraw;
glm::vec4 color;
float defaultBlur;
float blurGlowIntensity;
float blurAlpha;
glm::vec4 blurGlowColor;
int32_t internalSSAA;
};
#endif

50
src/gui/GuiToggle.cpp Normal file
View File

@ -0,0 +1,50 @@
/****************************************************************************
* Copyright (C) 2016 Maschell
*
* 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 <gui/GuiToggle.h>
/**
* Constructor for the GuiToggle class.
*/
GuiToggle::GuiToggle(bool checked, float width, float height)
: GuiButton(width, height) {
bChanged = false;
selected = checked;
clicked.connect(this, &GuiToggle::OnToggleClick);
}
/**
* Destructor for the GuiButton class.
*/
GuiToggle::~GuiToggle() {
bChanged = false;
selected = false;
}
void GuiToggle::OnToggleClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger) {
if (!isStateSet(STATE_DISABLED | STATE_HIDDEN | STATE_DISABLE_INPUT)) {
if (selected) {
setUnchecked();
} else {
setChecked();
}
}
}
void GuiToggle::update(GuiController *c) {
GuiButton::update(c);
}

64
src/gui/GuiToggle.h Normal file
View File

@ -0,0 +1,64 @@
/****************************************************************************
* Copyright (C) 2016 Maschell
*
* 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/>.
****************************************************************************/
#ifndef GUI_TOGGLE_H_
#define GUI_TOGGLE_H_
#include <gui/GuiButton.h>
#include <gui/GuiFrame.h>
//!A simple CheckBox
class GuiToggle : public GuiButton, public sigslot::has_slots<> {
public:
//!Constructor
//!\param checked Checked
GuiToggle(bool checked, float width, float height);
//!Destructor
virtual ~GuiToggle();
void setValue(bool checked) {
if (selected != checked) {
selected = checked;
bChanged = true;
valueChanged(this, selected);
}
}
void setChecked() {
setValue(true);
}
void setUnchecked() {
setValue(false);
}
bool getValue() {
return selected;
}
sigslot::signal2<GuiToggle *, bool> valueChanged;
void OnToggleClick(GuiButton *button, const GuiController *controller, GuiTrigger *trigger);
protected:
bool selected;
bool bChanged;
void update(GuiController *c);
};
#endif

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

@ -0,0 +1,143 @@
/****************************************************************************
* 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 <gui/GuiController.h>
#include <gui/GuiElement.h>
#include <gui/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 & VPAD_TOUCH) && !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 & VPAD_TOUCH) && 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 & VPAD_TOUCH) && 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/>.
****************************************************************************/
#ifndef GUI_TRIGGER_H_
#define GUI_TRIGGER_H_
#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,
VPAD_TOUCH = 0x80000000,
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
};
//!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;
};
#endif

63
src/gui/VPadController.h Normal file
View File

@ -0,0 +1,63 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef VPAD_CONTROLLER_H_
#define VPAD_CONTROLLER_H_
#include <gui/GuiController.h>
#include <vpad/input.h>
class VPadController : public GuiController {
public:
//!Constructor
VPadController(int32_t channel)
: GuiController(channel) {
memset(&vpad, 0, sizeof(vpad));
}
//!Destructor
virtual ~VPadController() {}
bool update(int32_t width, int32_t height) {
lastData = data;
VPADReadError vpadError = VPAD_READ_NO_SAMPLES;
VPADRead(VPAD_CHAN_0, &vpad, 1, &vpadError);
if (vpadError == VPAD_READ_SUCCESS) {
data.buttons_r = vpad.release;
data.buttons_h = vpad.hold;
data.buttons_d = vpad.trigger;
data.validPointer = !vpad.tpNormal.validity;
data.touched = vpad.tpNormal.touched;
VPADGetTPCalibratedPoint(VPAD_CHAN_0, &tpCalib, &vpad.tpFiltered1);
//! calculate the screen offsets
data.x = -(width >> 1) + (int32_t) (((float) tpCalib.x / 1280.0f) * (float) width);
data.y = -(height >> 1) + (int32_t) (float) height - (((float) tpCalib.y / 720.0f) * (float) height);
return true;
}
return false;
}
private:
VPADStatus vpad;
VPADTouchData tpCalib;
};
#endif

217
src/gui/WPadController.h Normal file
View File

@ -0,0 +1,217 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef WPAD_CONTROLLER_H_
#define WPAD_CONTROLLER_H_
#include <gui/GuiController.h>
#include <padscore/kpad.h>
#include <padscore/wpad.h>
class WPadController : public GuiController {
public:
//!Constructor
WPadController(int32_t channel)
: GuiController(channel) {
memset(&kpadData, 0, sizeof(kpadData));
}
//!Destructor
virtual ~WPadController() {}
uint32_t remapWiiMoteButtons(uint32_t buttons) {
uint32_t conv_buttons = 0;
if (buttons & WPAD_BUTTON_LEFT) {
conv_buttons |= GuiTrigger::BUTTON_LEFT;
}
if (buttons & WPAD_BUTTON_RIGHT) {
conv_buttons |= GuiTrigger::BUTTON_RIGHT;
}
if (buttons & WPAD_BUTTON_DOWN) {
conv_buttons |= GuiTrigger::BUTTON_DOWN;
}
if (buttons & WPAD_BUTTON_UP) {
conv_buttons |= GuiTrigger::BUTTON_UP;
}
if (buttons & WPAD_BUTTON_PLUS) {
conv_buttons |= GuiTrigger::BUTTON_PLUS;
}
if (buttons & WPAD_BUTTON_2) {
conv_buttons |= GuiTrigger::BUTTON_2;
}
if (buttons & WPAD_BUTTON_1) {
conv_buttons |= GuiTrigger::BUTTON_1;
}
if (buttons & WPAD_BUTTON_B) {
conv_buttons |= GuiTrigger::BUTTON_B;
}
if (buttons & WPAD_BUTTON_A) {
conv_buttons |= GuiTrigger::BUTTON_A;
}
if (buttons & WPAD_BUTTON_MINUS) {
conv_buttons |= GuiTrigger::BUTTON_MINUS;
}
if (buttons & WPAD_BUTTON_Z) {
conv_buttons |= GuiTrigger::BUTTON_Z;
}
if (buttons & WPAD_BUTTON_C) {
conv_buttons |= GuiTrigger::BUTTON_C;
}
if (buttons & WPAD_BUTTON_HOME) {
conv_buttons |= GuiTrigger::BUTTON_HOME;
}
return conv_buttons;
}
uint32_t remapClassicButtons(uint32_t buttons) {
uint32_t conv_buttons = 0;
if (buttons & WPAD_CLASSIC_BUTTON_LEFT) {
conv_buttons |= GuiTrigger::BUTTON_LEFT;
}
if (buttons & WPAD_CLASSIC_BUTTON_RIGHT) {
conv_buttons |= GuiTrigger::BUTTON_RIGHT;
}
if (buttons & WPAD_CLASSIC_BUTTON_DOWN) {
conv_buttons |= GuiTrigger::BUTTON_DOWN;
}
if (buttons & WPAD_CLASSIC_BUTTON_UP) {
conv_buttons |= GuiTrigger::BUTTON_UP;
}
if (buttons & WPAD_CLASSIC_BUTTON_PLUS) {
conv_buttons |= GuiTrigger::BUTTON_PLUS;
}
if (buttons & WPAD_CLASSIC_BUTTON_X) {
conv_buttons |= GuiTrigger::BUTTON_X;
}
if (buttons & WPAD_CLASSIC_BUTTON_Y) {
conv_buttons |= GuiTrigger::BUTTON_Y;
}
if (buttons & WPAD_CLASSIC_BUTTON_B) {
conv_buttons |= GuiTrigger::BUTTON_B;
}
if (buttons & WPAD_CLASSIC_BUTTON_A) {
conv_buttons |= GuiTrigger::BUTTON_A;
}
if (buttons & WPAD_CLASSIC_BUTTON_MINUS) {
conv_buttons |= GuiTrigger::BUTTON_MINUS;
}
if (buttons & WPAD_CLASSIC_BUTTON_HOME) {
conv_buttons |= GuiTrigger::BUTTON_HOME;
}
if (buttons & WPAD_CLASSIC_BUTTON_ZR) {
conv_buttons |= GuiTrigger::BUTTON_ZR;
}
if (buttons & WPAD_CLASSIC_BUTTON_ZL) {
conv_buttons |= GuiTrigger::BUTTON_ZL;
}
if (buttons & WPAD_CLASSIC_BUTTON_R) {
conv_buttons |= GuiTrigger::BUTTON_R;
}
if (buttons & WPAD_CLASSIC_BUTTON_L) {
conv_buttons |= GuiTrigger::BUTTON_L;
}
return conv_buttons;
}
WPADChan getChanByInt(int32_t chan) {
if (chan == 0) {
return WPAD_CHAN_0;
}
if (chan == 1) {
return WPAD_CHAN_1;
}
if (chan == 2) {
return WPAD_CHAN_3;
}
if (chan == 3) {
return WPAD_CHAN_3;
}
return WPAD_CHAN_0;
}
bool update(int32_t width, int32_t height) {
lastData = data;
WPADExtensionType controller_type;
//! check if the controller is connected
if (WPADProbe(getChanByInt(chanIdx - 1), &controller_type) != 0) {
return false;
}
KPADRead(getChanByInt(chanIdx - 1), &kpadData, 1);
if (kpadData.extensionType <= 1) {
data.buttons_r = remapWiiMoteButtons(kpadData.release);
data.buttons_h = remapWiiMoteButtons(kpadData.hold);
data.buttons_d = remapWiiMoteButtons(kpadData.trigger);
} else {
data.buttons_r = remapClassicButtons(kpadData.classic.release);
data.buttons_h = remapClassicButtons(kpadData.classic.hold);
data.buttons_d = remapClassicButtons(kpadData.classic.trigger);
}
data.validPointer = (kpadData.posValid == 1 || kpadData.posValid == 2) && (kpadData.pos.x >= -1.0f && kpadData.pos.x <= 1.0f) && (kpadData.pos.y >= -1.0f && kpadData.pos.y <= 1.0f);
//! calculate the screen offsets if pointer is valid else leave old value
if (data.validPointer) {
data.x = (width >> 1) * kpadData.pos.x;
data.y = (height >> 1) * (-kpadData.pos.y);
if (kpadData.angle.y > 0.0f) {
data.pointerAngle = (-kpadData.angle.x + 1.0f) * 0.5f * 180.0f;
} else {
data.pointerAngle = (kpadData.angle.x + 1.0f) * 0.5f * 180.0f - 180.0f;
}
}
return true;
}
private:
KPADStatus kpadData;
uint32_t lastButtons;
};
#endif

161
src/gui/gx2_ext.h Normal file
View File

@ -0,0 +1,161 @@
#ifndef __GX2_EXTENSION_H
#define __GX2_EXTENSION_H
#include <gx2/draw.h>
#include <gx2/enum.h>
#include <gx2/mem.h>
#include <gx2/registers.h>
#include <gx2/sampler.h>
#include <gx2/shaders.h>
#include <gx2/surface.h>
#include <gx2/texture.h>
#ifdef __cplusplus
extern "C" {
#endif
#define GX2_AA_BUFFER_CLEAR_VALUE 0xCC
#define GX2_COMP_SEL_NONE 0x04040405
#define GX2_COMP_SEL_X001 0x00040405
#define GX2_COMP_SEL_XY01 0x00010405
#define GX2_COMP_SEL_XYZ1 0x00010205
#define GX2_COMP_SEL_XYZW 0x00010203
#define GX2_COMP_SEL_XXXX 0x00000000
#define GX2_COMP_SEL_YYYY 0x01010101
#define GX2_COMP_SEL_ZZZZ 0x02020202
#define GX2_COMP_SEL_WWWW 0x03030303
#define GX2_COMP_SEL_WZYX 0x03020100
#define GX2_COMP_SEL_WXYZ 0x03000102
typedef struct _GX2Color {
uint8_t r, g, b, a;
} GX2Color;
typedef struct _GX2ColorF32 {
float r, g, b, a;
} GX2ColorF32;
static const uint32_t attribute_dest_comp_selector[20] = {
GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_X001, GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_X001,
GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW,
GX2_COMP_SEL_XY01, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZ1,
GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW};
static const uint32_t texture_comp_selector[54] = {
GX2_COMP_SEL_NONE, GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_X001,
GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW,
GX2_COMP_SEL_WZYX, GX2_COMP_SEL_X001, GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XY01, GX2_COMP_SEL_NONE,
GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_NONE,
GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_WZYX, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XY01,
GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW,
GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_X001,
GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZ1,
GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01};
static inline void GX2InitDepthBuffer(GX2DepthBuffer *depthBuffer, GX2SurfaceDim dim, uint32_t width, uint32_t height, uint32_t depth, GX2SurfaceFormat format, GX2AAMode aa) {
depthBuffer->surface.dim = dim;
depthBuffer->surface.width = width;
depthBuffer->surface.height = height;
depthBuffer->surface.depth = depth;
depthBuffer->surface.mipLevels = 1;
depthBuffer->surface.format = format;
depthBuffer->surface.aa = aa;
depthBuffer->surface.use = (GX2SurfaceUse) (((format == GX2_SURFACE_FORMAT_UNORM_R24_X8) || (format == GX2_SURFACE_FORMAT_FLOAT_D24_S8)) ? GX2_SURFACE_USE_DEPTH_BUFFER : (GX2_SURFACE_USE_DEPTH_BUFFER | GX2_SURFACE_USE_TEXTURE));
depthBuffer->surface.tileMode = GX2_TILE_MODE_DEFAULT;
depthBuffer->surface.swizzle = 0;
depthBuffer->viewMip = 0;
depthBuffer->viewFirstSlice = 0;
depthBuffer->viewNumSlices = depth;
depthBuffer->depthClear = 1.0f;
depthBuffer->stencilClear = 0;
depthBuffer->hiZPtr = NULL;
depthBuffer->hiZSize = 0;
GX2CalcSurfaceSizeAndAlignment(&depthBuffer->surface);
GX2InitDepthBufferRegs(depthBuffer);
}
static inline void GX2InitColorBuffer(GX2ColorBuffer *colorBuffer, GX2SurfaceDim dim, uint32_t width, uint32_t height, uint32_t depth, GX2SurfaceFormat format, GX2AAMode aa) {
colorBuffer->surface.dim = dim;
colorBuffer->surface.width = width;
colorBuffer->surface.height = height;
colorBuffer->surface.depth = depth;
colorBuffer->surface.mipLevels = 1;
colorBuffer->surface.format = format;
colorBuffer->surface.aa = aa;
colorBuffer->surface.use = GX2_SURFACE_USE_TEXTURE_COLOR_BUFFER_TV;
colorBuffer->surface.imageSize = 0;
colorBuffer->surface.image = NULL;
colorBuffer->surface.mipmapSize = 0;
colorBuffer->surface.mipmaps = NULL;
colorBuffer->surface.tileMode = GX2_TILE_MODE_DEFAULT;
colorBuffer->surface.swizzle = 0;
colorBuffer->surface.alignment = 0;
colorBuffer->surface.pitch = 0;
uint32_t i;
for (i = 0; i < 13; i++) {
colorBuffer->surface.mipLevelOffset[i] = 0;
}
colorBuffer->viewMip = 0;
colorBuffer->viewFirstSlice = 0;
colorBuffer->viewNumSlices = depth;
colorBuffer->aaBuffer = NULL;
colorBuffer->aaSize = 0;
for (i = 0; i < 5; i++) {
colorBuffer->regs[i] = 0;
}
GX2CalcSurfaceSizeAndAlignment(&colorBuffer->surface);
GX2InitColorBufferRegs(colorBuffer);
}
static inline void GX2InitAttribStream(GX2AttribStream *attr, uint32_t location, uint32_t buffer, uint32_t offset, GX2AttribFormat format) {
attr->location = location;
attr->buffer = buffer;
attr->offset = offset;
attr->format = format;
attr->type = GX2_ATTRIB_INDEX_PER_VERTEX;
attr->aluDivisor = 0;
attr->mask = attribute_dest_comp_selector[format & 0xff];
attr->endianSwap = GX2_ENDIAN_SWAP_DEFAULT;
}
static inline void GX2InitTexture(GX2Texture *tex, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipLevels, GX2SurfaceFormat format, GX2SurfaceDim dim, GX2TileMode tile) {
tex->surface.dim = dim;
tex->surface.width = width;
tex->surface.height = height;
tex->surface.depth = depth;
tex->surface.mipLevels = mipLevels;
tex->surface.format = format;
tex->surface.aa = GX2_AA_MODE1X;
tex->surface.use = GX2_SURFACE_USE_TEXTURE;
tex->surface.imageSize = 0;
tex->surface.image = NULL;
tex->surface.mipmapSize = 0;
tex->surface.mipmaps = NULL;
tex->surface.tileMode = tile;
tex->surface.swizzle = 0;
tex->surface.alignment = 0;
tex->surface.pitch = 0;
uint32_t i;
for (i = 0; i < 13; i++) {
tex->surface.mipLevelOffset[i] = 0;
}
tex->viewFirstMip = 0;
tex->viewNumMips = mipLevels;
tex->viewFirstSlice = 0;
tex->viewNumSlices = depth;
tex->compMap = texture_comp_selector[format & 0x3f];
for (i = 0; i < 5; i++) {
tex->regs[i] = 0;
}
GX2CalcSurfaceSizeAndAlignment(&tex->surface);
GX2InitTextureRegs(tex);
}
#ifdef __cplusplus
}
#endif
#endif

2452
src/gui/sigslot.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -8,11 +8,11 @@ class GameSplashScreen : public GuiFrame, public sigslot::has_slots<> {
public:
GameSplashScreen(int32_t w, int32_t h, gameInfo *info, bool onTV);
virtual ~GameSplashScreen();
~GameSplashScreen() override;
void OnSplashScreenFadeInDone(GuiElement *element);
virtual void draw(CVideo *v);
void draw(CVideo *v) override;
sigslot::signal3<GuiElement *, gameInfo *, bool> gameGameSplashScreenFinished;
private:

View File

@ -403,10 +403,6 @@ void MainWindow::OnGameLaunchSplashScreenFinished(GuiElement *element, gameInfo
}
}
extern "C" int32_t SYSSwitchToBrowser(void *);
extern "C" int32_t SYSSwitchToEShop(void *);
extern "C" int32_t _SYSSwitchTo(uint32_t pfid);
void MainWindow::OnGameLaunch(uint64_t titleId) {
DEBUG_FUNCTION_LINE("Launch GAME!!");
@ -422,6 +418,7 @@ void MainWindow::OnGameLaunch(uint64_t titleId) {
titleId == 0x000500301001200AL) {
DEBUG_FUNCTION_LINE("Launching the browser");
SYSSwitchToBrowser(nullptr);
return;
}
if (titleId == 0x000500301001400AL ||
@ -436,28 +433,28 @@ void MainWindow::OnGameLaunch(uint64_t titleId) {
titleId == 0x000500301001810AL ||
titleId == 0x000500301001820AL) {
DEBUG_FUNCTION_LINE("Launching the Download Management");
_SYSSwitchTo(12);
_SYSSwitchTo(SYSAPP_PFID_DOWNLOAD_MANAGEMENT);
return;
}
if (titleId == 0x000500301001600AL ||
titleId == 0x000500301001610AL ||
titleId == 0x000500301001620AL) {
DEBUG_FUNCTION_LINE("Launching Miiverse");
_SYSSwitchTo(9);
_SYSSwitchTo(SYSAPP_PFID_MIIVERSE);
return;
}
if (titleId == 0x000500301001500AL ||
titleId == 0x000500301001510AL ||
titleId == 0x000500301001520AL) {
DEBUG_FUNCTION_LINE("Launching Friendlist");
_SYSSwitchTo(11);
_SYSSwitchTo(SYSAPP_PFID_FRIENDLIST);
return;
}
if (titleId == 0x000500301001300AL ||
titleId == 0x000500301001310AL ||
titleId == 0x000500301001320AL) {
DEBUG_FUNCTION_LINE("Launching TVii");
_SYSSwitchTo(3);
_SYSSwitchTo(SYSAPP_PFID_TVII);
return;
}
@ -467,7 +464,7 @@ void MainWindow::OnGameLaunch(uint64_t titleId) {
MCP_Close(handle);
if (err == 0) {
ACPAssignTitlePatch(&titleInfo);
_SYSLaunchTitleWithStdArgsInNoSplash(titleId, nullptr);
_SYSLaunchTitleByPathFromLauncher(titleInfo.path, strlen(titleInfo.path));
return;
}

136
src/sounds/BufferCircle.cpp Normal file
View File

@ -0,0 +1,136 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#include <sounds/BufferCircle.hpp>
#include <malloc.h>
#include <utils/utils.h>
BufferCircle::BufferCircle() {
which = 0;
BufferBlockSize = 0;
}
BufferCircle::~BufferCircle() {
FreeBuffer();
SoundBuffer.clear();
BufferSize.clear();
BufferReady.clear();
}
void BufferCircle::SetBufferBlockSize(int32_t size) {
if (size < 0) {
return;
}
BufferBlockSize = size;
for (int32_t i = 0; i < Size(); i++) {
if (SoundBuffer[i] != NULL) {
free(SoundBuffer[i]);
}
SoundBuffer[i] = (uint8_t *) memalign(32, ALIGN32(BufferBlockSize));
BufferSize[i] = 0;
BufferReady[i] = false;
}
}
void BufferCircle::Resize(int32_t size) {
while (size < Size())
RemoveBuffer(Size() - 1);
int32_t oldSize = Size();
SoundBuffer.resize(size);
BufferSize.resize(size);
BufferReady.resize(size);
for (int32_t i = oldSize; i < Size(); i++) {
if (BufferBlockSize > 0) {
SoundBuffer[i] = (uint8_t *) memalign(32, ALIGN32(BufferBlockSize));
} else {
SoundBuffer[i] = NULL;
}
BufferSize[i] = 0;
BufferReady[i] = false;
}
}
void BufferCircle::RemoveBuffer(int32_t pos) {
if (!Valid(pos)) {
return;
}
if (SoundBuffer[pos] != NULL) {
free(SoundBuffer[pos]);
}
SoundBuffer.erase(SoundBuffer.begin() + pos);
BufferSize.erase(BufferSize.begin() + pos);
BufferReady.erase(BufferReady.begin() + pos);
}
void BufferCircle::ClearBuffer() {
for (int32_t i = 0; i < Size(); i++) {
BufferSize[i] = 0;
BufferReady[i] = false;
}
which = 0;
}
void BufferCircle::FreeBuffer() {
for (int32_t i = 0; i < Size(); i++) {
if (SoundBuffer[i] != NULL) {
free(SoundBuffer[i]);
}
SoundBuffer[i] = NULL;
BufferSize[i] = 0;
BufferReady[i] = false;
}
}
void BufferCircle::LoadNext() {
BufferReady[which] = false;
BufferSize[which] = 0;
which = Next();
}
void BufferCircle::SetBufferReady(int32_t pos, bool state) {
if (!Valid(pos)) {
return;
}
BufferReady[pos] = state;
}
void BufferCircle::SetBufferSize(int32_t pos, int32_t size) {
if (!Valid(pos)) {
return;
}
BufferSize[pos] = size;
}

143
src/sounds/BufferCircle.hpp Normal file
View File

@ -0,0 +1,143 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#ifndef BUFFER_CIRCLE_HPP_
#define BUFFER_CIRCLE_HPP_
#include <cstddef>
#include <stdint.h>
#include <vector>
class BufferCircle {
public:
//!> Constructor
BufferCircle();
//!> Destructor
~BufferCircle();
//!> Set circle size
void Resize(int32_t size);
//!> Get the circle size
int32_t Size() {
return SoundBuffer.size();
};
//!> Set/resize the buffer size
void SetBufferBlockSize(int32_t size);
//!> Remove a buffer
void RemoveBuffer(int32_t pos);
//!> Set all buffers clear
void ClearBuffer();
//!> Free all buffers
void FreeBuffer();
//!> Switch to next buffer
void LoadNext();
//!> Get the current buffer
uint8_t *GetBuffer() {
return GetBuffer(which);
};
//!> Get a buffer at a position
uint8_t *GetBuffer(int32_t pos) {
if (!Valid(pos)) {
return NULL;
} else {
return SoundBuffer[pos];
}
};
//!> Get current buffer size
uint32_t GetBufferSize() {
return GetBufferSize(which);
};
//!> Get buffer size at position
uint32_t GetBufferSize(int32_t pos) {
if (!Valid(pos)) {
return 0;
} else {
return BufferSize[pos];
}
};
//!> Is current buffer ready
bool IsBufferReady() {
return IsBufferReady(which);
};
//!> Is a buffer at a position ready
bool IsBufferReady(int32_t pos) {
if (!Valid(pos)) {
return false;
} else {
return BufferReady[pos];
}
};
//!> Set a buffer at a position to a ready state
void SetBufferReady(int32_t pos, bool st);
//!> Set the buffersize at a position
void SetBufferSize(int32_t pos, int32_t size);
//!> Get the current position in the circle
uint16_t Which() {
return which;
};
//!> Get the next location
inline uint16_t Next() {
return (which + 1 >= Size()) ? 0 : which + 1;
}
inline uint16_t Prev() {
if (Size() == 0) {
return 0;
} else {
return ((int32_t) which - 1 < 0) ? Size() - 1 : which - 1;
}
}
protected:
//!> Check if the position is a valid position in the vector
bool Valid(int32_t pos) {
return !(pos < 0 || pos >= Size());
};
uint16_t which;
uint32_t BufferBlockSize;
std::vector<uint8_t *> SoundBuffer;
std::vector<uint32_t> BufferSize;
std::vector<bool> BufferReady;
};
#endif

213
src/sounds/Mp3Decoder.cpp Normal file
View File

@ -0,0 +1,213 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#include "fs/CFile.hpp"
#include <coreinit/thread.h>
#include <coreinit/time.h>
#include <sounds/Mp3Decoder.hpp>
#include <limits.h>
#include <malloc.h>
#include <math.h>
#include <string.h>
#include <string>
#include <unistd.h>
Mp3Decoder::Mp3Decoder(const char *filepath)
: SoundDecoder(filepath) {
SoundType = SOUND_MP3;
ReadBuffer = NULL;
mad_timer_reset(&Timer);
mad_stream_init(&Stream);
mad_frame_init(&Frame);
mad_synth_init(&Synth);
if (!file_fd) {
return;
}
OpenFile();
}
Mp3Decoder::Mp3Decoder(const uint8_t *snd, int32_t len)
: SoundDecoder(snd, len) {
SoundType = SOUND_MP3;
ReadBuffer = NULL;
mad_timer_reset(&Timer);
mad_stream_init(&Stream);
mad_frame_init(&Frame);
mad_synth_init(&Synth);
if (!file_fd) {
return;
}
OpenFile();
}
Mp3Decoder::~Mp3Decoder() {
ExitRequested = true;
while (Decoding)
OSSleepTicks(OSMicrosecondsToTicks(100));
mad_synth_finish(&Synth);
mad_frame_finish(&Frame);
mad_stream_finish(&Stream);
if (ReadBuffer) {
free(ReadBuffer);
}
ReadBuffer = NULL;
}
void Mp3Decoder::OpenFile() {
GuardPtr = NULL;
ReadBuffer = (uint8_t *) memalign(32, SoundBlockSize * SoundBlocks);
if (!ReadBuffer) {
if (file_fd) {
delete file_fd;
}
file_fd = NULL;
return;
}
uint8_t dummybuff[4096];
int32_t ret = Read(dummybuff, 4096, 0);
if (ret <= 0) {
if (file_fd) {
delete file_fd;
}
file_fd = NULL;
return;
}
SampleRate = (uint32_t) Frame.header.samplerate;
Format = ((MAD_NCHANNELS(&Frame.header) == 2) ? (FORMAT_PCM_16_BIT | CHANNELS_STEREO) : (FORMAT_PCM_16_BIT | CHANNELS_MONO));
Rewind();
}
int32_t Mp3Decoder::Rewind() {
mad_synth_finish(&Synth);
mad_frame_finish(&Frame);
mad_stream_finish(&Stream);
mad_timer_reset(&Timer);
mad_stream_init(&Stream);
mad_frame_init(&Frame);
mad_synth_init(&Synth);
SynthPos = 0;
GuardPtr = NULL;
if (!file_fd) {
return -1;
}
return SoundDecoder::Rewind();
}
static inline int16_t FixedToShort(mad_fixed_t Fixed) {
/* Clipping */
if (Fixed >= MAD_F_ONE) {
return (SHRT_MAX);
}
if (Fixed <= -MAD_F_ONE) {
return (-SHRT_MAX);
}
Fixed = Fixed >> (MAD_F_FRACBITS - 15);
return ((int16_t) Fixed);
}
int32_t Mp3Decoder::Read(uint8_t *buffer, int32_t buffer_size, int32_t pos) {
if (!file_fd) {
return -1;
}
if (Format == (FORMAT_PCM_16_BIT | CHANNELS_STEREO)) {
buffer_size &= ~0x0003;
} else {
buffer_size &= ~0x0001;
}
uint8_t *write_pos = buffer;
uint8_t *write_end = buffer + buffer_size;
while (1) {
while (SynthPos < Synth.pcm.length) {
if (write_pos >= write_end) {
return write_pos - buffer;
}
*((int16_t *) write_pos) = FixedToShort(Synth.pcm.samples[0][SynthPos]);
write_pos += 2;
if (MAD_NCHANNELS(&Frame.header) == 2) {
*((int16_t *) write_pos) = FixedToShort(Synth.pcm.samples[1][SynthPos]);
write_pos += 2;
}
SynthPos++;
}
if (Stream.buffer == NULL || Stream.error == MAD_ERROR_BUFLEN) {
uint8_t *ReadStart = ReadBuffer;
int32_t ReadSize = SoundBlockSize * SoundBlocks;
int32_t Remaining = 0;
if (Stream.next_frame != NULL) {
Remaining = Stream.bufend - Stream.next_frame;
memmove(ReadBuffer, Stream.next_frame, Remaining);
ReadStart += Remaining;
ReadSize -= Remaining;
}
ReadSize = file_fd->read(ReadStart, ReadSize);
if (ReadSize <= 0) {
GuardPtr = ReadStart;
memset(GuardPtr, 0, MAD_BUFFER_GUARD);
ReadSize = MAD_BUFFER_GUARD;
}
CurPos += ReadSize;
mad_stream_buffer(&Stream, ReadBuffer, Remaining + ReadSize);
}
if (mad_frame_decode(&Frame, &Stream)) {
if (MAD_RECOVERABLE(Stream.error)) {
if (Stream.error != MAD_ERROR_LOSTSYNC || !GuardPtr) {
continue;
}
} else {
if (Stream.error != MAD_ERROR_BUFLEN) {
return -1;
} else if (Stream.error == MAD_ERROR_BUFLEN && GuardPtr) {
return -1;
}
}
}
mad_timer_add(&Timer, Frame.header.duration);
mad_synth_frame(&Synth, &Frame);
SynthPos = 0;
}
return 0;
}

52
src/sounds/Mp3Decoder.hpp Normal file
View File

@ -0,0 +1,52 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#include <mad.h>
#include <sounds/SoundDecoder.hpp>
class Mp3Decoder : public SoundDecoder {
public:
Mp3Decoder(const char *filepath);
Mp3Decoder(const uint8_t *sound, int32_t len);
virtual ~Mp3Decoder();
int32_t Rewind();
int32_t Read(uint8_t *buffer, int32_t buffer_size, int32_t pos);
protected:
void OpenFile();
struct mad_stream Stream;
struct mad_frame Frame;
struct mad_synth Synth;
mad_timer_t Timer;
uint8_t *GuardPtr;
uint8_t *ReadBuffer;
uint32_t SynthPos;
};

133
src/sounds/OggDecoder.cpp Normal file
View File

@ -0,0 +1,133 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#include "fs/CFile.hpp"
#include <coreinit/thread.h>
#include <coreinit/time.h>
#include <sounds/OggDecoder.hpp>
#include <malloc.h>
#include <unistd.h>
static int ogg_read(void *punt, int bytes, int blocks, int *f) {
return ((CFile *) f)->read((uint8_t *) punt, bytes * blocks);
}
static int ogg_seek(int *f, ogg_int64_t offset, int mode) {
return ((CFile *) f)->seek((uint64_t) offset, mode);
}
static int ogg_close(int *f) {
((CFile *) f)->close();
return 0;
}
static long ogg_tell(int *f) {
return (long) ((CFile *) f)->tell();
}
static ov_callbacks callbacks = {
(size_t(*)(void *, size_t, size_t, void *)) ogg_read,
(int (*)(void *, ogg_int64_t, int)) ogg_seek,
(int (*)(void *)) ogg_close,
(long (*)(void *)) ogg_tell};
OggDecoder::OggDecoder(const char *filepath)
: SoundDecoder(filepath) {
SoundType = SOUND_OGG;
if (!file_fd) {
return;
}
OpenFile();
}
OggDecoder::OggDecoder(const uint8_t *snd, int32_t len)
: SoundDecoder(snd, len) {
SoundType = SOUND_OGG;
if (!file_fd) {
return;
}
OpenFile();
}
OggDecoder::~OggDecoder() {
ExitRequested = true;
while (Decoding)
OSSleepTicks(OSMicrosecondsToTicks(100));
if (file_fd) {
ov_clear(&ogg_file);
}
}
void OggDecoder::OpenFile() {
if (ov_open_callbacks(file_fd, &ogg_file, NULL, 0, callbacks) < 0) {
delete file_fd;
file_fd = NULL;
return;
}
ogg_info = ov_info(&ogg_file, -1);
if (!ogg_info) {
ov_clear(&ogg_file);
delete file_fd;
file_fd = NULL;
return;
}
Format = ((ogg_info->channels == 2) ? (FORMAT_PCM_16_BIT | CHANNELS_STEREO) : (FORMAT_PCM_16_BIT | CHANNELS_MONO));
SampleRate = ogg_info->rate;
}
int32_t OggDecoder::Rewind() {
if (!file_fd) {
return -1;
}
int32_t ret = ov_time_seek(&ogg_file, 0);
CurPos = 0;
EndOfFile = false;
return ret;
}
int32_t OggDecoder::Read(uint8_t *buffer, int32_t buffer_size, int32_t pos) {
if (!file_fd) {
return -1;
}
int32_t bitstream = 0;
int32_t read = (int32_t) ov_read(&ogg_file, (char *) buffer, (int) buffer_size, (int *) &bitstream);
if (read > 0) {
CurPos += read;
}
return read;
}

48
src/sounds/OggDecoder.hpp Normal file
View File

@ -0,0 +1,48 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#include <tremor/ivorbiscodec.h>
#include <tremor/ivorbisfile.h>
#include <sounds/SoundDecoder.hpp>
class OggDecoder : public SoundDecoder {
public:
OggDecoder(const char *filepath);
OggDecoder(const uint8_t *snd, int32_t len);
virtual ~OggDecoder();
int32_t Rewind();
int32_t Read(uint8_t *buffer, int32_t buffer_size, int32_t pos);
protected:
void OpenFile();
OggVorbis_File ogg_file;
vorbis_info *ogg_info;
};

211
src/sounds/SoundDecoder.cpp Normal file
View File

@ -0,0 +1,211 @@
/****************************************************************************
* Copyright (C) 2009-2013 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 "fs/CFile.hpp"
#include <coreinit/cache.h>
#include <coreinit/thread.h>
#include <coreinit/time.h>
#include <sounds/SoundDecoder.hpp>
#include <malloc.h>
#include <string.h>
#include <unistd.h>
static const uint32_t FixedPointShift = 15;
static const uint32_t FixedPointScale = 1 << FixedPointShift;
SoundDecoder::SoundDecoder() {
file_fd = NULL;
Init();
}
SoundDecoder::SoundDecoder(const std::string &filepath) {
file_fd = new CFile(filepath, CFile::ReadOnly);
Init();
}
SoundDecoder::SoundDecoder(const uint8_t *buffer, int32_t size) {
file_fd = new CFile(buffer, size);
Init();
}
SoundDecoder::~SoundDecoder() {
ExitRequested = true;
while (Decoding)
OSSleepTicks(OSMicrosecondsToTicks(1000));
//! lock unlock once to make sure it's really not decoding
Lock();
Unlock();
if (file_fd) {
delete file_fd;
}
file_fd = NULL;
if (ResampleBuffer) {
free(ResampleBuffer);
}
}
int32_t SoundDecoder::Seek(int32_t pos) {
CurPos = pos;
return file_fd->seek(CurPos, SEEK_SET);
}
void SoundDecoder::Init() {
SoundType = SOUND_RAW;
SoundBlocks = 8;
SoundBlockSize = 0x4000;
ResampleTo48kHz = false;
CurPos = 0;
whichLoad = 0;
Loop = false;
EndOfFile = false;
Decoding = false;
ExitRequested = false;
SoundBuffer.SetBufferBlockSize(SoundBlockSize);
SoundBuffer.Resize(SoundBlocks);
ResampleBuffer = NULL;
ResampleRatio = 0;
}
int32_t SoundDecoder::Rewind() {
CurPos = 0;
EndOfFile = false;
file_fd->rewind();
return 0;
}
int32_t SoundDecoder::Read(uint8_t *buffer, int32_t buffer_size, int32_t pos) {
int32_t ret = file_fd->read(buffer, buffer_size);
CurPos += ret;
return ret;
}
void SoundDecoder::EnableUpsample(void) {
if ((ResampleBuffer == NULL) && IsStereo() && Is16Bit() && SampleRate != 32000 && SampleRate != 48000) {
ResampleBuffer = (uint8_t *) memalign(32, SoundBlockSize);
ResampleRatio = (FixedPointScale * SampleRate) / 48000;
SoundBlockSize = (SoundBlockSize * ResampleRatio) / FixedPointScale;
SoundBlockSize &= ~0x03;
// set new sample rate
SampleRate = 48000;
}
}
void SoundDecoder::Upsample(int16_t *src, int16_t *dst, uint32_t nr_src_samples, uint32_t nr_dst_samples) {
int32_t timer = 0;
for (uint32_t i = 0, n = 0; i < nr_dst_samples; i += 2) {
if ((n + 3) < nr_src_samples) {
// simple fixed point linear interpolation
dst[i] = src[n] + (((src[n + 2] - src[n]) * timer) >> FixedPointShift);
dst[i + 1] = src[n + 1] + (((src[n + 3] - src[n + 1]) * timer) >> FixedPointShift);
} else {
dst[i] = src[n];
dst[i + 1] = src[n + 1];
}
timer += ResampleRatio;
if (timer >= (int32_t) FixedPointScale) {
n += 2;
timer -= FixedPointScale;
}
}
}
void SoundDecoder::Decode() {
if (!file_fd || ExitRequested || EndOfFile) {
return;
}
// check if we are not at the pre-last buffer (last buffer is playing)
uint16_t whichPlaying = SoundBuffer.Which();
if (((whichPlaying == 0) && (whichLoad == SoundBuffer.Size() - 2)) || ((whichPlaying == 1) && (whichLoad == SoundBuffer.Size() - 1)) || (whichLoad == (whichPlaying - 2))) {
return;
}
Decoding = true;
int32_t done = 0;
uint8_t *write_buf = SoundBuffer.GetBuffer(whichLoad);
if (!write_buf) {
ExitRequested = true;
Decoding = false;
return;
}
if (ResampleTo48kHz && !ResampleBuffer) {
EnableUpsample();
}
while (done < SoundBlockSize) {
int32_t ret = Read(&write_buf[done], SoundBlockSize - done, Tell());
if (ret <= 0) {
if (Loop) {
Rewind();
continue;
} else {
EndOfFile = true;
break;
}
}
done += ret;
}
if (done > 0) {
// check if we need to resample
if (ResampleBuffer && ResampleRatio) {
memcpy(ResampleBuffer, write_buf, done);
int32_t src_samples = done >> 1;
int32_t dest_samples = (src_samples * FixedPointScale) / ResampleRatio;
dest_samples &= ~0x01;
Upsample((int16_t *) ResampleBuffer, (int16_t *) write_buf, src_samples, dest_samples);
done = dest_samples << 1;
}
//! TODO: remove this later and add STEREO support with two voices, for now we convert to MONO
if (IsStereo()) {
int16_t *monoBuf = (int16_t *) write_buf;
done = done >> 1;
for (int32_t i = 0; i < done; i++) {
monoBuf[i] = monoBuf[i << 1];
}
}
DCFlushRange(write_buf, done);
SoundBuffer.SetBufferSize(whichLoad, done);
SoundBuffer.SetBufferReady(whichLoad, true);
if (++whichLoad >= SoundBuffer.Size()) {
whichLoad = 0;
}
}
// check if next in queue needs to be filled as well and do so
if (!SoundBuffer.IsBufferReady(whichLoad)) {
Decode();
}
Decoding = false;
}

162
src/sounds/SoundDecoder.hpp Normal file
View File

@ -0,0 +1,162 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#ifndef SOUND_DECODER_HPP
#define SOUND_DECODER_HPP
#include <sounds/BufferCircle.hpp>
#include <mutex>
#include <string>
class CFile;
class SoundDecoder {
public:
SoundDecoder();
SoundDecoder(const std::string &filepath);
SoundDecoder(const uint8_t *buffer, int32_t size);
virtual ~SoundDecoder();
virtual void Lock() {
mutex.lock();
}
virtual void Unlock() {
mutex.unlock();
}
virtual int32_t Read(uint8_t *buffer, int32_t buffer_size, int32_t pos);
virtual int32_t Tell() {
return CurPos;
}
virtual int32_t Seek(int32_t pos);
virtual int32_t Rewind();
virtual uint16_t GetFormat() {
return Format;
}
virtual uint16_t GetSampleRate() {
return SampleRate;
}
virtual void Decode();
virtual bool IsBufferReady() {
return SoundBuffer.IsBufferReady();
}
virtual uint8_t *GetBuffer() {
return SoundBuffer.GetBuffer();
}
virtual uint32_t GetBufferSize() {
return SoundBuffer.GetBufferSize();
}
virtual void LoadNext() {
SoundBuffer.LoadNext();
}
virtual bool IsEOF() {
return EndOfFile;
}
virtual void SetLoop(bool l) {
Loop = l;
EndOfFile = false;
}
virtual uint8_t GetSoundType() {
return SoundType;
}
virtual void ClearBuffer() {
SoundBuffer.ClearBuffer();
whichLoad = 0;
}
virtual bool IsStereo() {
return (GetFormat() & CHANNELS_STEREO) != 0;
}
virtual bool Is16Bit() {
return ((GetFormat() & 0xFF) == FORMAT_PCM_16_BIT);
}
virtual bool IsDecoding() {
return Decoding;
}
void EnableUpsample(void);
enum SoundFormats {
FORMAT_PCM_16_BIT = 0x0A,
FORMAT_PCM_8_BIT = 0x19,
};
enum SoundChannels {
CHANNELS_MONO = 0x100,
CHANNELS_STEREO = 0x200
};
enum SoundType {
SOUND_RAW = 0,
SOUND_MP3,
SOUND_OGG,
SOUND_WAV
};
protected:
void Init();
void Upsample(int16_t *src, int16_t *dst, uint32_t nr_src_samples, uint32_t nr_dst_samples);
CFile *file_fd;
BufferCircle SoundBuffer;
uint8_t SoundType;
uint16_t whichLoad;
uint16_t SoundBlocks;
int32_t SoundBlockSize;
int32_t CurPos;
bool ResampleTo48kHz;
bool Loop;
bool EndOfFile;
bool Decoding;
bool ExitRequested;
uint16_t Format;
uint16_t SampleRate;
uint8_t *ResampleBuffer;
uint32_t ResampleRatio;
std::recursive_mutex mutex;
};
#endif

330
src/sounds/SoundHandler.cpp Normal file
View File

@ -0,0 +1,330 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#include <fs/CFile.hpp>
#include <sounds/Mp3Decoder.hpp>
#include <sounds/OggDecoder.hpp>
#include <sounds/SoundHandler.hpp>
#include <sounds/WavDecoder.hpp>
#include <malloc.h>
#include <sndcore2/core.h>
#include <unistd.h>
SoundHandler *SoundHandler::handlerInstance = NULL;
SoundHandler::SoundHandler()
: CThread(CThread::eAttributeAffCore1 | CThread::eAttributePinnedAff, 0, 0x8000) {
Decoding = false;
ExitRequested = false;
for (uint32_t i = 0; i < MAX_DECODERS; ++i) {
DecoderList[i] = NULL;
voiceList[i] = NULL;
}
resumeThread();
//! wait for initialization
while (!isThreadSuspended())
OSSleepTicks(OSMicrosecondsToTicks(1000));
}
SoundHandler::~SoundHandler() {
ExitRequested = true;
ThreadSignal();
ClearDecoderList();
}
void SoundHandler::AddDecoder(int32_t voice, const char *filepath) {
if (voice < 0 || voice >= MAX_DECODERS) {
return;
}
if (DecoderList[voice] != NULL) {
RemoveDecoder(voice);
}
DecoderList[voice] = GetSoundDecoder(filepath);
}
void SoundHandler::AddDecoder(int32_t voice, const uint8_t *snd, int32_t len) {
if (voice < 0 || voice >= MAX_DECODERS) {
return;
}
if (DecoderList[voice] != NULL) {
RemoveDecoder(voice);
}
DecoderList[voice] = GetSoundDecoder(snd, len);
}
void SoundHandler::RemoveDecoder(int32_t voice) {
if (voice < 0 || voice >= MAX_DECODERS) {
return;
}
if (DecoderList[voice] != NULL) {
if (voiceList[voice] && voiceList[voice]->getState() != Voice::STATE_STOPPED) {
if (voiceList[voice]->getState() != Voice::STATE_STOP) {
voiceList[voice]->setState(Voice::STATE_STOP);
}
// it shouldn't take longer than 3 ms actually but we wait up to 20
// on application quit the AX frame callback is not called anymore
// therefore this would end in endless loop if no timeout is defined
int timeOut = 20;
while (--timeOut && (voiceList[voice]->getState() != Voice::STATE_STOPPED))
OSSleepTicks(OSMicrosecondsToTicks(1000));
}
SoundDecoder *decoder = DecoderList[voice];
decoder->Lock();
DecoderList[voice] = NULL;
decoder->Unlock();
delete decoder;
}
}
void SoundHandler::ClearDecoderList() {
for (uint32_t i = 0; i < MAX_DECODERS; ++i) {
RemoveDecoder(i);
}
}
static inline bool CheckMP3Signature(const uint8_t *buffer) {
const char MP3_Magic[][3] = {
{'I', 'D', '3'}, //'ID3'
{0xff, 0xfe}, //'MPEG ADTS, layer III, v1.0 [protected]', 'mp3', 'audio/mpeg'),
{0xff, 0xff}, //'MPEG ADTS, layer III, v1.0', 'mp3', 'audio/mpeg'),
{0xff, 0xfa}, //'MPEG ADTS, layer III, v1.0 [protected]', 'mp3', 'audio/mpeg'),
{0xff, 0xfb}, //'MPEG ADTS, layer III, v1.0', 'mp3', 'audio/mpeg'),
{0xff, 0xf2}, //'MPEG ADTS, layer III, v2.0 [protected]', 'mp3', 'audio/mpeg'),
{0xff, 0xf3}, //'MPEG ADTS, layer III, v2.0', 'mp3', 'audio/mpeg'),
{0xff, 0xf4}, //'MPEG ADTS, layer III, v2.0 [protected]', 'mp3', 'audio/mpeg'),
{0xff, 0xf5}, //'MPEG ADTS, layer III, v2.0', 'mp3', 'audio/mpeg'),
{0xff, 0xf6}, //'MPEG ADTS, layer III, v2.0 [protected]', 'mp3', 'audio/mpeg'),
{0xff, 0xf7}, //'MPEG ADTS, layer III, v2.0', 'mp3', 'audio/mpeg'),
{0xff, 0xe2}, //'MPEG ADTS, layer III, v2.5 [protected]', 'mp3', 'audio/mpeg'),
{0xff, 0xe3}, //'MPEG ADTS, layer III, v2.5', 'mp3', 'audio/mpeg'),
};
if (buffer[0] == MP3_Magic[0][0] && buffer[1] == MP3_Magic[0][1] &&
buffer[2] == MP3_Magic[0][2]) {
return true;
}
for (int32_t i = 1; i < 13; i++) {
if (buffer[0] == MP3_Magic[i][0] && buffer[1] == MP3_Magic[i][1]) {
return true;
}
}
return false;
}
SoundDecoder *SoundHandler::GetSoundDecoder(const char *filepath) {
uint32_t magic;
CFile f(filepath, CFile::ReadOnly);
if (f.size() == 0) {
return NULL;
}
do {
f.read((uint8_t *) &magic, 1);
} while (((uint8_t *) &magic)[0] == 0 && f.tell() < f.size());
if (f.tell() == f.size()) {
return NULL;
}
f.seek(f.tell() - 1, SEEK_SET);
f.read((uint8_t *) &magic, 4);
f.close();
if (magic == 0x4f676753) { // 'OggS'
return new OggDecoder(filepath);
} else if (magic == 0x52494646) { // 'RIFF'
return new WavDecoder(filepath);
} else if (CheckMP3Signature((uint8_t *) &magic) == true) {
return new Mp3Decoder(filepath);
}
return new SoundDecoder(filepath);
}
SoundDecoder *SoundHandler::GetSoundDecoder(const uint8_t *sound, int32_t length) {
const uint8_t *check = sound;
int32_t counter = 0;
while (check[0] == 0 && counter < length) {
check++;
counter++;
}
if (counter >= length) {
return NULL;
}
uint32_t *magic = (uint32_t *) check;
if (magic[0] == 0x4f676753) { // 'OggS'
return new OggDecoder(sound, length);
} else if (magic[0] == 0x52494646) { // 'RIFF'
return new WavDecoder(sound, length);
} else if (CheckMP3Signature(check) == true) {
return new Mp3Decoder(sound, length);
}
return new SoundDecoder(sound, length);
}
void SoundHandler::executeThread() {
/*// v2 sound lib can not properly end transition audio on old firmwares
if (OS_FIRMWARE >= 400 && OS_FIRMWARE <= 410)
{
ProperlyEndTransitionAudio();
}*/
//! initialize 48 kHz renderer
AXInitParams params;
memset(&params, 0, sizeof(params));
params.renderer = AX_INIT_RENDERER_48KHZ;
// TODO: handle support for 3.1.0 with dynamic libs instead of static linking it
//if(AXInitWithParams != 0)
AXInitWithParams(&params);
//else
// AXInit();
// The problem with last voice on 500 was caused by it having priority 0
// We would need to change this priority distribution if for some reason
// we would need MAX_DECODERS > Voice::PRIO_MAX
for (uint32_t i = 0; i < MAX_DECODERS; ++i) {
int32_t priority = (MAX_DECODERS - i) * Voice::PRIO_MAX / MAX_DECODERS;
voiceList[i] = new Voice(priority); // allocate voice 0 with highest priority
}
AXRegisterAppFrameCallback(SoundHandler::axFrameCallback);
uint16_t i = 0;
while (!ExitRequested) {
suspendThread();
for (i = 0; i < MAX_DECODERS; ++i) {
if (DecoderList[i] == NULL) {
continue;
}
Decoding = true;
if (DecoderList[i]) {
DecoderList[i]->Lock();
}
if (DecoderList[i]) {
DecoderList[i]->Decode();
}
if (DecoderList[i]) {
DecoderList[i]->Unlock();
}
}
Decoding = false;
}
for (uint32_t i = 0; i < MAX_DECODERS; ++i) {
voiceList[i]->stop();
}
AXRegisterAppFrameCallback(NULL);
AXQuit();
for (uint32_t i = 0; i < MAX_DECODERS; ++i) {
delete voiceList[i];
voiceList[i] = NULL;
}
}
void SoundHandler::axFrameCallback(void) {
for (uint32_t i = 0; i < MAX_DECODERS; i++) {
Voice *voice = handlerInstance->getVoice(i);
switch (voice->getState()) {
default:
case Voice::STATE_STOPPED:
break;
case Voice::STATE_START: {
SoundDecoder *decoder = handlerInstance->getDecoder(i);
decoder->Lock();
if (decoder->IsBufferReady()) {
const uint8_t *buffer = decoder->GetBuffer();
const uint32_t bufferSize = decoder->GetBufferSize();
decoder->LoadNext();
const uint8_t *nextBuffer = NULL;
uint32_t nextBufferSize = 0;
if (decoder->IsBufferReady()) {
nextBuffer = decoder->GetBuffer();
nextBufferSize = decoder->GetBufferSize();
decoder->LoadNext();
}
voice->play(buffer, bufferSize, nextBuffer, nextBufferSize, decoder->GetFormat() & 0xff, decoder->GetSampleRate());
handlerInstance->ThreadSignal();
voice->setState(Voice::STATE_PLAYING);
}
decoder->Unlock();
break;
}
case Voice::STATE_PLAYING:
if (voice->getInternState() == 1) {
if (voice->isBufferSwitched()) {
SoundDecoder *decoder = handlerInstance->getDecoder(i);
decoder->Lock();
if (decoder->IsBufferReady()) {
voice->setNextBuffer(decoder->GetBuffer(), decoder->GetBufferSize());
decoder->LoadNext();
handlerInstance->ThreadSignal();
} else if (decoder->IsEOF()) {
voice->setState(Voice::STATE_STOP);
}
decoder->Unlock();
}
} else {
voice->setState(Voice::STATE_STOPPED);
}
break;
case Voice::STATE_STOP:
if (voice->getInternState() != 0) {
voice->stop();
}
voice->setState(Voice::STATE_STOPPED);
break;
}
}
}

View File

@ -0,0 +1,98 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#ifndef SOUNDHANDLER_H_
#define SOUNDHANDLER_H_
#include <vector>
#include <sounds/SoundDecoder.hpp>
#include <sounds/Voice.h>
#include <system/CThread.h>
#include <sndcore2/voice.h>
#define MAX_DECODERS 16 // can be increased up to 96
class SoundHandler : public CThread {
public:
static SoundHandler *instance() {
if (!handlerInstance) {
handlerInstance = new SoundHandler();
}
return handlerInstance;
}
static void DestroyInstance() {
delete handlerInstance;
handlerInstance = NULL;
}
void AddDecoder(int32_t voice, const char *filepath);
void AddDecoder(int32_t voice, const uint8_t *snd, int32_t len);
void RemoveDecoder(int32_t voice);
SoundDecoder *getDecoder(int32_t i) {
return ((i < 0 || i >= MAX_DECODERS) ? NULL : DecoderList[i]);
};
Voice *getVoice(int32_t i) {
return ((i < 0 || i >= MAX_DECODERS) ? NULL : voiceList[i]);
};
void ThreadSignal() {
resumeThread();
};
bool IsDecoding() {
return Decoding;
};
protected:
SoundHandler();
~SoundHandler();
static void axFrameCallback(void);
void executeThread(void);
void ClearDecoderList();
SoundDecoder *GetSoundDecoder(const char *filepath);
SoundDecoder *GetSoundDecoder(const uint8_t *sound, int32_t length);
static SoundHandler *handlerInstance;
bool Decoding;
bool ExitRequested;
Voice *voiceList[MAX_DECODERS];
SoundDecoder *DecoderList[MAX_DECODERS];
};
#endif

158
src/sounds/Voice.h Normal file
View File

@ -0,0 +1,158 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef _AXSOUND_H_
#define _AXSOUND_H_
#include <sndcore2/core.h>
#include <sndcore2/voice.h>
class Voice {
public:
enum VoicePriorities {
PRIO_MIN = 1,
PRIO_MAX = 31
};
enum VoiceStates {
STATE_STOPPED,
STATE_START,
STATE_PLAYING,
STATE_STOP,
};
Voice(int32_t prio)
: state(STATE_STOPPED) {
lastLoopCounter = 0;
nextBufferSize = 0;
voice = AXAcquireVoice(prio, 0, 0);
if (voice) {
AXVoiceBegin(voice);
AXSetVoiceType(voice, 0);
setVolume(0x80000000);
AXVoiceDeviceMixData mix[6];
memset(mix, 0, sizeof(mix));
mix[0].bus[0].volume = 0x8000;
mix[0].bus[0].delta = 0;
mix[1].bus[0].volume = 0x8000;
mix[1].bus[0].delta = 0;
AXSetVoiceDeviceMix(voice, 0, 0, mix);
AXSetVoiceDeviceMix(voice, 1, 0, mix);
AXVoiceEnd(voice);
}
}
~Voice() {
if (voice) {
AXFreeVoice(voice);
}
}
void play(const uint8_t *buffer, uint32_t bufferSize, const uint8_t *nextBuffer, uint32_t nextBufSize, uint16_t format, uint32_t sampleRate) {
if (!voice) {
return;
}
memset(&voiceBuffer, 0, sizeof(voiceBuffer));
voiceBuffer.data = buffer;
voiceBuffer.dataType = format;
voiceBuffer.loopingEnabled = (nextBuffer == NULL) ? 0 : 1;
voiceBuffer.currentOffset = 0;
voiceBuffer.endOffset = (bufferSize >> 1) - 1;
voiceBuffer.loopOffset = ((nextBuffer - buffer) >> 1);
nextBufferSize = nextBufSize;
// TODO: handle support for 3.1.0 with dynamic libs instead of static linking it
//uint32_t samplesPerSec = (AXGetInputSamplesPerSec != 0) ? AXGetInputSamplesPerSec() : 32000;
uint32_t samplesPerSec = AXGetInputSamplesPerSec();
memset(&ratioBits, 0, sizeof(ratioBits));
ratioBits.ratio = (uint32_t) (0x00010000 * ((float) sampleRate / (float) samplesPerSec));
AXSetVoiceOffsets(voice, &voiceBuffer);
AXSetVoiceSrc(voice, &ratioBits);
AXSetVoiceSrcType(voice, 1);
AXSetVoiceState(voice, 1);
}
void stop() {
if (voice) {
AXSetVoiceState(voice, 0);
}
}
void setVolume(uint32_t vol) {
if (voice) {
AXVoiceVeData data;
data.volume = vol >> 16;
data.delta = vol & 0xFFFF;
AXSetVoiceVe(voice, &data);
}
}
void setNextBuffer(const uint8_t *buffer, uint32_t bufferSize) {
voiceBuffer.loopOffset = ((buffer - (const uint8_t *) voiceBuffer.data) >> 1);
nextBufferSize = bufferSize;
AXSetVoiceLoopOffset(voice, voiceBuffer.loopOffset);
}
bool isBufferSwitched() {
uint32_t loopCounter = AXGetVoiceLoopCount(voice);
if (lastLoopCounter != loopCounter) {
lastLoopCounter = loopCounter;
AXSetVoiceEndOffset(voice, voiceBuffer.loopOffset + (nextBufferSize >> 1) - 1);
return true;
}
return false;
}
uint32_t getInternState() const {
if (voice) {
return ((uint32_t *) voice)[1];
}
return 0;
}
uint32_t getState() const {
return state;
}
void setState(uint32_t s) {
state = s;
}
void *getVoice() const {
return voice;
}
private:
AXVoice *voice;
AXVoiceSrc ratioBits;
AXVoiceOffsets voiceBuffer;
uint32_t state;
uint32_t nextBufferSize;
uint32_t lastLoopCounter;
};
#endif // _AXSOUND_H_

148
src/sounds/WavDecoder.cpp Normal file
View File

@ -0,0 +1,148 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#include "fs/CFile.hpp"
#include "utils/utils.h"
#include <sounds/WavDecoder.hpp>
#include <string.h>
WavDecoder::WavDecoder(const char *filepath)
: SoundDecoder(filepath) {
SoundType = SOUND_WAV;
SampleRate = 48000;
Format = CHANNELS_STEREO | FORMAT_PCM_16_BIT;
if (!file_fd) {
return;
}
OpenFile();
}
WavDecoder::WavDecoder(const uint8_t *snd, int32_t len)
: SoundDecoder(snd, len) {
SoundType = SOUND_WAV;
SampleRate = 48000;
Format = CHANNELS_STEREO | FORMAT_PCM_16_BIT;
if (!file_fd) {
return;
}
OpenFile();
}
WavDecoder::~WavDecoder() {
}
void WavDecoder::OpenFile() {
SWaveHdr Header;
SWaveFmtChunk FmtChunk;
memset(&Header, 0, sizeof(SWaveHdr));
memset(&FmtChunk, 0, sizeof(SWaveFmtChunk));
file_fd->read((uint8_t *) &Header, sizeof(SWaveHdr));
file_fd->read((uint8_t *) &FmtChunk, sizeof(SWaveFmtChunk));
if (Header.magicRIFF != 0x52494646) { // 'RIFF'
CloseFile();
return;
} else if (Header.magicWAVE != 0x57415645) { // 'WAVE'
CloseFile();
return;
} else if (FmtChunk.magicFMT != 0x666d7420) { // 'fmt '
CloseFile();
return;
}
DataOffset = sizeof(SWaveHdr) + le32(FmtChunk.size) + 8;
file_fd->seek(DataOffset, SEEK_SET);
SWaveChunk DataChunk;
file_fd->read((uint8_t *) &DataChunk, sizeof(SWaveChunk));
while (DataChunk.magicDATA != 0x64617461) { // 'data'
DataOffset += 8 + le32(DataChunk.size);
file_fd->seek(DataOffset, SEEK_SET);
int32_t ret = file_fd->read((uint8_t *) &DataChunk, sizeof(SWaveChunk));
if (ret <= 0) {
CloseFile();
return;
}
}
DataOffset += 8;
DataSize = le32(DataChunk.size);
Is16Bit = (le16(FmtChunk.bps) == 16);
SampleRate = le32(FmtChunk.freq);
if (le16(FmtChunk.channels) == 1 && le16(FmtChunk.bps) == 8 && le16(FmtChunk.alignment) <= 1) {
Format = CHANNELS_MONO | FORMAT_PCM_8_BIT;
} else if (le16(FmtChunk.channels) == 1 && le16(FmtChunk.bps) == 16 && le16(FmtChunk.alignment) <= 2) {
Format = CHANNELS_MONO | FORMAT_PCM_16_BIT;
} else if (le16(FmtChunk.channels) == 2 && le16(FmtChunk.bps) == 8 && le16(FmtChunk.alignment) <= 2) {
Format = CHANNELS_STEREO | FORMAT_PCM_8_BIT;
} else if (le16(FmtChunk.channels) == 2 && le16(FmtChunk.bps) == 16 && le16(FmtChunk.alignment) <= 4) {
Format = CHANNELS_STEREO | FORMAT_PCM_16_BIT;
}
}
void WavDecoder::CloseFile() {
if (file_fd) {
delete file_fd;
}
file_fd = NULL;
}
int32_t WavDecoder::Read(uint8_t *buffer, int32_t buffer_size, int32_t pos) {
if (!file_fd) {
return -1;
}
if (CurPos >= (int32_t) DataSize) {
return 0;
}
file_fd->seek(DataOffset + CurPos, SEEK_SET);
if (buffer_size > (int32_t) DataSize - CurPos) {
buffer_size = DataSize - CurPos;
}
int32_t read = file_fd->read(buffer, buffer_size);
if (read > 0) {
if (Is16Bit) {
read &= ~0x0001;
for (uint32_t i = 0; i < (uint32_t) (read / sizeof(uint16_t)); ++i) {
((uint16_t *) buffer)[i] = le16(((uint16_t *) buffer)[i]);
}
}
CurPos += read;
}
return read;
}

73
src/sounds/WavDecoder.hpp Normal file
View File

@ -0,0 +1,73 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#ifndef WAVDECODER_HPP_
#define WAVDECODER_HPP_
#include <sounds/SoundDecoder.hpp>
typedef struct {
uint32_t magicRIFF;
uint32_t size;
uint32_t magicWAVE;
} SWaveHdr;
typedef struct {
uint32_t magicFMT;
uint32_t size;
uint16_t format;
uint16_t channels;
uint32_t freq;
uint32_t avgBps;
uint16_t alignment;
uint16_t bps;
} SWaveFmtChunk;
typedef struct {
uint32_t magicDATA;
uint32_t size;
} SWaveChunk;
class WavDecoder : public SoundDecoder {
public:
WavDecoder(const char *filepath);
WavDecoder(const uint8_t *snd, int32_t len);
virtual ~WavDecoder();
int32_t Read(uint8_t *buffer, int32_t buffer_size, int32_t pos);
protected:
void OpenFile();
void CloseFile();
uint32_t DataOffset;
uint32_t DataSize;
bool Is16Bit;
};
#endif

View File

@ -17,20 +17,17 @@
#ifndef CTHREAD_H_
#define CTHREAD_H_
#include <coreinit/thread.h>
#include <malloc.h>
#include <unistd.h>
#include <coreinit/thread.h>
class CThread {
public:
typedef void (*Callback)(CThread *thread, void *arg);
//! constructor
CThread(int32_t iAttr, int32_t iPriority = 16, int32_t iStackSize = 0x8000, CThread::Callback callback = nullptr, void *callbackArg = nullptr)
: pThread(nullptr)
, pThreadStack(nullptr)
, pCallback(callback)
, pCallbackArg(callbackArg) {
CThread(int32_t iAttr, int32_t iPriority = 16, int32_t iStackSize = 0x8000, CThread::Callback callback = NULL, void *callbackArg = NULL)
: pThread(NULL), pThreadStack(NULL), pCallback(callback), pCallbackArg(callbackArg) {
//! save attribute assignment
iAttributes = iAttr;
//! allocate the thread
@ -38,9 +35,10 @@ public:
//! allocate the stack
pThreadStack = (uint8_t *) memalign(0x20, iStackSize);
//! create the thread
if(pThread && pThreadStack)
if (pThread && pThreadStack) {
OSCreateThread(pThread, &CThread::threadCallback, 1, (char *) this, pThreadStack + iStackSize, iStackSize, iPriority, iAttributes);
}
}
//! destructor
virtual ~CThread() {
@ -55,64 +53,84 @@ public:
virtual void *getThread() const {
return pThread;
}
//! Thread entry function
virtual void executeThread(void) {
if(pCallback)
if (pCallback) {
pCallback(this, pCallbackArg);
}
}
//! Suspend thread
virtual void suspendThread(void) {
if(isThreadSuspended())
if (isThreadSuspended()) {
return;
if(pThread)
}
if (pThread) {
OSSuspendThread(pThread);
}
}
//! Resume thread
virtual void resumeThread(void) {
if(!isThreadSuspended())
if (!isThreadSuspended()) {
return;
if(pThread)
}
if (pThread) {
OSResumeThread(pThread);
}
}
//! Set thread priority
virtual void setThreadPriority(int32_t prio) {
if(pThread)
if (pThread) {
OSSetThreadPriority(pThread, prio);
}
}
//! Check if thread is suspended
virtual bool isThreadSuspended(void) const {
if(pThread)
if (pThread) {
return OSIsThreadSuspended(pThread);
}
return false;
}
//! Check if thread is terminated
virtual bool isThreadTerminated(void) const {
if(pThread)
if (pThread) {
return OSIsThreadTerminated(pThread);
}
return false;
}
//! Check if thread is running
virtual bool isThreadRunning(void) const {
return !isThreadSuspended() && !isThreadRunning();
}
//! Shutdown thread
virtual void shutdownThread(void) {
//! wait for thread to finish
if (pThread && !(iAttributes & eAttributeDetach)) {
if(isThreadSuspended())
if (isThreadSuspended()) {
resumeThread();
}
OSJoinThread(pThread, nullptr);
OSJoinThread(pThread, NULL);
}
//! free the thread stack buffer
if(pThreadStack)
if (pThreadStack) {
free(pThreadStack);
if(pThread)
free(pThread);
pThread = nullptr;
pThreadStack = nullptr;
}
if (pThread) {
free(pThread);
}
pThread = NULL;
pThreadStack = NULL;
}
//! Thread attributes
enum eCThreadAttributes {
eAttributeNone = 0x07,
@ -122,12 +140,14 @@ public:
eAttributeDetach = 0x08,
eAttributePinnedAff = 0x10
};
private:
static int32_t threadCallback(int32_t argc, const char **argv) {
//! After call to start() continue with the internal function
((CThread *) argv)->executeThread();
return 0;
}
int32_t iAttributes;
OSThread *pThread;
uint8_t *pThreadStack;

91
src/system/memory.cpp Normal file
View File

@ -0,0 +1,91 @@
/****************************************************************************
* 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 "memory.h"
#include <coreinit/memexpheap.h>
#include <coreinit/memfrmheap.h>
#include <coreinit/memheap.h>
#include <malloc.h>
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//! Memory functions
//! This is the only place where those are needed so lets keep them more or less private
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
static MEMHeapHandle mem1_heap = NULL;
static MEMHeapHandle bucket_heap = NULL;
void libgui_memoryInitialize(void) {
if (!mem1_heap) {
MEMHeapHandle mem1_heap_handle = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1);
uint32_t mem1_allocatable_size = MEMGetAllocatableSizeForFrmHeapEx(mem1_heap_handle, 4);
void *mem1_memory = MEMAllocFromFrmHeapEx(mem1_heap_handle, mem1_allocatable_size, 4);
if (mem1_memory)
mem1_heap = MEMCreateExpHeapEx(mem1_memory, mem1_allocatable_size, 0);
}
if (!bucket_heap) {
MEMHeapHandle bucket_heap_handle = MEMGetBaseHeapHandle(MEM_BASE_HEAP_FG);
uint32_t bucket_allocatable_size = MEMGetAllocatableSizeForFrmHeapEx(bucket_heap_handle, 4);
void *bucket_memory = MEMAllocFromFrmHeapEx(bucket_heap_handle, bucket_allocatable_size, 4);
if (bucket_memory)
bucket_heap = MEMCreateExpHeapEx(bucket_memory, bucket_allocatable_size, 0);
}
}
void libgui_memoryRelease(void) {
if (mem1_heap) {
MEMDestroyExpHeap(mem1_heap);
MEMFreeToFrmHeap(MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1), MEM_FRM_HEAP_FREE_ALL);
mem1_heap = NULL;
}
if (bucket_heap) {
MEMDestroyExpHeap(bucket_heap);
MEMFreeToFrmHeap(MEMGetBaseHeapHandle(MEM_BASE_HEAP_FG), MEM_FRM_HEAP_FREE_ALL);
bucket_heap = NULL;
}
}
//!-------------------------------------------------------------------------------------------
//! some wrappers
//!-------------------------------------------------------------------------------------------
void *MEM2_alloc(uint32_t size, uint32_t align) {
return memalign(align, size);
}
void MEM2_free(void *ptr) {
free(ptr);
}
void *MEM1_alloc(uint32_t size, uint32_t align) {
if (align < 4)
align = 4;
return MEMAllocFromExpHeapEx(mem1_heap, size, align);
}
void MEM1_free(void *ptr) {
MEMFreeToExpHeap(mem1_heap, ptr);
}
void *MEMBucket_alloc(uint32_t size, uint32_t align) {
if (align < 4)
align = 4;
return MEMAllocFromExpHeapEx(bucket_heap, size, align);
}
void MEMBucket_free(void *ptr) {
MEMFreeToExpHeap(bucket_heap, ptr);
}

47
src/system/memory.h Normal file
View File

@ -0,0 +1,47 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef __MEMORY_H_
#define __MEMORY_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <cstdint>
#include <malloc.h>
void libgui_memoryInitialize(void);
void libgui_memoryRelease(void);
void *MEM2_alloc(uint32_t size, uint32_t align);
void MEM2_free(void *ptr);
void *MEM1_alloc(uint32_t size, uint32_t align);
void MEM1_free(void *ptr);
void *MEMBucket_alloc(uint32_t size, uint32_t align);
void MEMBucket_free(void *ptr);
#ifdef __cplusplus
}
#endif
#endif // __MEMORY_H_

View File

@ -1,41 +0,0 @@
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <malloc.h>
#include <utils/logger.h>
// https://gist.github.com/ccbrown/9722406
void dumpHex(const void *data, size_t size) {
char ascii[17];
size_t i, j;
ascii[16] = '\0';
DEBUG_FUNCTION_LINE_WRITE("0x%08X (0x0000): ", data);
for (i = 0; i < size; ++i) {
WHBLogWritef("%02X ", ((unsigned char *) data)[i]);
if (((unsigned char *) data)[i] >= ' ' && ((unsigned char *) data)[i] <= '~') {
ascii[i % 16] = ((unsigned char *) data)[i];
} else {
ascii[i % 16] = '.';
}
if ((i + 1) % 8 == 0 || i + 1 == size) {
WHBLogWritef(" ");
if ((i + 1) % 16 == 0) {
WHBLogWritef("| %s \n", ascii);
if (i + 1 < size) {
WHBLogWritef("0x%08X (0x%04X); ", data + i + 1, i + 1);
}
} else if (i + 1 == size) {
ascii[(i + 1) % 16] = '\0';
if ((i + 1) % 16 <= 8) {
WHBLogWritef(" ");
}
for (j = (i + 1) % 16; j < 16; ++j) {
WHBLogWritef(" ");
}
WHBLogWritef("| %s \n", ascii);
}
}
}
}

41
src/utils/utils.cpp Normal file
View File

@ -0,0 +1,41 @@
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <malloc.h>
#include <utils/logger.h>
// https://gist.github.com/ccbrown/9722406
void dumpHex(const void *data, size_t size) {
char ascii[17];
size_t i, j;
ascii[16] = '\0';
DEBUG_FUNCTION_LINE_WRITE("0x%08X (0x0000): ", data);
for (i = 0; i < size; ++i) {
WHBLogWritef("%02X ", ((unsigned char *) data)[i]);
if (((unsigned char *) data)[i] >= ' ' && ((unsigned char *) data)[i] <= '~') {
ascii[i % 16] = ((unsigned char *) data)[i];
} else {
ascii[i % 16] = '.';
}
if ((i + 1) % 8 == 0 || i + 1 == size) {
WHBLogWritef(" ");
if ((i + 1) % 16 == 0) {
WHBLogWritef("| %s \n", ascii);
if (i + 1 < size) {
WHBLogWritef("0x%08X (0x%04X); ", ((char *) data)[i + 1], i + 1);
}
} else if (i + 1 == size) {
ascii[(i + 1) % 16] = '\0';
if ((i + 1) % 16 <= 8) {
WHBLogWritef(" ");
}
for (j = (i + 1) % 16; j < 16; ++j) {
WHBLogWritef(" ");
}
WHBLogWritef("| %s \n", ascii);
}
}
}
}

264
src/video/CVideo.cpp Normal file
View File

@ -0,0 +1,264 @@
/****************************************************************************
* 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 "utils/utils.h"
#include <cstdint>
#include "system/memory.h"
#include <video/CVideo.h>
#include <video/shaders/ColorShader.h>
#include <video/shaders/FXAAShader.h>
#include <video/shaders/Shader3D.h>
#include <video/shaders/ShaderFractalColor.h>
#include <video/shaders/Texture2DShader.h>
#include <malloc.h>
#include <string.h>
CVideo::CVideo(int32_t forceTvScanMode, int32_t forceDrcScanMode) {
tvEnabled = false;
drcEnabled = false;
//! allocate MEM2 command buffer memory
gx2CommandBuffer = MEM2_alloc(GX2_COMMAND_BUFFER_SIZE, 0x40);
//! initialize GX2 command buffer
uint32_t gx2_init_attributes[9];
gx2_init_attributes[0] = GX2_INIT_CMD_BUF_BASE;
gx2_init_attributes[1] = (uint32_t) gx2CommandBuffer;
gx2_init_attributes[2] = GX2_INIT_CMD_BUF_POOL_SIZE;
gx2_init_attributes[3] = GX2_COMMAND_BUFFER_SIZE;
gx2_init_attributes[4] = GX2_INIT_ARGC;
gx2_init_attributes[5] = 0;
gx2_init_attributes[6] = GX2_INIT_ARGV;
gx2_init_attributes[7] = 0;
gx2_init_attributes[8] = GX2_INIT_END;
GX2Init(gx2_init_attributes);
uint32_t scanBufferSize = 0;
uint32_t scaleNeeded = 0;
int32_t tvScanMode = ((forceTvScanMode >= 0) ? forceTvScanMode : (int32_t) GX2GetSystemTVScanMode());
int32_t drcScanMode = ((forceDrcScanMode >= 0) ? forceDrcScanMode : (int32_t) GX2GetSystemDRCScanMode());
int32_t tvRenderMode;
uint32_t tvWidth = 0;
uint32_t tvHeight = 0;
switch (tvScanMode) {
case GX2_TV_SCAN_MODE_480I:
case GX2_TV_SCAN_MODE_480P:
tvWidth = 854;
tvHeight = 480;
tvRenderMode = GX2_TV_RENDER_MODE_WIDE_480P;
break;
case GX2_TV_SCAN_MODE_1080I:
case GX2_TV_SCAN_MODE_1080P:
tvWidth = 1920;
tvHeight = 1080;
tvRenderMode = GX2_TV_RENDER_MODE_WIDE_1080P;
break;
case GX2_TV_SCAN_MODE_720P:
default:
tvWidth = 1280;
tvHeight = 720;
tvRenderMode = GX2_TV_RENDER_MODE_WIDE_720P;
break;
}
int32_t tvAAMode = GX2_AA_MODE1X;
int32_t drcAAMode = GX2_AA_MODE4X;
//! calculate the scale factor for later texture resize
widthScaleFactor = 1.0f / (float) tvWidth;
heightScaleFactor = 1.0f / (float) tvHeight;
depthScaleFactor = widthScaleFactor;
//! calculate the size needed for the TV scan buffer and allocate the buffer from bucket memory
GX2CalcTVSize((GX2TVRenderMode) tvRenderMode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE, &scanBufferSize, &scaleNeeded);
tvScanBuffer = MEMBucket_alloc(scanBufferSize, GX2_SCAN_BUFFER_ALIGNMENT);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU, tvScanBuffer, scanBufferSize);
GX2SetTVBuffer(tvScanBuffer, scanBufferSize, (GX2TVRenderMode) tvRenderMode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE);
//! calculate the size needed for the DRC scan buffer and allocate the buffer from bucket memory
GX2CalcDRCSize((GX2DrcRenderMode) drcScanMode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE, &scanBufferSize, &scaleNeeded);
drcScanBuffer = MEMBucket_alloc(scanBufferSize, GX2_SCAN_BUFFER_ALIGNMENT);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU, drcScanBuffer, scanBufferSize);
GX2SetDRCBuffer(drcScanBuffer, scanBufferSize, (GX2DrcRenderMode) drcScanMode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE);
//! Setup color buffer for TV rendering
GX2InitColorBuffer(&tvColorBuffer, GX2_SURFACE_DIM_TEXTURE_2D, tvWidth, tvHeight, 1, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, (GX2AAMode) tvAAMode);
tvColorBuffer.surface.image = MEM1_alloc(tvColorBuffer.surface.imageSize, tvColorBuffer.surface.alignment);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU, tvColorBuffer.surface.image, tvColorBuffer.surface.imageSize);
//! due to AA we can only use 16 bit depth buffer in MEM1 otherwise we would have to switch to mem2 for depth buffer
//! this should be ok for our purpose i guess
//! Setup TV depth buffer (can be the same for both if rendered one after another)
uint32_t size, align;
GX2InitDepthBuffer(&tvDepthBuffer, GX2_SURFACE_DIM_TEXTURE_2D, tvColorBuffer.surface.width, tvColorBuffer.surface.height, 1, GX2_SURFACE_FORMAT_FLOAT_R32, (GX2AAMode) tvAAMode);
tvDepthBuffer.surface.image = MEM1_alloc(tvDepthBuffer.surface.imageSize, tvDepthBuffer.surface.alignment);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU, tvDepthBuffer.surface.image, tvDepthBuffer.surface.imageSize);
//! Setup TV HiZ buffer
GX2CalcDepthBufferHiZInfo(&tvDepthBuffer, &size, &align);
tvDepthBuffer.hiZPtr = MEM1_alloc(size, align);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU, tvDepthBuffer.hiZPtr, size);
GX2InitDepthBufferHiZEnable(&tvDepthBuffer, GX2_ENABLE);
//! Setup color buffer for DRC rendering
GX2InitColorBuffer(&drcColorBuffer, GX2_SURFACE_DIM_TEXTURE_2D, 854, 480, 1, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, (GX2AAMode) drcAAMode);
drcColorBuffer.surface.image = MEM1_alloc(drcColorBuffer.surface.imageSize, drcColorBuffer.surface.alignment);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU, drcColorBuffer.surface.image, drcColorBuffer.surface.imageSize);
//! Setup DRC depth buffer (can be the same for both if rendered one after another)
GX2InitDepthBuffer(&drcDepthBuffer, GX2_SURFACE_DIM_TEXTURE_2D, drcColorBuffer.surface.width, drcColorBuffer.surface.height, 1, GX2_SURFACE_FORMAT_FLOAT_R32, (GX2AAMode) drcAAMode);
drcDepthBuffer.surface.image = MEM1_alloc(drcDepthBuffer.surface.imageSize, drcDepthBuffer.surface.alignment);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU, drcDepthBuffer.surface.image, drcDepthBuffer.surface.imageSize);
//! Setup DRC HiZ buffer
GX2CalcDepthBufferHiZInfo(&drcDepthBuffer, &size, &align);
drcDepthBuffer.hiZPtr = MEM1_alloc(size, align);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU, drcDepthBuffer.hiZPtr, size);
GX2InitDepthBufferHiZEnable(&drcDepthBuffer, GX2_ENABLE);
//! allocate auxilary buffer last as there might not be enough MEM1 left for other stuff after that
if (tvColorBuffer.surface.aa) {
uint32_t auxSize, auxAlign;
GX2CalcColorBufferAuxInfo(&tvColorBuffer, &auxSize, &auxAlign);
tvColorBuffer.aaBuffer = MEM1_alloc(auxSize, auxAlign);
if (!tvColorBuffer.aaBuffer) {
tvColorBuffer.aaBuffer = MEM2_alloc(auxSize, auxAlign);
}
tvColorBuffer.aaSize = auxSize;
memset(tvColorBuffer.aaBuffer, GX2_AA_BUFFER_CLEAR_VALUE, auxSize);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU, tvColorBuffer.aaBuffer, auxSize);
}
if (drcColorBuffer.surface.aa) {
uint32_t auxSize, auxAlign;
GX2CalcColorBufferAuxInfo(&drcColorBuffer, &auxSize, &auxAlign);
drcColorBuffer.aaBuffer = MEM1_alloc(auxSize, auxAlign);
if (!drcColorBuffer.aaBuffer) {
drcColorBuffer.aaBuffer = MEM2_alloc(auxSize, auxAlign);
}
drcColorBuffer.aaSize = auxSize;
memset(drcColorBuffer.aaBuffer, GX2_AA_BUFFER_CLEAR_VALUE, auxSize);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU, drcColorBuffer.aaBuffer, auxSize);
}
//! allocate memory and setup context state TV
tvContextState = (GX2ContextState *) MEM2_alloc(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT);
GX2SetupContextStateEx(tvContextState, GX2_TRUE);
//! allocate memory and setup context state DRC
drcContextState = (GX2ContextState *) MEM2_alloc(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT);
GX2SetupContextStateEx(drcContextState, GX2_TRUE);
//! set initial context state and render buffers
GX2SetContextState(tvContextState);
GX2SetColorBuffer(&tvColorBuffer, GX2_RENDER_TARGET_0);
GX2SetDepthBuffer(&tvDepthBuffer);
GX2SetContextState(drcContextState);
GX2SetColorBuffer(&drcColorBuffer, GX2_RENDER_TARGET_0);
GX2SetDepthBuffer(&drcDepthBuffer);
//! set initial viewport
GX2SetViewport(0.0f, 0.0f, tvColorBuffer.surface.width, tvColorBuffer.surface.height, 0.0f, 1.0f);
GX2SetScissor(0, 0, tvColorBuffer.surface.width, tvColorBuffer.surface.height);
//! this is not necessary but can be used for swap counting and vsyncs
GX2SetSwapInterval(1);
//GX2SetTVGamma(0.8f);
//GX2SetDRCGamma(0.8f);
//! initialize perspective matrix
const float cam_X_rot = 25.0f;
projectionMtx = glm::perspective(45.0f, 1.0f, 0.1f, 100.0f);
viewMtx = glm::mat4(1.0f);
viewMtx = glm::translate(viewMtx, glm::vec3(0.0f, 0.0f, -2.5f));
viewMtx = glm::rotate(viewMtx, DegToRad(cam_X_rot), glm::vec3(1.0f, 0.0f, 0.0f));
GX2InitSampler(&aaSampler, GX2_TEX_CLAMP_MODE_CLAMP, GX2_TEX_XY_FILTER_MODE_LINEAR);
GX2InitTexture(&tvAaTexture, tvColorBuffer.surface.width, tvColorBuffer.surface.height, 1, 0, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_SURFACE_DIM_TEXTURE_2D, GX2_TILE_MODE_DEFAULT);
tvAaTexture.surface.image = tvColorBuffer.surface.image;
tvAaTexture.surface.imageSize = tvColorBuffer.surface.imageSize;
tvAaTexture.surface.mipmaps = tvColorBuffer.surface.mipmaps;
}
CVideo::~CVideo() {
//! flush buffers
GX2Flush();
GX2DrawDone();
//! shutdown
GX2Shutdown();
//! free command buffer memory
MEM2_free(gx2CommandBuffer);
//! free scan buffers
MEMBucket_free(tvScanBuffer);
MEMBucket_free(drcScanBuffer);
//! free color buffers
MEM1_free(tvColorBuffer.surface.image);
MEM1_free(drcColorBuffer.surface.image);
//! free depth buffers
MEM1_free(tvDepthBuffer.surface.image);
MEM1_free(tvDepthBuffer.hiZPtr);
MEM1_free(drcDepthBuffer.surface.image);
MEM1_free(drcDepthBuffer.hiZPtr);
//! free context buffers
MEM2_free(tvContextState);
MEM2_free(drcContextState);
//! free aux buffer
if (tvColorBuffer.aaBuffer) {
if (((uint32_t) tvColorBuffer.aaBuffer & 0xF0000000) == 0xF0000000) {
MEM1_free(tvColorBuffer.aaBuffer);
} else {
MEM2_free(tvColorBuffer.aaBuffer);
}
}
if (drcColorBuffer.aaBuffer) {
if (((uint32_t) drcColorBuffer.aaBuffer & 0xF0000000) == 0xF0000000) {
MEM1_free(drcColorBuffer.aaBuffer);
} else {
MEM2_free(drcColorBuffer.aaBuffer);
}
}
//! destroy shaders
ColorShader::destroyInstance();
FXAAShader::destroyInstance();
Shader3D::destroyInstance();
ShaderFractalColor::destroyInstance();
Texture2DShader::destroyInstance();
}
void CVideo::renderFXAA(const GX2Texture *texture, const GX2Sampler *sampler) {
resolution[0] = texture->surface.width;
resolution[1] = texture->surface.height;
GX2Invalidate((GX2InvalidateMode) (GX2_INVALIDATE_MODE_COLOR_BUFFER | GX2_INVALIDATE_MODE_TEXTURE), texture->surface.image, texture->surface.imageSize);
GX2SetDepthOnlyControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_FUNC_ALWAYS);
FXAAShader::instance()->setShaders();
FXAAShader::instance()->setAttributeBuffer();
FXAAShader::instance()->setResolution(resolution);
FXAAShader::instance()->setTextureAndSampler(texture, sampler);
FXAAShader::instance()->draw();
GX2SetDepthOnlyControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_FUNC_LEQUAL);
}

213
src/video/CVideo.h Normal file
View File

@ -0,0 +1,213 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef __CVIDEO_H_
#define __CVIDEO_H_
#include <gui/gx2_ext.h>
#include <gx2/clear.h>
#include <gx2/context.h>
#include <gx2/display.h>
#include <gx2/draw.h>
#include <gx2/event.h>
#include <gx2/registers.h>
#include <gx2/sampler.h>
#include <gx2/state.h>
#include <gx2/swap.h>
#include <video/shaders/Shader.h>
class CVideo {
public:
CVideo(int32_t forceTvScanMode = -1, int32_t forceDrcScanMode = -1);
virtual ~CVideo();
void prepareTvRendering(void) {
currContextState = tvContextState;
currColorBuffer = &tvColorBuffer;
currDepthBuffer = &tvDepthBuffer;
prepareRendering();
}
void prepareDrcRendering(void) {
currContextState = drcContextState;
currColorBuffer = &drcColorBuffer;
currDepthBuffer = &drcDepthBuffer;
prepareRendering();
}
void prepareRendering(void) {
GX2ClearColor(currColorBuffer, 0.0f, 0.0f, 0.0f, 1.0f);
GX2ClearDepthStencilEx(currDepthBuffer, currDepthBuffer->depthClear, currDepthBuffer->stencilClear, GX2_CLEAR_FLAGS_BOTH);
GX2SetContextState(currContextState);
GX2SetViewport(0.0f, 0.0f, currColorBuffer->surface.width, currColorBuffer->surface.height, 0.0f, 1.0f);
GX2SetScissor(0, 0, currColorBuffer->surface.width, currColorBuffer->surface.height);
GX2SetDepthOnlyControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_FUNC_LEQUAL);
GX2SetColorControl(GX2_LOGIC_OP_COPY, 1, GX2_DISABLE, GX2_ENABLE);
GX2SetBlendControl(GX2_RENDER_TARGET_0, GX2_BLEND_MODE_SRC_ALPHA, GX2_BLEND_MODE_INV_SRC_ALPHA, GX2_BLEND_COMBINE_MODE_ADD, GX2_ENABLE, GX2_BLEND_MODE_SRC_ALPHA, GX2_BLEND_MODE_INV_SRC_ALPHA, GX2_BLEND_COMBINE_MODE_ADD);
GX2SetCullOnlyControl(GX2_FRONT_FACE_CCW, GX2_DISABLE, GX2_ENABLE);
}
void setStencilRender(bool bEnable) {
if (bEnable) {
GX2SetStencilMask(0xff, 0xff, 0x01, 0xff, 0xff, 0x01);
GX2SetDepthStencilControl(GX2_DISABLE, GX2_DISABLE, GX2_COMPARE_FUNC_LEQUAL, GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_FUNC_ALWAYS, GX2_STENCIL_FUNCTION_KEEP, GX2_STENCIL_FUNCTION_KEEP, GX2_STENCIL_FUNCTION_REPLACE,
GX2_COMPARE_FUNC_ALWAYS, GX2_STENCIL_FUNCTION_KEEP, GX2_STENCIL_FUNCTION_KEEP, GX2_STENCIL_FUNCTION_REPLACE);
} else {
GX2SetStencilMask(0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
GX2SetDepthStencilControl(GX2_ENABLE, GX2_ENABLE, GX2_COMPARE_FUNC_LEQUAL, GX2_DISABLE, GX2_DISABLE, GX2_COMPARE_FUNC_NEVER, GX2_STENCIL_FUNCTION_KEEP, GX2_STENCIL_FUNCTION_KEEP, GX2_STENCIL_FUNCTION_KEEP,
GX2_COMPARE_FUNC_NEVER, GX2_STENCIL_FUNCTION_KEEP, GX2_STENCIL_FUNCTION_KEEP, GX2_STENCIL_FUNCTION_KEEP);
}
}
void drcDrawDone(void) {
//! on DRC we do a hardware AA because FXAA does not look good
//renderFXAA(&drcAaTexture, &aaSampler);
GX2CopyColorBufferToScanBuffer(&drcColorBuffer, GX2_SCAN_TARGET_DRC);
}
void tvDrawDone(void) {
renderFXAA(&tvAaTexture, &aaSampler);
GX2CopyColorBufferToScanBuffer(&tvColorBuffer, GX2_SCAN_TARGET_TV);
GX2SwapScanBuffers();
GX2Flush();
}
void waitForVSync(void) {
GX2WaitForVsync();
frameCount++;
}
void tvEnable(bool bEnable) {
if (tvEnabled != bEnable) {
GX2SetTVEnable(bEnable ? GX2_ENABLE : GX2_DISABLE);
tvEnabled = bEnable;
}
}
void drcEnable(bool bEnable) {
if (drcEnabled != bEnable) {
GX2SetDRCEnable(bEnable ? GX2_ENABLE : GX2_DISABLE);
drcEnabled = bEnable;
}
}
uint32_t getFrameCount(void) const {
return frameCount;
}
uint32_t getTvWidth(void) const {
return tvColorBuffer.surface.width;
}
uint32_t getTvHeight(void) const {
return tvColorBuffer.surface.height;
}
uint32_t getDrcWidth(void) const {
return drcColorBuffer.surface.width;
}
uint32_t getDrcHeight(void) const {
return drcColorBuffer.surface.height;
}
const glm::mat4 &getProjectionMtx(void) const {
return projectionMtx;
}
const glm::mat4 &getViewMtx(void) const {
return viewMtx;
}
float getWidthScaleFactor(void) const {
return widthScaleFactor;
}
float getHeightScaleFactor(void) const {
return heightScaleFactor;
}
float getDepthScaleFactor(void) const {
return depthScaleFactor;
}
void screenPosToWorldRay(float posX, float posY, glm::vec3 &rayOrigin, glm::vec3 &rayDirection) {
//! normalize positions
posX = 2.0f * posX * getWidthScaleFactor();
posY = 2.0f * posY * getHeightScaleFactor();
glm::vec4 rayStart(posX, posY, 0.0f, 1.0f);
glm::vec4 rayEnd(posX, posY, 1.0f, 1.0f);
glm::mat4 IMV = glm::inverse(projectionMtx * viewMtx);
glm::vec4 rayStartWorld = IMV * rayStart;
rayStartWorld /= rayStartWorld.w;
glm::vec4 rayEndWorld = IMV * rayEnd;
rayEndWorld /= rayEndWorld.w;
glm::vec3 rayDirectionWorld(rayEndWorld - rayStartWorld);
rayDirectionWorld = glm::normalize(rayDirectionWorld);
rayOrigin = glm::vec3(rayStartWorld);
rayDirection = glm::normalize(rayDirectionWorld);
}
private:
static void *GX2RAlloc(uint32_t flags, uint32_t size, uint32_t align);
static void GX2RFree(uint32_t flags, void *p);
void renderFXAA(const GX2Texture *texture, const GX2Sampler *sampler);
void *gx2CommandBuffer;
void *tvScanBuffer;
void *drcScanBuffer;
uint32_t frameCount;
float widthScaleFactor;
float heightScaleFactor;
float depthScaleFactor;
bool tvEnabled;
bool drcEnabled;
GX2ColorBuffer tvColorBuffer;
GX2DepthBuffer tvDepthBuffer;
GX2ColorBuffer drcColorBuffer;
GX2DepthBuffer drcDepthBuffer;
GX2ContextState *tvContextState;
GX2ContextState *drcContextState;
GX2ContextState *currContextState;
GX2ColorBuffer *currColorBuffer;
GX2DepthBuffer *currDepthBuffer;
GX2Texture tvAaTexture;
GX2Sampler aaSampler;
glm::mat4 projectionMtx;
glm::mat4 viewMtx;
glm::vec2 resolution;
};
#endif // __GX2_VIDEO_H_

View File

@ -0,0 +1,83 @@
/****************************************************************************
* Copyright (C) 2016,2017 Maschell
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <video/CursorDrawer.h>
#include <video/shaders/ColorShader.h>
#include <video/shaders/FXAAShader.h>
#include <video/shaders/Shader3D.h>
#include <video/shaders/ShaderFractalColor.h>
#include <video/shaders/Texture2DShader.h>
CursorDrawer *CursorDrawer::instance = NULL;
CursorDrawer::CursorDrawer() {
init_colorVtxs();
}
CursorDrawer::~CursorDrawer() {
//! destroy shaders
ColorShader::destroyInstance();
FXAAShader::destroyInstance();
Shader3D::destroyInstance();
ShaderFractalColor::destroyInstance();
Texture2DShader::destroyInstance();
if (this->colorVtxs) {
free(this->colorVtxs);
this->colorVtxs = NULL;
}
}
void CursorDrawer::init_colorVtxs() {
if (!this->colorVtxs) {
this->colorVtxs = (uint8_t *) memalign(0x40, sizeof(uint8_t) * 16);
if (this->colorVtxs == NULL) { return; }
}
memset(this->colorVtxs, 0xFF, 16 * sizeof(uint8_t));
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, this->colorVtxs, 16 * sizeof(uint8_t));
}
// Could be improved. It be more generic.
void CursorDrawer::draw_Cursor(float x, float y) {
if (this->colorVtxs == NULL) {
init_colorVtxs();
return;
}
float widthScaleFactor = 1.0f / (float) 1280;
float heightScaleFactor = 1.0f / (float) 720;
int32_t width = 20;
glm::vec3 positionOffsets = glm::vec3(0.0f);
positionOffsets[0] = (x - ((1280) / 2) + (width / 2)) * widthScaleFactor * 2.0f;
positionOffsets[1] = -(y - ((720) / 2) + (width / 2)) * heightScaleFactor * 2.0f;
glm::vec3 scale(width * widthScaleFactor, width * heightScaleFactor, 1.0f);
ColorShader::instance()->setShaders();
ColorShader::instance()->setAttributeBuffer(this->colorVtxs, NULL, 4);
ColorShader::instance()->setAngle(0);
ColorShader::instance()->setOffset(positionOffsets);
ColorShader::instance()->setScale(scale);
ColorShader::instance()->setColorIntensity(glm::vec4(1.0f));
ColorShader::instance()->draw(GX2_PRIMITIVE_MODE_QUADS, 4);
}

64
src/video/CursorDrawer.h Normal file
View File

@ -0,0 +1,64 @@
/****************************************************************************
* Copyright (C) 2016,2017 Maschell
*
* 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/>.
****************************************************************************/
#ifndef _CursorDrawer_H_
#define _CursorDrawer_H_
#include <string>
#include <stdint.h>
#include <stdio.h>
class CursorDrawer {
public:
static CursorDrawer *getInstance() {
if (!instance) {
instance = new CursorDrawer();
}
return instance;
}
static void destroyInstance() {
if (instance) {
delete instance;
instance = NULL;
}
}
static void draw(float x, float y) {
CursorDrawer *cur_instance = getInstance();
if (cur_instance == NULL) { return; }
cur_instance->draw_Cursor(x, y);
}
private:
//!Constructor
CursorDrawer();
//!Destructor
~CursorDrawer();
static CursorDrawer *instance;
void draw_Cursor(float x, float y);
void init_colorVtxs();
uint8_t *colorVtxs = NULL;
};
#endif

View File

@ -0,0 +1,171 @@
/****************************************************************************
* 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 <video/shaders/ColorShader.h>
#include <malloc.h>
#include <string.h>
static const uint32_t cpVertexShaderProgram[] = {
0x00000000, 0x00008009, 0x20000000, 0x000078a0,
0x3c200000, 0x88060094, 0x00c00000, 0x88062014,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00a11f00, 0xfc00620f, 0x02490001, 0x80000040,
0xfd041f80, 0x900c0060, 0x83f9223e, 0x0000803f,
0xfe282001, 0x10000040, 0xfe001f80, 0x00080060,
0xfeac9f80, 0xfd00624f, 0xdb0f49c0, 0xdb0fc940,
0xfea81f80, 0x9000e02f, 0x83f9223e, 0x00000000,
0xfe041f80, 0x00370000, 0xffa01f00, 0x80000000,
0xff101f00, 0x800c0020, 0x7f041f80, 0x80370000,
0x0000103f, 0x00000000, 0x02c51f00, 0x80000000,
0xfea41f00, 0x80000020, 0xffa09f00, 0x80000040,
0xff001f80, 0x800c0060, 0x398ee33f, 0x0000103f,
0x02c41f00, 0x9000e00f, 0x02c59f01, 0x80000020,
0xfea81f00, 0x80000040, 0x02c19f80, 0x9000e06f,
0x398ee33f, 0x00000000, 0x02c11f01, 0x80000000,
0x02c49f80, 0x80000060, 0x02e08f01, 0xfe0c620f,
0x02c01f80, 0x7f00622f, 0xfe242000, 0x10000000,
0xfe20a080, 0x10000020, 0xf2178647, 0x49c0e9fb,
0xfbbdb2ab, 0x768ac733};
static const uint32_t cpVertexShaderRegs[] = {
0x00000103, 0x00000000, 0x00000000, 0x00000001,
0xffffff00, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0x00000000, 0xfffffffc,
0x00000002, 0x00000001, 0x00000000, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x00000000, 0x0000000e, 0x00000010};
static const uint32_t cpPixelShaderProgram[] = {
0x20000000, 0x00000ca0, 0x00000000, 0x88062094,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00002000, 0x90000000, 0x0004a000, 0x90000020,
0x00082001, 0x90000040, 0x000ca081, 0x90000060,
0xbb7dd898, 0x9746c59c, 0xc69b00e7, 0x03c36218};
static const uint32_t cpPixelShaderRegs[] = {
0x00000001, 0x00000002, 0x14000001, 0x00000000,
0x00000001, 0x00000100, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x0000000f, 0x00000001, 0x00000010,
0x00000000};
ColorShader *ColorShader::shaderInstance = NULL;
ColorShader::ColorShader()
: vertexShader(cuAttributeCount) {
//! create pixel shader
pixelShader.setProgram(cpPixelShaderProgram, sizeof(cpPixelShaderProgram), cpPixelShaderRegs, sizeof(cpPixelShaderRegs));
colorIntensityLocation = 0;
pixelShader.addUniformVar((GX2UniformVar){
"unf_color_intensity", GX2_SHADER_VAR_TYPE_FLOAT4, 1, colorIntensityLocation, -1});
//! create vertex shader
vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs));
angleLocation = 0;
offsetLocation = 4;
scaleLocation = 8;
vertexShader.addUniformVar((GX2UniformVar){
"unf_angle", GX2_SHADER_VAR_TYPE_FLOAT, 1, angleLocation, -1});
vertexShader.addUniformVar((GX2UniformVar){
"unf_offset", GX2_SHADER_VAR_TYPE_FLOAT3, 1, offsetLocation, -1});
vertexShader.addUniformVar((GX2UniformVar){
"unf_scale", GX2_SHADER_VAR_TYPE_FLOAT3, 1, scaleLocation, -1});
colorLocation = 1;
positionLocation = 0;
vertexShader.addAttribVar((GX2AttribVar){
"attr_color", GX2_SHADER_VAR_TYPE_FLOAT4, 0, colorLocation});
vertexShader.addAttribVar((GX2AttribVar){
"attr_position", GX2_SHADER_VAR_TYPE_FLOAT3, 0, positionLocation});
//! setup attribute streams
GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32_32);
GX2InitAttribStream(vertexShader.getAttributeBuffer(1), colorLocation, 1, 0, GX2_ATTRIB_FORMAT_UNORM_8_8_8_8);
//! create fetch shader
fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount());
//! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000
positionVtxs = (float *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, cuPositionVtxsSize);
if (positionVtxs) {
//! position vertex structure
int32_t i = 0;
positionVtxs[i++] = -1.0f;
positionVtxs[i++] = -1.0f;
positionVtxs[i++] = 0.0f;
positionVtxs[i++] = 1.0f;
positionVtxs[i++] = -1.0f;
positionVtxs[i++] = 0.0f;
positionVtxs[i++] = 1.0f;
positionVtxs[i++] = 1.0f;
positionVtxs[i++] = 0.0f;
positionVtxs[i++] = -1.0f;
positionVtxs[i++] = 1.0f;
positionVtxs[i++] = 0.0f;
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, positionVtxs, cuPositionVtxsSize);
}
}
ColorShader::~ColorShader() {
if (positionVtxs) {
free(positionVtxs);
positionVtxs = NULL;
}
delete fetchShader;
fetchShader = NULL;
}

View File

@ -0,0 +1,98 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef __COLOR_SHADER_H_
#define __COLOR_SHADER_H_
#include <video/shaders/FetchShader.h>
#include <video/shaders/PixelShader.h>
#include <video/shaders/VertexShader.h>
class ColorShader : public Shader {
private:
ColorShader();
virtual ~ColorShader();
static const uint32_t cuAttributeCount = 2;
static const uint32_t cuPositionVtxsSize = 4 * cuVertexAttrSize;
static ColorShader *shaderInstance;
FetchShader *fetchShader;
VertexShader vertexShader;
PixelShader pixelShader;
float *positionVtxs;
uint32_t angleLocation;
uint32_t offsetLocation;
uint32_t scaleLocation;
uint32_t colorLocation;
uint32_t colorIntensityLocation;
uint32_t positionLocation;
public:
static const uint32_t cuColorVtxsSize = 4 * cuColorAttrSize;
static ColorShader *instance() {
if (!shaderInstance) {
shaderInstance = new ColorShader();
}
return shaderInstance;
}
static void destroyInstance() {
if (shaderInstance) {
delete shaderInstance;
shaderInstance = NULL;
}
}
void setShaders(void) const {
fetchShader->setShader();
vertexShader.setShader();
pixelShader.setShader();
}
void setAttributeBuffer(const uint8_t *colorAttr, const float *posVtxs_in = NULL, const uint32_t &vtxCount = 0) const {
if (posVtxs_in && vtxCount) {
VertexShader::setAttributeBuffer(0, vtxCount * cuVertexAttrSize, cuVertexAttrSize, posVtxs_in);
VertexShader::setAttributeBuffer(1, vtxCount * cuColorAttrSize, cuColorAttrSize, colorAttr);
} else {
VertexShader::setAttributeBuffer(0, cuPositionVtxsSize, cuVertexAttrSize, positionVtxs);
VertexShader::setAttributeBuffer(1, cuColorVtxsSize, cuColorAttrSize, colorAttr);
}
}
void setAngle(const float &val) {
VertexShader::setUniformReg(angleLocation, 4, &val);
}
void setOffset(const glm::vec3 &vec) {
VertexShader::setUniformReg(offsetLocation, 4, &vec[0]);
}
void setScale(const glm::vec3 &vec) {
VertexShader::setUniformReg(scaleLocation, 4, &vec[0]);
}
void setColorIntensity(const glm::vec4 &vec) {
PixelShader::setUniformReg(colorIntensityLocation, 4, &vec[0]);
}
};
#endif // __COLOR_SHADER_H_

View File

@ -0,0 +1,236 @@
/****************************************************************************
* 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 <video/shaders/FXAAShader.h>
#include <malloc.h>
#include <string.h>
static const uint32_t cpVertexShaderProgram[] = {
0x00000000, 0x00008009, 0x20000000, 0x000004a0,
0x3ca00000, 0x88060094, 0x00400000, 0xff0f2094,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0xfd001f80, 0x900c2060, 0x0000803f, 0x00000000,
0xc1a229f5, 0xd0eddc33, 0x426618fd, 0x8509cfe7};
static const uint32_t cpVertexShaderRegs[] = {
0x00000102, 0x00000000, 0x00000000, 0x00000001,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0x00000000, 0xfffffffe,
0x00000001, 0x00000000, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x00000000, 0x0000000e, 0x00000010};
static const uint32_t cpPixelShaderProgram[] = {
0x20000000, 0x00003ca0, 0xa0000000, 0x000c8080,
0x30000000, 0x000010a1, 0xa8000000, 0x0010c080,
0x75000000, 0x000088a0, 0x00800100, 0x88062094,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00241f02, 0x1000e00f, 0x00241f00, 0x1000e02f,
0x00201f02, 0x00000040, 0x00201f00, 0x00000060,
0x00011f80, 0x10332060, 0xff000000, 0xff102200,
0xfd001f00, 0x900cc020, 0xffc09f01, 0x90004040,
0xffc01f01, 0x90000060, 0x00051f80, 0x1033a040,
0x0000803f, 0x00000000, 0xffe00f00, 0x90004000,
0xff008000, 0xff102220, 0xffe08f00, 0x90000440,
0x010c0000, 0x010c4660, 0xff008080, 0xff004220,
0x01a01f00, 0x00280000, 0x01a49f00, 0x00280020,
0x01a81f01, 0x00280040, 0xfd0c1f00, 0x1028e06f,
0x00208081, 0x90002000, 0x8716993e, 0xa245163f,
0xd578e93d, 0x00000080, 0x03a01f00, 0x00280000,
0x03a49f00, 0x00280020, 0x03a81f01, 0x1028e04f,
0xfd0c1f00, 0x00280060, 0x00a40081, 0x90002020,
0x8716993e, 0xa245163f, 0xd578e93d, 0x00000080,
0x04a01f00, 0x00280000, 0x04a49f00, 0x1028a02f,
0x04a81f01, 0x00280040, 0xfd0c1f00, 0x00280060,
0x7fcc1f80, 0x1000c02f, 0x8716993e, 0xa245163f,
0xd578e93d, 0x00000080, 0x02a01f00, 0x1028e00f,
0x02a49f00, 0x00280020, 0x02a81f01, 0x00280040,
0xfd0c1f00, 0x00280060, 0x7fcc1f80, 0x1000e02f,
0x8716993e, 0xa245163f, 0xd578e93d, 0x00000080,
0x7dc41f00, 0x00020000, 0x7fec0f01, 0x00020020,
0x7fc81f00, 0x00000040, 0x7dc41f00, 0x00000060,
0x7fec0f81, 0x9001802f, 0xfef88f00, 0x1000e00f,
0xfedc8f00, 0x00000420, 0x7de40f00, 0x80010040,
0x7ec49f01, 0x00001060, 0xfec41f80, 0x10024060,
0xfed49f00, 0x80020000, 0xfe141f00, 0x900c802f,
0xfeac1f00, 0x80000040, 0xfec01f02, 0x80020060,
0x7cc41f81, 0x90010060, 0x0000003d, 0x00000000,
0xfd001f00, 0x900c6000, 0xfea89f00, 0x80010020,
0xfec09f81, 0x00020040, 0x0000803f, 0x0000003e,
0xfec41f81, 0x00000020, 0xfe041f80, 0x00330000,
0x7fe01f00, 0x80000040, 0x7ce41f80, 0x80000060,
0xfea81f00, 0x80010000, 0xfeac1f80, 0x80010020,
0x000000c1, 0x00000000, 0xfea01f00, 0x00020040,
0xfea41f80, 0x00020060, 0x00000041, 0x00000000,
0x05c81f01, 0x9000e00f, 0x01cc9f81, 0x9000e06f,
0xfeac1f00, 0x01004200, 0xfea01f00, 0x01044220,
0xfeac9f00, 0x01002240, 0xfea09f00, 0x01042260,
0xfe8c1f80, 0x01008600, 0xacaa2a3e, 0xaaaa2abe,
0x7f9c1f00, 0x0100a200, 0x7f801f00, 0x01048220,
0x7f901f80, 0x0104a240, 0x02080001, 0x7000a00f,
0x02000000, 0x7000c04f, 0x02048000, 0x7000e06f,
0x01a81f80, 0x9000e00f, 0xd578e93d, 0x00000000,
0x04a80001, 0x1000c00f, 0x04a48000, 0x00000020,
0x04a00000, 0x00000040, 0xfe081f00, 0xe00c0060,
0xfe0c1f80, 0xe00c0000, 0x01a41f00, 0x7f00620f,
0xfea89f00, 0xfe0c822f, 0xfea49f00, 0xff00a24f,
0x7d001f80, 0xe00c0060, 0xa245163f, 0x0000803e,
0x7ea01f00, 0xfe0ce20f, 0x01a09f80, 0xfe006a4f,
0x0000803e, 0x8716993e, 0xfe088001, 0x9001c00f,
0xfe488001, 0x1002e44f, 0xfea01f80, 0x80000000,
0xd578e93d, 0x00000000, 0x7ca41f00, 0x00280000,
0x7da89f00, 0x00280020, 0xff201f00, 0x00280040,
0xfd081f80, 0x00280060, 0x8716993e, 0xa245163f,
0x00000080, 0x00000000, 0x7fc81f00, 0x80060000,
0xfec00f80, 0x80060060, 0xfec09f81, 0xfb80634f,
0xfe888f00, 0x7e886300, 0xfea80f01, 0x7f8c6320,
0xfee80f00, 0x7d806340, 0xfe680080, 0x06846f60,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x10000100, 0x01101df0, 0x00008010, 0xecdfea0d,
0x10000200, 0x03101df0, 0x00002050, 0xecdfea0d,
0x10000000, 0x04101df0, 0x00003071, 0xecdfea0d,
0x10000200, 0x02101df0, 0x0000b070, 0xecdfea0d,
0x10000200, 0x02101df0, 0x00008010, 0xecdfea0d,
0x10000100, 0x00101df0, 0x0000a051, 0xecdfea0d,
0x10000400, 0x04101df0, 0x00008010, 0xecdfea0d,
0x10000500, 0x05101df0, 0x00000011, 0xecdfea0d,
0x10000100, 0x01101df0, 0x00008010, 0xecdfea0d,
0xfe2e963a, 0x0269a9a3, 0x38f88096, 0x400cf48b};
static const uint32_t cpPixelShaderRegs[] = {
0x00000007, 0x00000002, 0x04000101, 0x00000000,
0x00000001, 0x00000100, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x0000000f, 0x00000001, 0x00000010,
0x00000000};
FXAAShader *FXAAShader::shaderInstance = NULL;
FXAAShader::FXAAShader()
: vertexShader(cuAttributeCount) {
//! create pixel shader
pixelShader.setProgram(cpPixelShaderProgram, sizeof(cpPixelShaderProgram), cpPixelShaderRegs, sizeof(cpPixelShaderRegs));
resolutionLocation = 0;
pixelShader.addUniformVar((GX2UniformVar){
"unf_resolution", GX2_SHADER_VAR_TYPE_FLOAT2, 1, resolutionLocation, -1});
samplerLocation = 0;
pixelShader.addSamplerVar((GX2SamplerVar){
"sampl_texture", GX2_SAMPLER_VAR_TYPE_SAMPLER_2D, samplerLocation});
//! create vertex shader
vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs));
positionLocation = 0;
texCoordLocation = 1;
vertexShader.addAttribVar((GX2AttribVar){
"attr_position", GX2_SHADER_VAR_TYPE_FLOAT3, 0, positionLocation});
vertexShader.addAttribVar((GX2AttribVar){
"attr_texture_coord", GX2_SHADER_VAR_TYPE_FLOAT2, 0, texCoordLocation});
//! setup attribute streams
GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32_32);
GX2InitAttribStream(vertexShader.getAttributeBuffer(1), texCoordLocation, 1, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32);
//! create fetch shader
fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount());
//! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000
posVtxs = (float *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciPositionVtxsSize);
texCoords = (float *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciTexCoordsVtxsSize);
//! position vertex structure and texture coordinate vertex structure
int32_t i = 0;
posVtxs[i++] = -1.0f;
posVtxs[i++] = -1.0f;
posVtxs[i++] = 0.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = -1.0f;
posVtxs[i++] = 0.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = 0.0f;
posVtxs[i++] = -1.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = 0.0f;
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, posVtxs, ciPositionVtxsSize);
i = 0;
texCoords[i++] = 0.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 0.0f;
texCoords[i++] = 0.0f;
texCoords[i++] = 0.0f;
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, texCoords, ciTexCoordsVtxsSize);
}
FXAAShader::~FXAAShader() {
if (posVtxs) {
free(posVtxs);
posVtxs = NULL;
}
if (texCoords) {
free(texCoords);
texCoords = NULL;
}
delete fetchShader;
fetchShader = NULL;
}

View File

@ -0,0 +1,84 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef __FXAA_SHADER_H_
#define __FXAA_SHADER_H_
#include <video/shaders/FetchShader.h>
#include <video/shaders/PixelShader.h>
#include <video/shaders/VertexShader.h>
class FXAAShader : public Shader {
public:
static FXAAShader *instance() {
if (!shaderInstance) {
shaderInstance = new FXAAShader();
}
return shaderInstance;
}
static void destroyInstance() {
if (shaderInstance) {
delete shaderInstance;
shaderInstance = NULL;
}
}
void setShaders(void) const {
fetchShader->setShader();
vertexShader.setShader();
pixelShader.setShader();
}
void setAttributeBuffer() const {
VertexShader::setAttributeBuffer(0, ciPositionVtxsSize, cuVertexAttrSize, posVtxs);
VertexShader::setAttributeBuffer(1, ciTexCoordsVtxsSize, cuTexCoordAttrSize, texCoords);
}
void setResolution(const glm::vec2 &vec) {
PixelShader::setUniformReg(resolutionLocation, 4, &vec[0]);
}
void setTextureAndSampler(const GX2Texture *texture, const GX2Sampler *sampler) const {
GX2SetPixelTexture((GX2Texture *) texture, samplerLocation);
GX2SetPixelSampler((GX2Sampler *) sampler, samplerLocation);
}
private:
FXAAShader();
virtual ~FXAAShader();
static const uint32_t cuAttributeCount = 2;
static const uint32_t ciPositionVtxsSize = 4 * cuVertexAttrSize;
static const uint32_t ciTexCoordsVtxsSize = 4 * cuTexCoordAttrSize;
static FXAAShader *shaderInstance;
FetchShader *fetchShader;
VertexShader vertexShader;
PixelShader pixelShader;
float *posVtxs;
float *texCoords;
uint32_t samplerLocation;
uint32_t positionLocation;
uint32_t texCoordLocation;
uint32_t resolutionLocation;
};
#endif // __FXAA_SHADER_H_

View File

@ -0,0 +1,57 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef FETCH_SHADER_H
#define FETCH_SHADER_H
#include <video/shaders/Shader.h>
class FetchShader : public Shader {
public:
FetchShader(GX2AttribStream *attributes, uint32_t attrCount, GX2FetchShaderType type = GX2_FETCH_SHADER_TESSELLATION_NONE, GX2TessellationMode tess = GX2_TESSELLATION_MODE_DISCRETE)
: fetchShader(NULL), fetchShaderProgramm(NULL) {
uint32_t shaderSize = GX2CalcFetchShaderSizeEx(attrCount, type, tess);
fetchShaderProgramm = (uint8_t *) memalign(GX2_SHADER_PROGRAM_ALIGNMENT, shaderSize);
if (fetchShaderProgramm) {
fetchShader = new GX2FetchShader;
GX2InitFetchShaderEx(fetchShader, fetchShaderProgramm, attrCount, attributes, type, tess);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, fetchShaderProgramm, shaderSize);
}
}
virtual ~FetchShader() {
if (fetchShaderProgramm) {
free(fetchShaderProgramm);
}
if (fetchShader) {
delete fetchShader;
}
}
GX2FetchShader *getFetchShader() const {
return fetchShader;
}
void setShader(void) const {
GX2SetFetchShader(fetchShader);
}
protected:
GX2FetchShader *fetchShader;
uint8_t *fetchShaderProgramm;
};
#endif // FETCH_SHADER_H

View File

@ -0,0 +1,152 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef PIXEL_SHADER_H
#define PIXEL_SHADER_H
#include <video/shaders/Shader.h>
class PixelShader : public Shader {
public:
PixelShader()
: pixelShader((GX2PixelShader *) memalign(0x40, sizeof(GX2PixelShader))) {
if (pixelShader) {
memset(pixelShader, 0, sizeof(GX2PixelShader));
pixelShader->mode = GX2_SHADER_MODE_UNIFORM_REGISTER;
}
}
virtual ~PixelShader() {
if (pixelShader) {
if (pixelShader->program) {
free(pixelShader->program);
}
for (uint32_t i = 0; i < pixelShader->uniformBlockCount; i++) {
free((void *) pixelShader->uniformBlocks[i].name);
}
if (pixelShader->uniformBlocks) {
free((void *) pixelShader->uniformBlocks);
}
for (uint32_t i = 0; i < pixelShader->uniformVarCount; i++) {
free((void *) pixelShader->uniformVars[i].name);
}
if (pixelShader->uniformVars) {
free((void *) pixelShader->uniformVars);
}
if (pixelShader->initialValues) {
free((void *) pixelShader->initialValues);
}
for (uint32_t i = 0; i < pixelShader->samplerVarCount; i++) {
free((void *) pixelShader->samplerVars[i].name);
}
if (pixelShader->samplerVars) {
free((void *) pixelShader->samplerVars);
}
if (pixelShader->loopVars) {
free((void *) pixelShader->loopVars);
}
free(pixelShader);
}
}
void setProgram(const uint32_t *program, const uint32_t &programSize, const uint32_t *regs, const uint32_t &regsSize) {
if (!pixelShader) {
return;
}
//! this must be moved into an area where the graphic engine has access to and must be aligned to 0x100
pixelShader->size = programSize;
pixelShader->program = (uint8_t *) memalign(GX2_SHADER_PROGRAM_ALIGNMENT, pixelShader->size);
if (pixelShader->program) {
memcpy(pixelShader->program, program, pixelShader->size);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, pixelShader->program, pixelShader->size);
}
memcpy(&pixelShader->regs, regs, regsSize);
}
void addUniformVar(const GX2UniformVar &var) {
if (!pixelShader) {
return;
}
uint32_t idx = pixelShader->uniformVarCount;
GX2UniformVar *newVar = (GX2UniformVar *) malloc((pixelShader->uniformVarCount + 1) * sizeof(GX2UniformVar));
if (newVar) {
if (pixelShader->uniformVars) {
memcpy(newVar, pixelShader->uniformVars, pixelShader->uniformVarCount * sizeof(GX2UniformVar));
free(pixelShader->uniformVars);
}
pixelShader->uniformVars = newVar;
memcpy(pixelShader->uniformVars + idx, &var, sizeof(GX2UniformVar));
pixelShader->uniformVars[idx].name = (char *) malloc(strlen(var.name) + 1);
strcpy((char *) pixelShader->uniformVars[idx].name, var.name);
pixelShader->uniformVarCount++;
}
}
void addSamplerVar(const GX2SamplerVar &var) {
if (!pixelShader) {
return;
}
uint32_t idx = pixelShader->samplerVarCount;
GX2SamplerVar *newVar = (GX2SamplerVar *) malloc((pixelShader->samplerVarCount + 1) * sizeof(GX2SamplerVar));
if (newVar) {
if (pixelShader->samplerVars) {
memcpy(newVar, pixelShader->samplerVars, pixelShader->samplerVarCount * sizeof(GX2SamplerVar));
free(pixelShader->samplerVars);
}
pixelShader->samplerVars = newVar;
memcpy(pixelShader->samplerVars + idx, &var, sizeof(GX2SamplerVar));
pixelShader->samplerVars[idx].name = (char *) malloc(strlen(var.name) + 1);
strcpy((char *) pixelShader->samplerVars[idx].name, var.name);
pixelShader->samplerVarCount++;
}
}
GX2PixelShader *getPixelShader() const {
return pixelShader;
}
void setShader(void) const {
GX2SetPixelShader(pixelShader);
}
static inline void setUniformReg(uint32_t location, uint32_t size, const void *reg) {
GX2SetPixelUniformReg(location, size, (uint32_t *) reg);
}
protected:
GX2PixelShader *pixelShader;
};
#endif // PIXEL_SHADER_H

View File

@ -0,0 +1,72 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef SHADER_H_
#define SHADER_H_
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <gx2/draw.h>
#include <gx2/enum.h>
#include <gx2/mem.h>
#include <gx2/registers.h>
#include <gx2/shaders.h>
#include <malloc.h>
class Shader {
protected:
Shader() {}
virtual ~Shader() {}
public:
static const uint16_t cuVertexAttrSize = sizeof(float) * 3;
static const uint16_t cuTexCoordAttrSize = sizeof(float) * 2;
static const uint16_t cuColorAttrSize = sizeof(uint8_t) * 4;
static void setLineWidth(const float &width) {
GX2SetLineWidth(width);
}
static void draw(int32_t primitive = GX2_PRIMITIVE_MODE_QUADS, uint32_t vtxCount = 4) {
switch (primitive) {
default:
case GX2_PRIMITIVE_MODE_QUADS: {
GX2DrawEx(GX2_PRIMITIVE_MODE_QUADS, vtxCount, 0, 1);
break;
}
case GX2_PRIMITIVE_MODE_TRIANGLES: {
GX2DrawEx(GX2_PRIMITIVE_MODE_TRIANGLES, vtxCount, 0, 1);
break;
}
case GX2_PRIMITIVE_MODE_TRIANGLE_FAN: {
GX2DrawEx(GX2_PRIMITIVE_MODE_TRIANGLE_FAN, vtxCount, 0, 1);
break;
}
case GX2_PRIMITIVE_MODE_LINES: {
GX2DrawEx(GX2_PRIMITIVE_MODE_LINES, vtxCount, 0, 1);
break;
}
case GX2_PRIMITIVE_MODE_LINE_STRIP: {
GX2DrawEx(GX2_PRIMITIVE_MODE_LINE_STRIP, vtxCount, 0, 1);
break;
}
//! TODO: add other primitives later
};
}
};
#endif // SHADER_H_

View File

@ -0,0 +1,276 @@
/****************************************************************************
* 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 <video/shaders/Shader3D.h>
#include <malloc.h>
#include <string.h>
static const uint32_t cpVertexShaderProgram[] = {
0x00000000, 0x00008009, 0x20000000, 0x0000e4a1,
0x00c00100, 0x88048093, 0x01c00300, 0x98060014,
0x9a000000, 0x000058a0, 0x3c200200, 0x88062094,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x0765a101, 0x9000e00f, 0x0761a101, 0x9000e02f,
0x01081f00, 0x900ce040, 0x01041f00, 0x900ce060,
0x01001f80, 0x900ce000, 0x02001f00, 0x900c6000,
0x02041f00, 0x900c6020, 0x076da101, 0x9000e04f,
0x0769a181, 0x9000e06f, 0x0745a101, 0x9000c00f,
0x0741a181, 0x9000c02f, 0x074da101, 0x9000c04f,
0x0749a181, 0x9000c06f, 0x0bc9a000, 0x7f00e20f,
0x0bc92080, 0x7f04e22f, 0x0bc9a001, 0x7f08e24f,
0x0bc92081, 0x7f0ce26f, 0x0725a101, 0x9000a00f,
0x0721a181, 0x9000a02f, 0x072da101, 0x9000a04f,
0x0729a181, 0x9000a06f, 0x0ac9a000, 0x7e00c20f,
0x0ac92080, 0x7e04c22f, 0x0ac9a001, 0x7e08c24f,
0x0ac92081, 0x7e0cc26f, 0x0ba5a000, 0x7f00e20f,
0x0ba52080, 0x7f04e22f, 0x0ba5a001, 0x7f08e24f,
0x0ba52081, 0x7f0ce26f, 0x08eda000, 0x9000800f,
0x08ed2080, 0x9000802f, 0x08eda001, 0x9000804f,
0x08ed2081, 0x9000806f, 0x09c9a000, 0x7d00a20f,
0x09c92080, 0x7d04a22f, 0x09c9a001, 0x7d08a24f,
0x09c92081, 0x7d0ca26f, 0x0aa5a000, 0x7e00c20f,
0x0aa52080, 0x7e04c22f, 0x0aa5a001, 0x7e08c24f,
0x0aa52081, 0x7e0cc26f, 0x0b81a000, 0x7f004200,
0x0b812080, 0x7f044220, 0x0b81a001, 0x7f082240,
0x0b812081, 0x7f0c0260, 0x08c9a000, 0x7c00820f,
0x08c92080, 0x7c04822f, 0x08c9a001, 0x7c08824f,
0x08c92081, 0x7c0c826f, 0x09a5a000, 0x7d00a20f,
0x09a52080, 0x7d04a22f, 0x09a5a001, 0x7d08a24f,
0x09a52081, 0x7d0ca26f, 0x0a81a000, 0x7e000200,
0x0a812080, 0x7e040220, 0x0a81a001, 0x7e080240,
0x0a812081, 0x7e0c2260, 0x0240a001, 0x9000c00f,
0x0244a001, 0x9000c02f, 0x0148a001, 0x9000c04f,
0x004ca001, 0x9000c06f, 0x0264a081, 0x9000e02f,
0x0260a001, 0x9000e00f, 0x0224a001, 0x90002020,
0x0168a001, 0x9000e04f, 0x006ca001, 0x9000e06f,
0x0220a081, 0x90002000, 0x08a5a000, 0x7c00820f,
0x08a52080, 0x7c04822f, 0x08a5a001, 0x7c08824f,
0x08a52081, 0x7c0c826f, 0x0981a000, 0x7d008200,
0x09812080, 0x7d048220, 0x0981a001, 0x7d084240,
0x09812081, 0x7d0c4260, 0x02090000, 0x7e00c20f,
0x02098000, 0x7e04c22f, 0x0128a001, 0x9000a04f,
0x002ca001, 0x9000c06f, 0x02298081, 0x7e0caa6f,
0x03090000, 0x7f00e20f, 0x03098000, 0x7f04e22f,
0x02090001, 0x7e08f64f, 0x03298001, 0x7f0ce26f,
0x03090081, 0x7f08ca4f, 0x0881a000, 0x7c00c200,
0x08812080, 0x7c04e220, 0x0881a001, 0x7c08a240,
0x08812081, 0x7c0c8260, 0x0200a001, 0x9000800f,
0x0204a001, 0x9000802f, 0x0108a001, 0x9000804f,
0x000ca001, 0x9000806f, 0x01098080, 0x0104aa2f,
0x01090000, 0x0100a20f, 0x02858000, 0x7e04c22f,
0x01090001, 0x7d08a24f, 0x01298081, 0x7e0cc26f,
0x02850000, 0x7e00f60f, 0x03858000, 0x7f04622f,
0x02450001, 0x7f08e24f, 0x02458001, 0x7d0ca26f,
0x03850080, 0x7f00ca0f, 0x00090000, 0x7c004200,
0x00098000, 0x7c04b220, 0x03450001, 0x7e08c24f,
0x03458001, 0x7f0ce26f, 0x03e18080, 0xfe042620,
0x01850000, 0x7d00a200, 0x01858000, 0x7d04622f,
0x00090001, 0x7c086240, 0x00298081, 0x7c0c0260,
0x02c10000, 0x7f000200, 0x02e18000, 0x7e040620,
0x01450001, 0x7d088240, 0x01458001, 0x7e0c6260,
0x01e18080, 0xfe04c620, 0x03c10000, 0x7e002200,
0x03818001, 0x7f0c4220, 0x02a10001, 0x7f081640,
0x02818001, 0x7d0c3660, 0x03a10081, 0x7e082a40,
0x07080000, 0x0100c20f, 0x07088000, 0x0104622f,
0x00458001, 0x000cea4f, 0x07288081, 0x0204f66f,
0x00850000, 0x0200620f, 0x00858000, 0x05046a2f,
0x07080001, 0x0108c24f, 0x01818001, 0x030c726f,
0x07cc8080, 0xfe04c22f, 0x01c10000, 0x0500660f,
0x00e18000, 0xfe04622f, 0x00450001, 0x0308624f,
0x07cc9f01, 0x7f0ce26f, 0x00c10080, 0xfe00e60f,
0x07cc1f00, 0x7e00660f, 0x00a10001, 0xfe08c22f,
0x01a10001, 0x0408624f, 0x00818001, 0x7f086a6f,
0x07c09f80, 0x7e048200, 0x07e00f00, 0xfe008220,
0x07cc1f01, 0x7e086a4f, 0x07c09f81, 0x7f0c8240,
0x07c08f80, 0xfe088260, 0x2c34800d, 0xe3b4f15e,
0x7642ed30, 0x7408600d};
static const uint32_t cpVertexShaderRegs[] = {
0x00000108, 0x00000000, 0x00000002, 0x00000001,
0xffff0001, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0x00000000, 0xfffffffc,
0x00000002, 0x00000000, 0x00000001, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x00000000, 0x0000000e, 0x00000010};
static const uint32_t cPixelShaderProgram[] = {
0x20000000, 0x000008a4, 0x03000000, 0x01004085,
0x23000000, 0x000044a8, 0x35000000, 0x000000a4,
0x06000000, 0x01004085, 0x36000000, 0x00002ca8,
0x50000000, 0x0000c080, 0x42000000, 0x00001ca0,
0x00800000, 0x88062094, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0xfd001f80, 0x900c0060, 0x0000803f, 0x00000000,
0x02011f80, 0x8c110000, 0xf8402000, 0x9006a00f,
0x02552001, 0x00000020, 0x01248082, 0x80020060,
0xfe3c1f00, 0x1000e04f, 0xfe041f80, 0x1033c00f,
0xfe482081, 0x80060020, 0xfee40f81, 0x0289e30f,
0x02c51f80, 0x80060060, 0xfeec0f80, 0x0285634f,
0xfec80f80, 0x80000060, 0xfe4ca081, 0x9000e04f,
0xfe281f00, 0x80060000, 0xf8c01f81, 0x9006e02f,
0xfee00f81, 0xfd80636f, 0x0000803f, 0x00000000,
0x7fc49f81, 0xf880e34f, 0xfe381f80, 0x00000000,
0x7de00f81, 0xfe800360, 0x01011f80, 0x8c100000,
0x00a81f00, 0x9000e02f, 0x00000082, 0x80020060,
0x00002040, 0x00000000, 0xfeac9f80, 0xfd00624f,
0x3333333f, 0x00002040, 0xfee88f80, 0x0101620f,
0x00cc1f80, 0x9000e06f, 0xf8c09f01, 0x80060020,
0xfe2c1f80, 0x9006e04f, 0xfee48f81, 0xf880630f,
0x7fc81f80, 0xfd800360, 0x0000803f, 0x00000000,
0x000ca001, 0x80000000, 0x00091f00, 0x800c0020,
0x00051f00, 0x800c0040, 0x00011f80, 0x800c0060,
0xfe2c0000, 0x90002000, 0xfe288000, 0x90002020,
0xfe240001, 0x90002040, 0xfe208081, 0x90002060,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x10000100, 0x01100df0, 0x00008010, 0xecdfea0d,
0x99720984, 0x041cab0d, 0xa28a9ccd, 0x95d199a5};
static const uint32_t cPixelShaderRegs[] = {
0x00000102, 0x00000002, 0x14000002, 0x00000000,
0x00000002, 0x00000100, 0x00000101, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x0000000f, 0x00000001, 0x00000010,
0x00000000};
Shader3D *Shader3D::shaderInstance = NULL;
Shader3D::Shader3D()
: vertexShader(cuAttributeCount) {
//! create pixel shader
pixelShader.setProgram(cPixelShaderProgram, sizeof(cPixelShaderProgram), cPixelShaderRegs, sizeof(cPixelShaderRegs));
colorIntensityLocation = 0;
fadeDistanceLocation = 4;
fadeOutLocation = 8;
pixelShader.addUniformVar((GX2UniformVar){
"unf_color_intensity", GX2_SHADER_VAR_TYPE_FLOAT4, 1, colorIntensityLocation, -1});
pixelShader.addUniformVar((GX2UniformVar){
"unf_fade_distance", GX2_SHADER_VAR_TYPE_FLOAT, 1, fadeDistanceLocation, -1});
pixelShader.addUniformVar((GX2UniformVar){
"unf_fade_out_alpha", GX2_SHADER_VAR_TYPE_FLOAT4, 1, fadeOutLocation, -1});
samplerLocation = 0;
pixelShader.addSamplerVar((GX2SamplerVar){
"sampl_texture", GX2_SAMPLER_VAR_TYPE_SAMPLER_2D, samplerLocation});
//! create vertex shader
vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs));
modelMatrixLocation = 0;
projectionMatrixLocation = 16;
viewMatrixLocation = 32;
vertexShader.addUniformVar((GX2UniformVar){
"modelMatrix", GX2_SHADER_VAR_TYPE_FLOAT4X4, 1, modelMatrixLocation, -1});
vertexShader.addUniformVar((GX2UniformVar){
"viewMatrix", GX2_SHADER_VAR_TYPE_FLOAT4X4, 1, projectionMatrixLocation, -1});
vertexShader.addUniformVar((GX2UniformVar){
"projectionMatrix", GX2_SHADER_VAR_TYPE_FLOAT4X4, 1, viewMatrixLocation, -1});
positionLocation = 0;
texCoordLocation = 1;
vertexShader.addAttribVar((GX2AttribVar){
"attr_position", GX2_SHADER_VAR_TYPE_FLOAT4, 0, positionLocation});
vertexShader.addAttribVar((GX2AttribVar){
"attr_texture_coord", GX2_SHADER_VAR_TYPE_FLOAT2, 0, texCoordLocation});
//! setup attribute streams
GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32_32);
GX2InitAttribStream(vertexShader.getAttributeBuffer(1), texCoordLocation, 1, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32);
//! create fetch shader
fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount());
//! initialize default quad texture vertexes as those are very commonly used
//! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000
posVtxs = (float *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciPositionVtxsSize);
texCoords = (float *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciTexCoordsVtxsSize);
//! position vertex structure and texture coordinate vertex structure
int32_t i = 0;
posVtxs[i++] = -1.0f;
posVtxs[i++] = -1.0f;
posVtxs[i++] = 0.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = -1.0f;
posVtxs[i++] = 0.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = 0.0f;
posVtxs[i++] = -1.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = 0.0f;
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, posVtxs, ciPositionVtxsSize);
i = 0;
texCoords[i++] = 0.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 0.0f;
texCoords[i++] = 0.0f;
texCoords[i++] = 0.0f;
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, texCoords, ciTexCoordsVtxsSize);
}
Shader3D::~Shader3D() {
if (posVtxs) {
free(posVtxs);
posVtxs = NULL;
}
if (texCoords) {
free(texCoords);
texCoords = NULL;
}
delete fetchShader;
fetchShader = NULL;
}

View File

@ -0,0 +1,116 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef SHADER_3D_H_
#define SHADER_3D_H_
#include <video/shaders/FetchShader.h>
#include <video/shaders/PixelShader.h>
#include <video/shaders/VertexShader.h>
class Shader3D : public Shader {
private:
Shader3D();
virtual ~Shader3D();
static Shader3D *shaderInstance;
static const unsigned char cuAttributeCount = 2;
static const uint32_t ciPositionVtxsSize = 4 * cuVertexAttrSize;
static const uint32_t ciTexCoordsVtxsSize = 4 * cuTexCoordAttrSize;
FetchShader *fetchShader;
VertexShader vertexShader;
PixelShader pixelShader;
float *posVtxs;
float *texCoords;
uint32_t modelMatrixLocation;
uint32_t viewMatrixLocation;
uint32_t projectionMatrixLocation;
uint32_t positionLocation;
uint32_t texCoordLocation;
uint32_t colorIntensityLocation;
uint32_t fadeDistanceLocation;
uint32_t fadeOutLocation;
uint32_t samplerLocation;
public:
static Shader3D *instance() {
if (!shaderInstance) {
shaderInstance = new Shader3D();
}
return shaderInstance;
}
static void destroyInstance() {
if (shaderInstance) {
delete shaderInstance;
shaderInstance = NULL;
}
}
void setShaders(void) const {
fetchShader->setShader();
vertexShader.setShader();
pixelShader.setShader();
}
void setAttributeBuffer(const uint32_t &vtxCount = 0, const float *posVtxs_in = NULL, const float *texCoords_in = NULL) const {
if (posVtxs_in && texCoords_in && vtxCount) {
VertexShader::setAttributeBuffer(0, vtxCount * cuVertexAttrSize, cuVertexAttrSize, posVtxs_in);
VertexShader::setAttributeBuffer(1, vtxCount * cuTexCoordAttrSize, cuTexCoordAttrSize, texCoords_in);
} else {
//! use default quad vertex and texture coordinates if nothing is passed
VertexShader::setAttributeBuffer(0, ciPositionVtxsSize, cuVertexAttrSize, posVtxs);
VertexShader::setAttributeBuffer(1, ciTexCoordsVtxsSize, cuTexCoordAttrSize, texCoords);
}
}
void setProjectionMtx(const glm::mat4 &mtx) {
VertexShader::setUniformReg(projectionMatrixLocation, 16, &mtx[0][0]);
}
void setViewMtx(const glm::mat4 &mtx) {
VertexShader::setUniformReg(viewMatrixLocation, 16, &mtx[0][0]);
}
void setModelViewMtx(const glm::mat4 &mtx) {
VertexShader::setUniformReg(modelMatrixLocation, 16, &mtx[0][0]);
}
void setColorIntensity(const glm::vec4 &vec) {
PixelShader::setUniformReg(colorIntensityLocation, 4, &vec[0]);
}
void setAlphaFadeOut(const glm::vec4 &vec) {
PixelShader::setUniformReg(fadeOutLocation, 4, &vec[0]);
}
void setDistanceFadeOut(const float &value) {
PixelShader::setUniformReg(fadeDistanceLocation, 4, &value);
}
void setTextureAndSampler(const GX2Texture *texture, const GX2Sampler *sampler) const {
GX2SetPixelTexture((GX2Texture *) texture, samplerLocation);
GX2SetPixelSampler((GX2Sampler *) sampler, samplerLocation);
}
};
#endif // SHADER_3D_H_

View File

@ -0,0 +1,384 @@
/****************************************************************************
* 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 <video/shaders/ShaderFractalColor.h>
#include <malloc.h>
#include <string.h>
static const uint32_t cpVertexShaderProgram[] = {
0x00000000, 0x00008009, 0x20000000, 0x0000eca1,
0x00c00000, 0x88068093, 0x01400200, 0x9a048013,
0x9c000000, 0x000044a0, 0x3c200000, 0x88060094,
0x02400000, 0x88062014, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x0765a101, 0x9000e00f, 0x0761a101, 0x9000e02f,
0x03001f00, 0x900c8040, 0x03041f80, 0x900c8060,
0x076da101, 0x9000e04f, 0x0769a181, 0x9000e06f,
0x0745a101, 0x9000c00f, 0x0741a181, 0x9000c02f,
0x074da101, 0x9000c04f, 0x0749a181, 0x9000c06f,
0x0bc9a000, 0x7f00e20f, 0x0bc92080, 0x7f04e22f,
0x0bc9a001, 0x7f08e24f, 0x0bc92081, 0x7f0ce26f,
0x0725a101, 0x9000a00f, 0x0721a181, 0x9000a02f,
0x072da101, 0x9000a04f, 0x0729a181, 0x9000a06f,
0x0ac9a000, 0x7e00c20f, 0x0ac92080, 0x7e04c22f,
0x0ac9a001, 0x7e08c24f, 0x0ac92081, 0x7e0cc26f,
0x0ba5a000, 0x7f00e20f, 0x0ba52080, 0x7f04e22f,
0x0ba5a001, 0x7f08e24f, 0x0ba52081, 0x7f0ce26f,
0x08eda000, 0x9000800f, 0x08ed2080, 0x9000802f,
0x08eda001, 0x9000804f, 0x08ed2081, 0x9000806f,
0x09c9a000, 0x7d00a20f, 0x09c92080, 0x7d04a22f,
0x09c9a001, 0x7d08a24f, 0x09c92081, 0x7d0ca26f,
0x0aa5a000, 0x7e00c20f, 0x0aa52080, 0x7e04c22f,
0x0aa5a001, 0x7e08c24f, 0x0aa52081, 0x7e0cc26f,
0x0b81a000, 0x7f006200, 0x0b812080, 0x7f046220,
0x0b81a001, 0x7f080240, 0x0b812081, 0x7f0c0260,
0x08c9a000, 0x7c00820f, 0x08c92080, 0x7c04822f,
0x08c9a001, 0x7c08824f, 0x08c92081, 0x7c0c826f,
0x09a5a000, 0x7d00a20f, 0x09a52080, 0x7d04a22f,
0x09a5a001, 0x7d08a24f, 0x09a52081, 0x7d0ca26f,
0x0a81a000, 0x7e008200, 0x0a812080, 0x7e048220,
0x0a81a001, 0x7e086240, 0x0a812081, 0x7e0c4260,
0x0340a001, 0x9000c00f, 0x0344a001, 0x9000c02f,
0x0048a001, 0x9000c04f, 0x004ca001, 0x9000c06f,
0x0364a081, 0x9000e02f, 0x0360a001, 0x9000e00f,
0x0324a001, 0x90000020, 0x0068a001, 0x9000e04f,
0x006ca001, 0x9000e06f, 0x0320a081, 0x90000000,
0x08a5a000, 0x7c00820f, 0x08a52080, 0x7c04822f,
0x08a5a001, 0x7c08824f, 0x08a52081, 0x7c0c826f,
0x0981a000, 0x7d00a200, 0x09812080, 0x7d04a220,
0x0981a001, 0x7d08a240, 0x09812081, 0x7d0c6260,
0x02890000, 0x7e00c20f, 0x02898000, 0x7e04c22f,
0x0028a001, 0x9000a04f, 0x002ca001, 0x9000c06f,
0x02498081, 0x7e0caa6f, 0x03890000, 0x7f00e20f,
0x03898000, 0x7f04e22f, 0x02690001, 0x7e08f64f,
0x03498001, 0x7f0ce26f, 0x03690081, 0x7f08ca4f,
0x0881a000, 0x7c00c200, 0x08812080, 0x7c04c220,
0x0881a001, 0x7c08e240, 0x08812081, 0x7c0ca260,
0x0300a001, 0x9000800f, 0x0304a001, 0x9000802f,
0x0008a001, 0x9000804f, 0x000ca001, 0x9000806f,
0x01898080, 0x0004aa2f, 0x01890000, 0x0000a20f,
0x02a58000, 0x7e04c22f, 0x01690001, 0x7d08a24f,
0x01498081, 0x7e0cc26f, 0x02a50000, 0x7e00f60f,
0x03a58000, 0x7f04622f, 0x02a50001, 0x7f08e24f,
0x02658001, 0x7d0ca26f, 0x03a50080, 0x7f00ca0f,
0x00890000, 0x7c00820f, 0x00898000, 0x7c049220,
0x03a50001, 0x7e08c24f, 0x03658001, 0x7f0ce26f,
0x03c18080, 0xfe04862f, 0x01a50000, 0x7d008200,
0x01a58000, 0x7d04622f, 0x00690001, 0x7c086240,
0x00498081, 0x7c0c4260, 0x02c10000, 0x7f00e20f,
0x02c18000, 0x7e04c62f, 0x01a50001, 0x7d080240,
0x01658001, 0x7e0c0260, 0x01c18080, 0xfe040620,
0x03c10000, 0x7e00620f, 0x03a18001, 0x7f0c622f,
0x02e10001, 0x7f08764f, 0x02a18001, 0x7d0c766f,
0x03e10081, 0x7e084a0f, 0x02e80f00, 0xfe000e00,
0x02c88f00, 0x7c046220, 0x02c81f01, 0xff00c240,
0x02c89f01, 0xfe04c260, 0x00a50080, 0x7c00aa00,
0x01c10000, 0x0400760f, 0x00a58000, 0x0404622f,
0x00a50001, 0x0308e24f, 0x00658001, 0x020c626f,
0x00c10080, 0x0500ea0f, 0x02c41f00, 0x0000620f,
0x00c18000, 0xfe04c22f, 0x01e10001, 0x0008624f,
0x01a18001, 0x000c666f, 0x00a18081, 0xfe0ce66f,
0x00e10001, 0x7f08620f, 0x02048000, 0x03046a2f,
0x02c41f01, 0x06086a4f, 0x02c49f01, 0x060c6a6f,
0x02e00f80, 0xfe000220, 0x02c08f00, 0xfe040200,
0x02e08f01, 0xfe0c0240, 0x02c01f80, 0xfe080260,
0x8aa480ad, 0x2bfc5ca6, 0xb5e05b5b, 0xd48dc71c};
static const uint32_t cpVertexShaderRegs[] = {
0x00000108, 0x00000000, 0x00000004, 0x00000001,
0xff000201, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0x00000000, 0xfffffff8,
0x00000003, 0x00000001, 0x00000000, 0x00000002,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x00000000, 0x0000000e, 0x00000010};
static const uint32_t cpPixelShaderProgram[] = {
0x20000000, 0x000008a4, 0x04000000, 0x01004085,
0x23000000, 0x0000eca1, 0x9f000000, 0x0000e0a8,
0xd8000000, 0x000000a4, 0x07000000, 0x01004085,
0xd9000000, 0x000048a8, 0xec000000, 0x000000a4,
0x0a000000, 0x01004085, 0xed000000, 0x000050a8,
0x02010000, 0x000030a0, 0x00000000, 0x88062094,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0xfd001f80, 0x900c0060, 0x0000803f, 0x00000000,
0x03011f80, 0x8c210000, 0xfd001f00, 0x900c0000,
0xfd001f00, 0x900ca02f, 0x00000002, 0x80020040,
0x00048002, 0x80020060, 0xf8001f80, 0x900cc04f,
0x0000803f, 0x00000000, 0xfea81f00, 0x9000e00f,
0xfeac1f00, 0x9000e02f, 0xf8001f00, 0x900c804f,
0xf8001f80, 0x900ca06f, 0x00000040, 0x00000000,
0xfea01f00, 0x00280000, 0xfea41f00, 0x00280020,
0xfe041f00, 0x00280040, 0xfd041f80, 0x00280060,
0xaf67bb3e, 0x00000080, 0x7fc41f00, 0x00000000,
0x7fc01f80, 0x00000020, 0xfe041f00, 0x100ac00f,
0xfe001f80, 0x100ac02f, 0xfea01f00, 0x00280000,
0xfea41f00, 0x00280020, 0xfe041f00, 0x00280040,
0xfd041f00, 0x1028e06f, 0x7fc01f82, 0x00000000,
0x8c65583e, 0x00000080, 0x7ea41f00, 0x80000000,
0x7ea01f00, 0x80000020, 0xfee01f00, 0x10006040,
0x7fc48f82, 0x00000860, 0xa7c4623b, 0x00000000,
0xfea81f00, 0x1000e00f, 0x7fcc9f01, 0x10006020,
0xfe001f00, 0x000a0040, 0xfe041f00, 0x000a0060,
0xfea89f80, 0x10008040, 0x8c65583e, 0x3acd13bf,
0xfeb81f00, 0x7e04c20f, 0xfebc1f00, 0x7e00822f,
0x03c89f00, 0x80060040, 0xfea49f00, 0x1000e06f,
0xfea41f81, 0x10006060, 0x00809043, 0x8c65583e,
0x3acd13bf, 0x00000000, 0xfea81f00, 0xf880a30f,
0xfe001f00, 0x900ca02f, 0x7dc41f00, 0x1000e04f,
0xfe081f00, 0xfd80636f, 0x04081f80, 0x900c800f,
0x0000803f, 0x00000000, 0xfea81f00, 0xf900620f,
0xfea41f00, 0xf900622f, 0xfe0c1f00, 0x900ca04f,
0xfec00f00, 0x1000c46f, 0xfefc0f80, 0x10006000,
0x00000842, 0x00000000, 0xfeac1f00, 0xf900620f,
0x7fc81f00, 0x9000c02f, 0x7dc49f00, 0x9000e04f,
0x7df08f01, 0x10008060, 0x030c1f80, 0x900ca02f,
0x00000842, 0x00000000, 0xfea41f00, 0x80000000,
0x7ecc1f00, 0x9000e02f, 0x7e688000, 0x80000040,
0xfea81f00, 0x80000060, 0x7d6c8081, 0x80000000,
0xa7c4623b, 0x00000000, 0xfe001f00, 0x000a0000,
0xfe0c1f00, 0x000a0020, 0xfea41f00, 0x80000040,
0x03648000, 0xfe08626f, 0x7d648081, 0xff00420f,
0xa7c4623b, 0x00000000, 0xfeb01f00, 0x7e04620f,
0xfeb41f00, 0x7f08662f, 0x7c800001, 0xff006e4f,
0xfe081f00, 0x000a0060, 0x03680081, 0xfe0c4e0f,
0x00809043, 0x00000000, 0xfebc1f00, 0x7f04620f,
0x7cc41f00, 0x00000020, 0x7cc49f00, 0x1000e04f,
0xff901f00, 0x00000060, 0xfe981f80, 0x00000000,
0x00809043, 0x00000000, 0xfea81f00, 0xf900620f,
0x7cc41f00, 0x00000020, 0x00c09f00, 0x1000c04f,
0xfe0c1f00, 0x80010060, 0xff001f80, 0x80010000,
0x00000842, 0x00000000, 0xfea81f00, 0xf900620f,
0xfecc9f01, 0x80000020, 0x7fc81f00, 0x9000e04f,
0x7dc89f00, 0x1000c86f, 0xffe01f80, 0x80000000,
0x00000842, 0x00000000, 0xfeac1f00, 0xf900620f,
0x7ec81f00, 0x9000802f, 0xfec49f00, 0x9000a040,
0xfea89f00, 0x80000060, 0xffe01f80, 0x9000a060,
0x00000842, 0xa7c4623b, 0xfea41f00, 0x80000000,
0x7ecc1f00, 0x9000e02f, 0xfe0c1f00, 0x000a0040,
0x7c888081, 0x80000000, 0xa7c4623b, 0x00000000,
0xfe001f00, 0x000a0000, 0xfeb81f00, 0x7f08622f,
0xfea49f00, 0x80000040, 0x048c8081, 0xff00420f,
0x00809043, 0xa7c4623b, 0xfeb01f00, 0x7c04620f,
0x03600000, 0xff00622f, 0xfea49f00, 0x80000040,
0xfe081f80, 0x000a0060, 0x00809043, 0x0ccec73c,
0xfebc1f00, 0x7f040200, 0xfea09f00, 0x90000020,
0xfe941f00, 0x10000040, 0xfe081f80, 0x30080060,
0x00809043, 0x0ccec73c, 0x00041f00, 0x20080000,
0x00a01f00, 0x80000020, 0x002c1f02, 0x1000e04f,
0x00081f80, 0x80010060, 0x0ccec73c, 0x00000000,
0xfe201f02, 0x1000800f, 0xfec81f03, 0x80020020,
0xfe041f00, 0x20080040, 0xfe881f00, 0x00000060,
0xfecc9f81, 0x9000a06f, 0xfe0c1f00, 0x000a0000,
0xfe801f00, 0x00000020, 0xfec01f02, 0x80020040,
0xfe281f02, 0x1000c06f, 0xfe841f82, 0x1000804f,
0xfe041f00, 0x000a0000, 0x7fc81f02, 0x00000020,
0xfe8c1f00, 0x00000040, 0xfecc9f03, 0x80020060,
0xfe881f82, 0x1000a00f, 0x7cc01f02, 0x00000000,
0xfe8c1f02, 0x1000e02f, 0xfec49f00, 0x80000040,
0xfe081f00, 0x000a0060, 0x03c89f80, 0x9000e04f,
0x7ecc9f03, 0x00000000, 0xfec01f00, 0x80000020,
0x04c81f00, 0x80000040, 0x7c880f01, 0xfe086a6f,
0x7dac8f81, 0x9000800f, 0x7da00f00, 0xfe04620f,
0xfec01f00, 0x80000020, 0x03c01f00, 0x80000840,
0x03ac0f00, 0xfe08c66f, 0xfebc9f80, 0xfd00420f,
0xe07be53f, 0x5c8e5a3f, 0xfeb09f00, 0xfd00620f,
0x05e81f00, 0x9000f02f, 0x7fe48f00, 0xfe04624f,
0x04ec8f00, 0xfe08626f, 0x03840f81, 0x7f08a20f,
0xe07be53f, 0x5c8e5a3f, 0x7e0c1f00, 0x900ce00f,
0xfe0c1f00, 0x900c802f, 0x05cc1f00, 0x9000e84f,
0xfeb89f80, 0xfd00626f, 0xe07be53f, 0x5c8e5a3f,
0x7cc09f81, 0x80000020, 0x7fa40f00, 0x00280000,
0xfe848f00, 0x00280020, 0x7fe80f00, 0x00280440,
0xfd001f80, 0x00280060, 0x00000080, 0x00000000,
0xfdc01f80, 0xf800620f, 0x00000243, 0x00000000,
0xfea01f80, 0x90000060, 0x5555d53f, 0x00000000,
0x02011f80, 0x8c110000, 0x02448002, 0x80020000,
0xf8402000, 0x9006a02f, 0x02552081, 0x00000040,
0xfe301f00, 0x1000e06f, 0xfe081f80, 0x1033c02f,
0xfe4c2081, 0x80060040, 0xfee88f81, 0x0289e32f,
0x02c59f80, 0x80060000, 0xfee08f80, 0x0285636f,
0xfecc8f80, 0x80000000, 0xfe40a081, 0x80000060,
0x00cc9f81, 0x9000e04f, 0xfe281f00, 0x80060000,
0xf8c01f81, 0x9006c02f, 0xfee00f81, 0xfd80636f,
0x0000803f, 0x00000000, 0x7ec49f81, 0xf880e34f,
0xfe381f80, 0x00000000, 0x7de40f81, 0xfe800360,
0x00011f80, 0x8c100000, 0xf8001f00, 0x900ce00f,
0x00311f00, 0x1000e02f, 0x02a41f00, 0xf910624f,
0x02a01f00, 0xf910626f, 0x00011f80, 0x1033e04f,
0x00000040, 0x00000000, 0xfecc9f03, 0x80020000,
0xfec81f83, 0x80020060, 0x7fd49f01, 0x00000020,
0x7fd41f80, 0x00000040, 0xfe081f00, 0x80010000,
0xfe041f80, 0x80010060, 0xfee00f01, 0x80000000,
0xfeec0f81, 0x80000020, 0xfec01f00, 0x00280000,
0xfec49f00, 0x00280020, 0x7fe00f00, 0x00280040,
0xfd001f80, 0x00280060, 0x00000080, 0x00000000,
0xfe001f80, 0x00350000, 0x00ec1f82, 0x000c0260,
0x01011f00, 0x800c0000, 0x01051f00, 0x800c0020,
0x002c1f00, 0x80060040, 0xf8008001, 0x9006e06f,
0x01091f80, 0x800c0000, 0x01c01f00, 0x90000000,
0xfe088001, 0xfd80632f, 0x01e81f00, 0x90000040,
0x01c49f80, 0x90000020, 0x0000803f, 0x00000000,
0x7fcc9f80, 0xf880630f, 0xfe20a081, 0x80000000,
0x01cc1f80, 0x90000060, 0xc21e82a7, 0x62ccc547,
0x1708607c, 0x73ea57a6};
static const uint32_t cpPixelShaderRegs[] = {
0x00000106, 0x00000002, 0x14000003, 0x00000000,
0x00000003, 0x00000100, 0x00000101, 0x00000102,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x0000000f, 0x00000001, 0x00000010,
0x00000000};
ShaderFractalColor *ShaderFractalColor::shaderInstance = NULL;
ShaderFractalColor::ShaderFractalColor()
: vertexShader(cuAttributeCount) {
//! create pixel shader
pixelShader.setProgram(cpPixelShaderProgram, sizeof(cpPixelShaderProgram), cpPixelShaderRegs, sizeof(cpPixelShaderRegs));
blurLocation = 0;
colorIntensityLocation = 4;
fadeOutLocation = 8;
fractalLocation = 12;
pixelShader.addUniformVar((GX2UniformVar){
"unf_blur_border", GX2_SHADER_VAR_TYPE_FLOAT, 1, blurLocation, -1});
pixelShader.addUniformVar((GX2UniformVar){
"unf_color_intensity", GX2_SHADER_VAR_TYPE_FLOAT4, 1, colorIntensityLocation, -1});
pixelShader.addUniformVar((GX2UniformVar){
"unf_fade_out_alpha", GX2_SHADER_VAR_TYPE_FLOAT4, 1, fadeOutLocation, -1});
pixelShader.addUniformVar((GX2UniformVar){
"unf_fract_alpha", GX2_SHADER_VAR_TYPE_INT, 1, fractalLocation, -1});
//! create vertex shader
vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs));
modelMatrixLocation = 0;
projectionMatrixLocation = 16;
viewMatrixLocation = 32;
vertexShader.addUniformVar((GX2UniformVar){
"modelMatrix", GX2_SHADER_VAR_TYPE_FLOAT4X4, 1, modelMatrixLocation, -1});
vertexShader.addUniformVar((GX2UniformVar){
"projectionMatrix", GX2_SHADER_VAR_TYPE_FLOAT4X4, 1, projectionMatrixLocation, -1});
vertexShader.addUniformVar((GX2UniformVar){
"viewMatrix", GX2_SHADER_VAR_TYPE_FLOAT4X4, 1, viewMatrixLocation, -1});
positionLocation = 0;
colorLocation = 1;
texCoordLocation = 2;
vertexShader.addAttribVar((GX2AttribVar){
"attr_colors", GX2_SHADER_VAR_TYPE_FLOAT4, 0, colorLocation});
vertexShader.addAttribVar((GX2AttribVar){
"attr_position", GX2_SHADER_VAR_TYPE_FLOAT3, 0, positionLocation});
vertexShader.addAttribVar((GX2AttribVar){
"attr_texture_coord", GX2_SHADER_VAR_TYPE_FLOAT2, 0, texCoordLocation});
//! setup attribute streams
GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32_32);
GX2InitAttribStream(vertexShader.getAttributeBuffer(1), texCoordLocation, 1, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32);
GX2InitAttribStream(vertexShader.getAttributeBuffer(2), colorLocation, 2, 0, GX2_ATTRIB_FORMAT_UNORM_8_8_8_8);
//! create fetch shader
fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount());
//! initialize default quad texture vertexes as those are very commonly used
//! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000
posVtxs = (float *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciPositionVtxsSize);
texCoords = (float *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciTexCoordsVtxsSize);
colorVtxs = (uint8_t *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciColorVtxsSize);
//! position vertex structure and texture coordinate vertex structure
int32_t i = 0;
posVtxs[i++] = -1.0f;
posVtxs[i++] = -1.0f;
posVtxs[i++] = 0.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = -1.0f;
posVtxs[i++] = 0.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = 0.0f;
posVtxs[i++] = -1.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = 0.0f;
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, posVtxs, ciPositionVtxsSize);
i = 0;
texCoords[i++] = 0.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 0.0f;
texCoords[i++] = 0.0f;
texCoords[i++] = 0.0f;
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, texCoords, ciTexCoordsVtxsSize);
for (i = 0; i < (int32_t) ciColorVtxsSize; i++) {
colorVtxs[i] = 0xff;
}
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, colorVtxs, ciColorVtxsSize);
}
ShaderFractalColor::~ShaderFractalColor() {
if (posVtxs) {
free(posVtxs);
posVtxs = NULL;
}
if (texCoords) {
free(texCoords);
texCoords = NULL;
}
if (colorVtxs) {
free(colorVtxs);
colorVtxs = NULL;
}
delete fetchShader;
fetchShader = NULL;
}

View File

@ -0,0 +1,120 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef SHADER_FRACTAL_COLOR_H_
#define SHADER_FRACTAL_COLOR_H_
#include <video/shaders/FetchShader.h>
#include <video/shaders/PixelShader.h>
#include <video/shaders/VertexShader.h>
class ShaderFractalColor : public Shader {
private:
ShaderFractalColor();
virtual ~ShaderFractalColor();
static ShaderFractalColor *shaderInstance;
static const unsigned char cuAttributeCount = 3;
static const uint32_t ciPositionVtxsSize = 4 * cuVertexAttrSize;
static const uint32_t ciTexCoordsVtxsSize = 4 * cuTexCoordAttrSize;
static const uint32_t ciColorVtxsSize = 4 * cuColorAttrSize;
FetchShader *fetchShader;
VertexShader vertexShader;
PixelShader pixelShader;
float *posVtxs;
float *texCoords;
uint8_t *colorVtxs;
uint32_t modelMatrixLocation;
uint32_t viewMatrixLocation;
uint32_t projectionMatrixLocation;
uint32_t positionLocation;
uint32_t colorLocation;
uint32_t texCoordLocation;
uint32_t blurLocation;
uint32_t colorIntensityLocation;
uint32_t fadeOutLocation;
uint32_t fractalLocation;
public:
static ShaderFractalColor *instance() {
if (!shaderInstance) {
shaderInstance = new ShaderFractalColor();
}
return shaderInstance;
}
static void destroyInstance() {
if (shaderInstance) {
delete shaderInstance;
shaderInstance = NULL;
}
}
void setShaders(void) const {
fetchShader->setShader();
vertexShader.setShader();
pixelShader.setShader();
}
void setAttributeBuffer(const uint32_t &vtxCount = 0, const float *posVtxs_in = NULL, const float *texCoords_in = NULL, const uint8_t *colorVtxs_in = NULL) const {
if (posVtxs_in && texCoords_in && vtxCount) {
VertexShader::setAttributeBuffer(0, vtxCount * cuVertexAttrSize, cuVertexAttrSize, posVtxs_in);
VertexShader::setAttributeBuffer(1, vtxCount * cuTexCoordAttrSize, cuTexCoordAttrSize, texCoords_in);
VertexShader::setAttributeBuffer(2, vtxCount * cuColorAttrSize, cuColorAttrSize, colorVtxs_in);
} else {
//! use default quad vertex and texture coordinates if nothing is passed
VertexShader::setAttributeBuffer(0, ciPositionVtxsSize, cuVertexAttrSize, posVtxs);
VertexShader::setAttributeBuffer(1, ciTexCoordsVtxsSize, cuTexCoordAttrSize, texCoords);
VertexShader::setAttributeBuffer(2, ciColorVtxsSize, cuColorAttrSize, colorVtxs);
}
}
void setProjectionMtx(const glm::mat4 &mtx) {
VertexShader::setUniformReg(projectionMatrixLocation, 16, &mtx[0][0]);
}
void setViewMtx(const glm::mat4 &mtx) {
VertexShader::setUniformReg(viewMatrixLocation, 16, &mtx[0][0]);
}
void setModelViewMtx(const glm::mat4 &mtx) {
VertexShader::setUniformReg(modelMatrixLocation, 16, &mtx[0][0]);
}
void setBlurBorder(const float &blurBorderSize) {
PixelShader::setUniformReg(blurLocation, 4, &blurBorderSize);
}
void setColorIntensity(const glm::vec4 &vec) {
PixelShader::setUniformReg(colorIntensityLocation, 4, &vec[0]);
}
void setAlphaFadeOut(const glm::vec4 &vec) {
PixelShader::setUniformReg(fadeOutLocation, 4, &vec[0]);
}
void setFractalColor(const int &fractalColorEnable) {
PixelShader::setUniformReg(fractalLocation, 4, &fractalColorEnable);
}
};
#endif // SHADER_FRACTAL_COLOR_H_

View File

@ -0,0 +1,281 @@
/****************************************************************************
* 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 <video/shaders/Texture2DShader.h>
#include <malloc.h>
#include <string.h>
static const uint32_t cpVertexShaderProgram[] = {
0x00000000, 0x00008009, 0x20000000, 0x000080a0,
0x3c200100, 0x88060094, 0x00400000, 0x88042014,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x02290001, 0x80000000, 0x02041f00, 0x900c0020,
0x00a11f00, 0xfc00624f, 0xfd041f00, 0x900c4060,
0x02001f80, 0x900c0000, 0x83f9223e, 0x0000803f,
0xfe081f00, 0x00080020, 0xfe202081, 0x10004040,
0xfea49f80, 0xfd00620f, 0xdb0f49c0, 0xdb0fc940,
0xfea01f80, 0x9000e06f, 0x83f9223e, 0x00000000,
0xfe0c1f80, 0x00370000, 0xffa01f00, 0x80000040,
0xff101f00, 0x800c0060, 0x7f0c1f80, 0x80370040,
0x0000103f, 0x00000000, 0xffa01f00, 0x80000000,
0xff001f00, 0x800c0020, 0x02c51f01, 0x80000040,
0xfeac9f80, 0x80000060, 0x0000103f, 0x398ee33f,
0xfea01f00, 0x80000000, 0x02c19f01, 0x9000e02f,
0x01c41f01, 0x9000e04f, 0x02c59f80, 0x80000060,
0x398ee33f, 0x00000000, 0x01c49f01, 0x80000020,
0x02c11f80, 0x80000040, 0x01e08f00, 0xfe04624f,
0x01c01f81, 0x7f08626f, 0xfe2c2000, 0x10004000,
0xfe28a080, 0x10004020, 0xeb825790, 0xb6f711be,
0x7c0e2df2, 0x81173cfa};
static const uint32_t cpVertexShaderRegs[] = {
0x00000103, 0x00000000, 0x00000000, 0x00000001,
0xffffff00, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0x00000000, 0xfffffffc,
0x00000002, 0x00000000, 0x00000001, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
0x000000ff, 0x00000000, 0x0000000e, 0x00000010};
static const uint32_t cPixelShaderProgram[] = {
0x20000000, 0x00000ca4, 0x0b000000, 0x00000085,
0x24000000, 0x000050a0, 0xb0000000, 0x000cc080,
0x39000000, 0x00005ca0, 0xb8000000, 0x000cc080,
0x51000000, 0x000078a0, 0xc0000000, 0x000cc080,
0x70000000, 0x000064a0, 0xc8000000, 0x0008c080,
0x8a000000, 0x00005ca0, 0x0e000000, 0x01008086,
0xce000000, 0x0000c080, 0xa2000000, 0x00000ca8,
0x00800000, 0x88062094, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00051f00, 0x80060000, 0x00011f80, 0x80060040,
0xfec81f80, 0xfb802320, 0x01041f80, 0x8c220000,
0x00a41f00, 0xfc10620f, 0x010d1f00, 0x900c0021,
0x00091f00, 0x80060040, 0x00a01f80, 0xfc10626f,
0x00000040, 0x00000000, 0xfe080000, 0xfe8cc300,
0xfe088080, 0xfe80c320, 0x00a11f00, 0xfe000200,
0x00a51f00, 0xfe040220, 0x00a19f00, 0xfe000240,
0x00a59f00, 0xfe040260, 0x00a11f81, 0xfe002600,
0x4260e5bc, 0xa69bc4bc, 0x0ad7a3bc, 0x00000000,
0x00a11f00, 0x06004200, 0x00a59f00, 0x06042220,
0x00a51f00, 0x06044240, 0x00a11f01, 0x06008260,
0x00a51f81, 0x06048620, 0x6f1283bc, 0x0ad7a3bc,
0xa69b44bc, 0x00000000, 0x00a41f00, 0x80000000,
0x00a01f00, 0x80000020, 0x00ac1f00, 0x80000040,
0x00a81f00, 0x80000060, 0x00a19f80, 0x06000600,
0xcac3123c, 0x6f1203bc, 0x03a41f00, 0xfe00620f,
0x03a01f00, 0xfe04622f, 0x03ac1f00, 0xfe08624f,
0x03a81f00, 0xfe0c626f, 0x00a59f80, 0x06040620,
0xcc28913b, 0x6f1203bc, 0x01a41f00, 0xfe00620f,
0x01a01f00, 0xfe04622f, 0x01ac1f00, 0xfe08624f,
0x01a81f00, 0xfe0c626f, 0x00a19f80, 0x06002600,
0xe8eab03c, 0x6f1283bb, 0x02ac1f00, 0xfe084200,
0x02a81f00, 0xfe0c4220, 0x02a41f00, 0xfe004240,
0x02a01f00, 0xfe044260, 0x00a59f80, 0x06042620,
0x92bb353d, 0x6f1283bb, 0x04a81f00, 0x0204620f,
0x04ac1f00, 0x0200662f, 0x04a41f00, 0x0208624f,
0x04a01f00, 0x020c626f, 0x00a19f80, 0x06004600,
0xc4139f3d, 0x6f12833b, 0x00a41f00, 0xfe08620f,
0x00a01f00, 0xfe0c622f, 0x00ac1f00, 0xfe04624f,
0x00a81f00, 0xfe00626f, 0x00a59f80, 0x06044620,
0xb950ed3d, 0x6f12833b, 0x01a41f00, 0xfe00620f,
0x01a01f00, 0xfe04622f, 0x01ac1f00, 0xfe08624f,
0x01a81f00, 0xfe0c626f, 0x00a19f80, 0x06002600,
0xecd7163e, 0x6f12033c, 0x03a41f00, 0xfe000200,
0x03a01f00, 0xfe040220, 0x03ac1f00, 0xfe082240,
0x03a81f00, 0xfe0c2260, 0x00a59f80, 0x06042620,
0x2168233e, 0x6f12033c, 0x00a11f00, 0x06006200,
0x00a51f00, 0x06046220, 0x00a19f00, 0x06006240,
0x00a59f00, 0x06046260, 0x00a11f81, 0x0600e600,
0xa69b443c, 0x6f12833c, 0x0ad7a33c, 0x00000000,
0x02ac1f00, 0x0108620f, 0x02a81f00, 0x010c622f,
0x02a41f00, 0x0000624f, 0x02a01f00, 0x0004666f,
0x00a59f80, 0x0604e620, 0xecd7163e, 0x0ad7a33c,
0x04a81f00, 0xfe04620f, 0x04ac1f00, 0xfe00622f,
0x04a41f00, 0xfe08624f, 0x04a01f00, 0xfe0c626f,
0x00a19f80, 0x06008600, 0xb950ed3d, 0xa69bc43c,
0x05a41f00, 0xfe08620f, 0x05a01f00, 0xfe0c622f,
0x05ac1f00, 0xfe04624f, 0x05a81f00, 0xfe00626f,
0x00a59f80, 0x06048620, 0xc4139f3d, 0xa69bc43c,
0x03a41f00, 0xfe00a200, 0x03a01f00, 0xfe04a220,
0x03ac1f00, 0xfe086240, 0x03a81f00, 0xfe0c6260,
0x00a19f80, 0x06006600, 0x92bb353d, 0x4260e53c,
0x00a51f80, 0x06046220, 0x4260e53c, 0x00000000,
0x07ac1f00, 0x0308620f, 0x07a81f00, 0x030c622f,
0x07a41f00, 0x0500624f, 0x07a01f80, 0x0504626f,
0xe8eab03c, 0x00000000, 0x04a81f00, 0xfe04620f,
0x04ac1f00, 0xfe00622f, 0x04a41f00, 0xfe08624f,
0x04a01f80, 0xfe0c626f, 0xcac3123c, 0x00000000,
0x06a41f00, 0xfe08620f, 0x06a01f00, 0xfe0c622f,
0x06ac1f00, 0xfe04624f, 0x06a81f80, 0xfe00626f,
0xcc28913b, 0x00000000, 0xfe20a000, 0x9000e00f,
0xfe242000, 0x9000e02f, 0xfe28a001, 0x9000e04f,
0xfe2c2081, 0x9000e06f, 0xfe28a081, 0x80060020,
0xfee48f00, 0x7f842300, 0xfee40f00, 0x7f802320,
0xfee48f01, 0x7f8c2340, 0xfee40f81, 0x08842b60,
0x00202000, 0x90002000, 0x0024a000, 0x90002020,
0x00282001, 0x90002040, 0x002ca081, 0x90002060,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x10000000, 0x03100df0, 0x00008010, 0xecdfea0d,
0x10000000, 0x00100df0, 0x0000a051, 0xecdfea0d,
0x10000100, 0x01100df0, 0x00008010, 0xecdfea0d,
0x10000200, 0x02100df0, 0x00000011, 0xecdfea0d,
0x10000400, 0x04100df0, 0x0000b070, 0xecdfea0d,
0x10000000, 0x00100df0, 0x00008010, 0xecdfea0d,
0x10000100, 0x01100df0, 0x00008010, 0xecdfea0d,
0x10000600, 0x03100df0, 0x00008010, 0xecdfea0d,
0x10000200, 0x02100df0, 0x00008010, 0xecdfea0d,
0x10000100, 0x04100df0, 0x00008010, 0xecdfea0d,
0x10000300, 0x05100df0, 0x00008010, 0xecdfea0d,
0x10000300, 0x03100df0, 0x0000a051, 0xecdfea0d,
0x10000700, 0x07100df0, 0x00008010, 0xecdfea0d,
0x10000400, 0x04100df0, 0x00008010, 0xecdfea0d,
0x10000300, 0x06100df0, 0x00008010, 0xecdfea0d,
0x10000000, 0x00100df0, 0x00008010, 0xecdfea0d,
0xc8581837, 0x22740275, 0x281eddcc, 0xfa8b9b65};
static const uint32_t cPixelShaderRegs[] = {
0x00000109, 0x00000002, 0x14000001, 0x00000000,
0x00000001, 0x00000100, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x0000000f, 0x00000001, 0x00000010,
0x00000000};
Texture2DShader *Texture2DShader::shaderInstance = NULL;
Texture2DShader::Texture2DShader()
: vertexShader(cuAttributeCount) {
//! create pixel shader
pixelShader.setProgram(cPixelShaderProgram, sizeof(cPixelShaderProgram), cPixelShaderRegs, sizeof(cPixelShaderRegs));
blurLocation = 0;
colorIntensityLocation = 4;
pixelShader.addUniformVar((GX2UniformVar){
"unf_blur_texture_direction", GX2_SHADER_VAR_TYPE_FLOAT3, 1, blurLocation, -1});
pixelShader.addUniformVar((GX2UniformVar){
"unf_color_intensity", GX2_SHADER_VAR_TYPE_FLOAT4, 1, colorIntensityLocation, -1});
samplerLocation = 0;
pixelShader.addSamplerVar((GX2SamplerVar){
"sampl_texture", GX2_SAMPLER_VAR_TYPE_SAMPLER_2D, samplerLocation});
//! create vertex shader
vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs));
angleLocation = 0;
offsetLocation = 4;
scaleLocation = 8;
vertexShader.addUniformVar((GX2UniformVar){
"unf_angle", GX2_SHADER_VAR_TYPE_FLOAT, 1, angleLocation, -1});
vertexShader.addUniformVar((GX2UniformVar){
"unf_offset", GX2_SHADER_VAR_TYPE_FLOAT3, 1, offsetLocation, -1});
vertexShader.addUniformVar((GX2UniformVar){
"unf_scale", GX2_SHADER_VAR_TYPE_FLOAT3, 1, scaleLocation, -1});
positionLocation = 0;
texCoordLocation = 1;
vertexShader.addAttribVar((GX2AttribVar){
"attr_position", GX2_SHADER_VAR_TYPE_FLOAT3, 0, positionLocation});
vertexShader.addAttribVar((GX2AttribVar){
"attr_texture_coord", GX2_SHADER_VAR_TYPE_FLOAT2, 0, texCoordLocation});
//! setup attribute streams
GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32_32);
GX2InitAttribStream(vertexShader.getAttributeBuffer(1), texCoordLocation, 1, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32);
//! create fetch shader
fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount());
//! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000
posVtxs = (float *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciPositionVtxsSize);
texCoords = (float *) memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciTexCoordsVtxsSize);
//! defaults for normal square
//! position vertex structure and texture coordinate vertex structure
int32_t i = 0;
posVtxs[i++] = -1.0f;
posVtxs[i++] = -1.0f;
posVtxs[i++] = 0.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = -1.0f;
posVtxs[i++] = 0.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = 0.0f;
posVtxs[i++] = -1.0f;
posVtxs[i++] = 1.0f;
posVtxs[i++] = 0.0f;
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, posVtxs, ciPositionVtxsSize);
i = 0;
texCoords[i++] = 0.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 1.0f;
texCoords[i++] = 0.0f;
texCoords[i++] = 0.0f;
texCoords[i++] = 0.0f;
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_ATTRIBUTE_BUFFER, texCoords, ciTexCoordsVtxsSize);
}
Texture2DShader::~Texture2DShader() {
if (posVtxs) {
free(posVtxs);
posVtxs = NULL;
}
if (texCoords) {
free(texCoords);
texCoords = NULL;
}
delete fetchShader;
fetchShader = NULL;
}

View File

@ -0,0 +1,110 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef __TEXTURE_2D_SHADER_H_
#define __TEXTURE_2D_SHADER_H_
#include <video/shaders/FetchShader.h>
#include <video/shaders/PixelShader.h>
#include <video/shaders/VertexShader.h>
class Texture2DShader : public Shader {
private:
Texture2DShader();
virtual ~Texture2DShader();
static const uint32_t cuAttributeCount = 2;
static const uint32_t ciPositionVtxsSize = 4 * cuVertexAttrSize;
static const uint32_t ciTexCoordsVtxsSize = 4 * cuTexCoordAttrSize;
static Texture2DShader *shaderInstance;
FetchShader *fetchShader;
VertexShader vertexShader;
PixelShader pixelShader;
float *posVtxs;
float *texCoords;
uint32_t angleLocation;
uint32_t offsetLocation;
uint32_t scaleLocation;
uint32_t colorIntensityLocation;
uint32_t blurLocation;
uint32_t samplerLocation;
uint32_t positionLocation;
uint32_t texCoordLocation;
public:
static Texture2DShader *instance() {
if (!shaderInstance) {
shaderInstance = new Texture2DShader();
}
return shaderInstance;
}
static void destroyInstance() {
if (shaderInstance) {
delete shaderInstance;
shaderInstance = NULL;
}
}
void setShaders(void) const {
fetchShader->setShader();
vertexShader.setShader();
pixelShader.setShader();
}
void setAttributeBuffer(const float *texCoords_in = NULL, const float *posVtxs_in = NULL, const uint32_t &vtxCount = 0) const {
if (posVtxs_in && texCoords_in && vtxCount) {
VertexShader::setAttributeBuffer(0, vtxCount * cuVertexAttrSize, cuVertexAttrSize, posVtxs_in);
VertexShader::setAttributeBuffer(1, vtxCount * cuTexCoordAttrSize, cuTexCoordAttrSize, texCoords_in);
} else {
VertexShader::setAttributeBuffer(0, ciPositionVtxsSize, cuVertexAttrSize, posVtxs);
VertexShader::setAttributeBuffer(1, ciTexCoordsVtxsSize, cuTexCoordAttrSize, texCoords);
}
}
void setAngle(const float &val) {
VertexShader::setUniformReg(angleLocation, 4, &val);
}
void setOffset(const glm::vec3 &vec) {
VertexShader::setUniformReg(offsetLocation, 4, &vec[0]);
}
void setScale(const glm::vec3 &vec) {
VertexShader::setUniformReg(scaleLocation, 4, &vec[0]);
}
void setColorIntensity(const glm::vec4 &vec) {
PixelShader::setUniformReg(colorIntensityLocation, 4, &vec[0]);
}
void setBlurring(const glm::vec3 &vec) {
PixelShader::setUniformReg(blurLocation, 4, &vec[0]);
}
void setTextureAndSampler(const GX2Texture *texture, const GX2Sampler *sampler) const {
GX2SetPixelTexture((GX2Texture *) texture, samplerLocation);
GX2SetPixelSampler((GX2Sampler *) sampler, samplerLocation);
}
};
#endif // __TEXTURE_2D_SHADER_H_

View File

@ -0,0 +1,181 @@
/****************************************************************************
* 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/>.
****************************************************************************/
#ifndef VERTEX_SHADER_H
#define VERTEX_SHADER_H
#include <gui/gx2_ext.h>
#include <video/shaders/Shader.h>
#include <string.h>
class VertexShader : public Shader {
public:
VertexShader(uint32_t numAttr)
: attributesCount(numAttr), attributes(new GX2AttribStream[attributesCount]), vertexShader((GX2VertexShader *) memalign(0x40, sizeof(GX2VertexShader))) {
if (vertexShader) {
memset(vertexShader, 0, sizeof(GX2VertexShader));
vertexShader->mode = GX2_SHADER_MODE_UNIFORM_REGISTER;
}
}
virtual ~VertexShader() {
delete[] attributes;
if (vertexShader) {
if (vertexShader->program) {
free(vertexShader->program);
}
for (uint32_t i = 0; i < vertexShader->uniformBlockCount; i++) {
free((void *) vertexShader->uniformBlocks[i].name);
}
if (vertexShader->uniformBlocks) {
free((void *) vertexShader->uniformBlocks);
}
for (uint32_t i = 0; i < vertexShader->uniformVarCount; i++) {
free((void *) vertexShader->uniformVars[i].name);
}
if (vertexShader->uniformVars) {
free((void *) vertexShader->uniformVars);
}
if (vertexShader->initialValues) {
free((void *) vertexShader->initialValues);
}
for (uint32_t i = 0; i < vertexShader->samplerVarCount; i++) {
free((void *) vertexShader->samplerVars[i].name);
}
if (vertexShader->samplerVars) {
free((void *) vertexShader->samplerVars);
}
for (uint32_t i = 0; i < vertexShader->attribVarCount; i++) {
free((void *) vertexShader->attribVars[i].name);
}
if (vertexShader->attribVars) {
free((void *) vertexShader->attribVars);
}
if (vertexShader->loopVars) {
free((void *) vertexShader->loopVars);
}
free(vertexShader);
}
}
void setProgram(const uint32_t *program, const uint32_t &programSize, const uint32_t *regs, const uint32_t &regsSize) {
if (!vertexShader) {
return;
}
//! this must be moved into an area where the graphic engine has access to and must be aligned to 0x100
vertexShader->size = programSize;
vertexShader->program = (uint8_t *) memalign(GX2_SHADER_PROGRAM_ALIGNMENT, vertexShader->size);
if (vertexShader->program) {
memcpy(vertexShader->program, program, vertexShader->size);
GX2Invalidate(GX2_INVALIDATE_MODE_CPU_SHADER, vertexShader->program, vertexShader->size);
}
memcpy(&vertexShader->regs, regs, regsSize);
}
void addUniformVar(const GX2UniformVar &var) {
if (!vertexShader) {
return;
}
uint32_t idx = vertexShader->uniformVarCount;
GX2UniformVar *newVar = (GX2UniformVar *) malloc((vertexShader->uniformVarCount + 1) * sizeof(GX2UniformVar));
if (newVar) {
if (vertexShader->uniformVarCount > 0) {
memcpy(newVar, vertexShader->uniformVars, vertexShader->uniformVarCount * sizeof(GX2UniformVar));
free(vertexShader->uniformVars);
}
vertexShader->uniformVars = newVar;
memcpy(vertexShader->uniformVars + idx, &var, sizeof(GX2UniformVar));
vertexShader->uniformVars[idx].name = (char *) malloc(strlen(var.name) + 1);
strcpy((char *) vertexShader->uniformVars[idx].name, var.name);
vertexShader->uniformVarCount++;
}
}
void addAttribVar(const GX2AttribVar &var) {
if (!vertexShader) {
return;
}
uint32_t idx = vertexShader->attribVarCount;
GX2AttribVar *newVar = (GX2AttribVar *) malloc((vertexShader->attribVarCount + 1) * sizeof(GX2AttribVar));
if (newVar) {
if (vertexShader->attribVarCount > 0) {
memcpy(newVar, vertexShader->attribVars, vertexShader->attribVarCount * sizeof(GX2AttribVar));
free(vertexShader->attribVars);
}
vertexShader->attribVars = newVar;
memcpy(vertexShader->attribVars + idx, &var, sizeof(GX2AttribVar));
vertexShader->attribVars[idx].name = (char *) malloc(strlen(var.name) + 1);
strcpy((char *) vertexShader->attribVars[idx].name, var.name);
vertexShader->attribVarCount++;
}
}
static inline void setAttributeBuffer(uint32_t bufferIdx, uint32_t bufferSize, uint32_t stride, const void *buffer) {
GX2SetAttribBuffer(bufferIdx, bufferSize, stride, (void *) buffer);
}
GX2VertexShader *getVertexShader() const {
return vertexShader;
}
void setShader(void) const {
GX2SetVertexShader(vertexShader);
}
GX2AttribStream *getAttributeBuffer(uint32_t idx = 0) const {
if (idx >= attributesCount) {
return NULL;
}
return &attributes[idx];
}
uint32_t getAttributesCount() const {
return attributesCount;
}
static void setUniformReg(uint32_t location, uint32_t size, const void *reg) {
GX2SetVertexUniformReg(location, size, (uint32_t *) reg);
}
protected:
uint32_t attributesCount;
GX2AttribStream *attributes;
GX2VertexShader *vertexShader;
};
#endif // VERTEX_SHADER_H