diff --git a/README.md b/README.md index 22801e8..8c9e7e0 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ make |newlib_heapsize_ctrl|VSDK00021|newlib's global heap size control example.| |json|VSDK00022|json parsing example.| |net_https|VSDK00023|https access example.| +|message_box|VSDK00024|Example on how to create a spawn a message box.| |soloud|VSDK01337|Plays an audio file and Text To Speech.| |common|-|Common functions for samples.| |prx_simple|-|Minimal sample prx module.| diff --git a/message_box/Makefile b/message_box/Makefile new file mode 100644 index 0000000..dce3581 --- /dev/null +++ b/message_box/Makefile @@ -0,0 +1,59 @@ +# You should only use Makefile-based build if you know what you're doing. +# For most vitasdk projects, CMake is a better choice. See CMakeLists.txt for an example. + +PHONY := all package clean +rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d)) + +CC := arm-vita-eabi-gcc +CXX := arm-vita-eabi-g++ +STRIP := arm-vita-eabi-strip + +PROJECT_TITLE := message_box_sample +PROJECT_TITLEID := VSDK00024 + +PROJECT := message_box_sample +CFLAGS += -Wl,-q -I../common +CXXFLAGS += -Wl,-q -std=c++11 -I../common + +SRC_C :=$(call rwildcard, src/, *.c) +SRC_CPP :=$(call rwildcard, src/, *.cpp) + +OBJ_DIRS := $(addprefix out/, $(dir $(SRC_C:src/%.c=%.o))) $(addprefix out/, $(dir $(SRC_CPP:src/%.cpp=%.o))) +OBJS := $(addprefix out/, $(SRC_C:src/%.c=%.o)) $(addprefix out/, $(SRC_CPP:src/%.cpp=%.o)) + +# Needed by psvDebugScreenPrintf +LIBS += -lSceSysmodule_stub -lSceCommonDialog_stub -lSceAppUtil_stub -lSceGxm_stub -lSceDisplay_stub + +all: package + +package: $(PROJECT).vpk + +$(PROJECT).vpk: eboot.bin param.sfo + vita-pack-vpk -s param.sfo -b eboot.bin \ + $(PROJECT).vpk + +eboot.bin: $(PROJECT).velf + vita-make-fself $(PROJECT).velf eboot.bin + +param.sfo: + vita-mksfoex -s TITLE_ID="$(PROJECT_TITLEID)" "$(PROJECT_TITLE)" param.sfo + +$(PROJECT).velf: $(PROJECT).elf + $(STRIP) -g $< + vita-elf-create $< $@ + +$(PROJECT).elf: $(OBJS) + $(CXX) $(CXXFLAGS) $^ $(LIBS) -o $@ + +$(OBJ_DIRS): + mkdir -p $@ + +out/%.o : src/%.cpp | $(OBJ_DIRS) + arm-vita-eabi-g++ -c $(CXXFLAGS) -o $@ $< + +out/%.o : src/%.c | $(OBJ_DIRS) + arm-vita-eabi-gcc -c $(CFLAGS) -o $@ $< + +clean: + rm -f $(PROJECT).velf $(PROJECT).elf $(PROJECT).vpk param.sfo eboot.bin $(OBJS) + rm -r $(abspath $(OBJ_DIRS)) diff --git a/message_box/src/gxm_base.c b/message_box/src/gxm_base.c new file mode 100644 index 0000000..72370f2 --- /dev/null +++ b/message_box/src/gxm_base.c @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include +#include +#include + +#define VITA_GXM_SCREEN_WIDTH 960 +#define VITA_GXM_SCREEN_HEIGHT 544 +#define VITA_GXM_SCREEN_STRIDE 960 +#define VITA_GXM_BUFFERS 3 +#define VITA_GXM_PENDING_SWAPS 1 + + +#define VITA_GXM_COLOR_FORMAT SCE_GXM_COLOR_FORMAT_A8B8G8R8 +#define VITA_GXM_PIXEL_FORMAT SCE_DISPLAY_PIXELFORMAT_A8B8G8R8 + +#define zero_memory(v) memset(&v, 0, sizeof(v)) +#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) + + +static unsigned int back_buffer_index_for_common_dialog = 0; +static unsigned int front_buffer_index_for_common_dialog = 0; + +typedef struct +{ + void *address; + unsigned char wait_vblank; +} VITA_GXM_DisplayData; + + +struct +{ + VITA_GXM_DisplayData displayData; + SceGxmSyncObject *sync; + SceGxmColorSurface surf; + SceUID uid; +} buffer_for_common_dialog[VITA_GXM_BUFFERS]; + +void *vita_mem_alloc(unsigned int type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid) +{ + void *mem; + + if (type == SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW) { + size = ALIGN(size, 256 * 1024); + } else if (type == SCE_KERNEL_MEMBLOCK_TYPE_USER_MAIN_PHYCONT_NC_RW) { + size = ALIGN(size, 1024 * 1024); + } else { + size = ALIGN(size, 4 * 1024); + } + + *uid = sceKernelAllocMemBlock("gpu_mem", type, size, NULL); + + if (*uid < 0) { + return NULL; + } + + if (sceKernelGetMemBlockBase(*uid, &mem) < 0) { + return NULL; + } + + if (sceGxmMapMemory(mem, size, attribs) < 0) { + return NULL; + } + + return mem; +} + +void vita_mem_free(SceUID uid) +{ + void *mem = NULL; + if (sceKernelGetMemBlockBase(uid, &mem) < 0) { + return; + } + sceGxmUnmapMemory(mem); + sceKernelFreeMemBlock(uid); +} + + +void gxm_minimal_term_for_common_dialog(void) +{ + sceGxmTerminate(); +} + +static void display_callback(const void *callback_data) +{ + SceDisplayFrameBuf framebuf; + const VITA_GXM_DisplayData *display_data = (const VITA_GXM_DisplayData *)callback_data; + + memset(&framebuf, 0x00, sizeof(SceDisplayFrameBuf)); + framebuf.size = sizeof(SceDisplayFrameBuf); + framebuf.base = display_data->address; + framebuf.pitch = VITA_GXM_SCREEN_STRIDE; + framebuf.pixelformat = VITA_GXM_PIXEL_FORMAT; + framebuf.width = VITA_GXM_SCREEN_WIDTH; + framebuf.height = VITA_GXM_SCREEN_HEIGHT; + sceDisplaySetFrameBuf(&framebuf, SCE_DISPLAY_SETBUF_NEXTFRAME); + + if (display_data->wait_vblank) { + sceDisplayWaitVblankStart(); + } +} + + + +void gxm_minimal_init_for_common_dialog(void) +{ + SceGxmInitializeParams initializeParams; + zero_memory(initializeParams); + initializeParams.flags = 0; + initializeParams.displayQueueMaxPendingCount = VITA_GXM_PENDING_SWAPS; + initializeParams.displayQueueCallback = display_callback; + initializeParams.displayQueueCallbackDataSize = sizeof(VITA_GXM_DisplayData); + initializeParams.parameterBufferSize = SCE_GXM_DEFAULT_PARAMETER_BUFFER_SIZE; + sceGxmInitialize(&initializeParams); +} + + +void gxm_init_for_common_dialog(void) +{ + for (int i = 0; i < VITA_GXM_BUFFERS; i += 1) { + buffer_for_common_dialog[i].displayData.wait_vblank = true; + buffer_for_common_dialog[i].displayData.address = vita_mem_alloc( + SCE_KERNEL_MEMBLOCK_TYPE_USER_MAIN_PHYCONT_NC_RW, + 4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT, + SCE_GXM_COLOR_SURFACE_ALIGNMENT, + SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, + &buffer_for_common_dialog[i].uid); + sceGxmColorSurfaceInit( + &buffer_for_common_dialog[i].surf, + VITA_GXM_PIXEL_FORMAT, + SCE_GXM_COLOR_SURFACE_LINEAR, + SCE_GXM_COLOR_SURFACE_SCALE_NONE, + SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT, + VITA_GXM_SCREEN_WIDTH, + VITA_GXM_SCREEN_HEIGHT, + VITA_GXM_SCREEN_STRIDE, + buffer_for_common_dialog[i].displayData.address); + sceGxmSyncObjectCreate(&buffer_for_common_dialog[i].sync); + } + sceGxmDisplayQueueFinish(); +} + +void gxm_swap_for_common_dialog(void) +{ + SceCommonDialogUpdateParam updateParam; + zero_memory(updateParam); + updateParam.renderTarget.colorFormat = VITA_GXM_PIXEL_FORMAT; + updateParam.renderTarget.surfaceType = SCE_GXM_COLOR_SURFACE_LINEAR; + updateParam.renderTarget.width = VITA_GXM_SCREEN_WIDTH; + updateParam.renderTarget.height = VITA_GXM_SCREEN_HEIGHT; + updateParam.renderTarget.strideInPixels = VITA_GXM_SCREEN_STRIDE; + + updateParam.renderTarget.colorSurfaceData = buffer_for_common_dialog[back_buffer_index_for_common_dialog].displayData.address; + + updateParam.displaySyncObject = buffer_for_common_dialog[back_buffer_index_for_common_dialog].sync; + memset(buffer_for_common_dialog[back_buffer_index_for_common_dialog].displayData.address, 0, 4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT); + sceCommonDialogUpdate(&updateParam); + + sceGxmDisplayQueueAddEntry(buffer_for_common_dialog[front_buffer_index_for_common_dialog].sync, buffer_for_common_dialog[back_buffer_index_for_common_dialog].sync, &buffer_for_common_dialog[back_buffer_index_for_common_dialog].displayData); + front_buffer_index_for_common_dialog = back_buffer_index_for_common_dialog; + back_buffer_index_for_common_dialog = (back_buffer_index_for_common_dialog + 1) % VITA_GXM_BUFFERS; +} + +void gxm_term_for_common_dialog(void) +{ + sceGxmDisplayQueueFinish(); + for (int i = 0; i < VITA_GXM_BUFFERS; i += 1) { + vita_mem_free(buffer_for_common_dialog[i].uid); + sceGxmSyncObjectDestroy(buffer_for_common_dialog[i].sync); + } +} diff --git a/message_box/src/gxm_base.h b/message_box/src/gxm_base.h new file mode 100644 index 0000000..6ae260a --- /dev/null +++ b/message_box/src/gxm_base.h @@ -0,0 +1,10 @@ +#ifndef GXM_BASE_H +#define GXM_BASE_H + +void gxm_minimal_init_for_common_dialog(void); +void gxm_init_for_common_dialog(void); +void gxm_swap_for_common_dialog(void); +void gxm_term_for_common_dialog(void); +void gxm_minimal_term_for_common_dialog(void); + +#endif \ No newline at end of file diff --git a/message_box/src/main.c b/message_box/src/main.c new file mode 100644 index 0000000..8f8648c --- /dev/null +++ b/message_box/src/main.c @@ -0,0 +1,154 @@ +#include +#include +#include +#include "gxm_base.h" +#include +#include +#include + +#define zero_memory(v) memset(&v, 0, sizeof(v)) +#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) + +typedef struct{ + void*data; + SceGxmSyncObject*sync; + SceGxmColorSurface surf; + SceUID uid; +}displayBuffer; + + +typedef struct MessageBoxButton +{ + char* text; + int buttonID; +} MessageBoxButton; + +typedef struct MessageBoxData +{ + char* title; + char* message; + unsigned char numbuttons; + MessageBoxButton buttons[3]; +} MessageBoxData; + +bool VITA_ShowMessageBox(const MessageBoxData *messageboxdata, int *buttonID); + + +int main(int argc, const char *argv[]) { + MessageBoxData msgBox; + + msgBox.title = "Box displays 'OK' as an option when you use numbuttons == 1"; + msgBox.message = "We are testing a really big message. Please you should try testing a bigger text here."; + msgBox.numbuttons = 1; + msgBox.buttons[0].text = "Custom Button 1"; + msgBox.buttons[0].buttonID = 0; + msgBox.buttons[1].text = "Custom Button 2"; + msgBox.buttons[1].buttonID = 1; + msgBox.buttons[2].text = "Custom Button 3"; + msgBox.buttons[2].buttonID = 2; + int selectedButton; + + for(int i = 1; i < 4; i++) + { + msgBox.numbuttons = i; + if(i == 2) + msgBox.title = "Box displays Yes and No whenever you use numbuttons == 2"; + if(i == 3) + msgBox.title = "Box displays custom messages whenever you use numbuttons == 3"; + + VITA_ShowMessageBox(&msgBox, &selectedButton); + + } + //here + return 0; +} + + + +bool VITA_ShowMessageBox(const MessageBoxData *messageboxdata, int *buttonID) +{ + SceMsgDialogParam param; + SceMsgDialogUserMessageParam msgParam; + SceMsgDialogButtonsParam buttonParam; + SceDisplayFrameBuf dispparam; + char message[512]; + + SceMsgDialogResult dialog_result; + SceCommonDialogErrorCode init_result; + bool setup_minimal_gxm = false; + + if (messageboxdata->numbuttons > 3) { + return false; + } + + zero_memory(param); + + sceMsgDialogParamInit(¶m); + param.mode = SCE_MSG_DIALOG_MODE_USER_MSG; + + zero_memory(msgParam); + + snprintf(message, sizeof(message), "%s\r\n\r\n%s", messageboxdata->title, messageboxdata->message); + + msgParam.msg = (const SceChar8 *)message; + zero_memory(buttonParam); + + if (messageboxdata->numbuttons == 3) { + msgParam.buttonType = SCE_MSG_DIALOG_BUTTON_TYPE_3BUTTONS; + msgParam.buttonParam = &buttonParam; + buttonParam.msg1 = messageboxdata->buttons[0].text; + buttonParam.msg2 = messageboxdata->buttons[1].text; + buttonParam.msg3 = messageboxdata->buttons[2].text; + } else if (messageboxdata->numbuttons == 2) { + msgParam.buttonType = SCE_MSG_DIALOG_BUTTON_TYPE_YESNO; + } else if (messageboxdata->numbuttons == 1) { + msgParam.buttonType = SCE_MSG_DIALOG_BUTTON_TYPE_OK; + } + param.userMsgParam = &msgParam; + + dispparam.size = sizeof(dispparam); + + init_result = sceMsgDialogInit(¶m); + + // Setup display if it hasn't been initialized before + if (init_result == SCE_COMMON_DIALOG_ERROR_GXM_IS_UNINITIALIZED) { + gxm_minimal_init_for_common_dialog(); + init_result = sceMsgDialogInit(¶m); + setup_minimal_gxm = true; + } + + gxm_init_for_common_dialog(); + + if (init_result >= 0) { + while (sceMsgDialogGetStatus() == SCE_COMMON_DIALOG_STATUS_RUNNING) { + gxm_swap_for_common_dialog(); + } + zero_memory(dialog_result); + sceMsgDialogGetResult(&dialog_result); + + if (dialog_result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_BUTTON1) { + *buttonID = messageboxdata->buttons[0].buttonID; + } else if (dialog_result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_BUTTON2) { + *buttonID = messageboxdata->buttons[1].buttonID; + } else if (dialog_result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_BUTTON3) { + *buttonID = messageboxdata->buttons[2].buttonID; + } else if (dialog_result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_YES) { + *buttonID = messageboxdata->buttons[0].buttonID; + } else if (dialog_result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_NO) { + *buttonID = messageboxdata->buttons[1].buttonID; + } else if (dialog_result.buttonId == SCE_MSG_DIALOG_BUTTON_ID_OK) { + *buttonID = messageboxdata->buttons[0].buttonID; + } + sceMsgDialogTerm(); + } else { + return false; + } + + gxm_term_for_common_dialog(); + + if (setup_minimal_gxm) { + gxm_minimal_term_for_common_dialog(); + } + + return true; +} \ No newline at end of file