Skip to content

Commit

Permalink
fix: Message dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
kaaass committed Jul 3, 2022
1 parent 09c578a commit 3c6bb47
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 108 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ target_link_libraries(Kero-Blaster
SceTouch_stub
SceVshBridge_stub
SceAudio_stub
SceGxm_stub
libIMGEGL_stub_weak
libgpu_es4_ext_stub_weak
libGLESv2_stub_weak
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ cmake .. && make
- GrapheneCt for PVR_PSP2, which is the graphic backend in this project
- frangarcj for porting OpenSLES
- alula for helping me to solve the key configuration issue (#2)
- SDL2 for the implementation of error message dialog

## Progress

Expand Down
273 changes: 174 additions & 99 deletions loader/dialog.c
Original file line number Diff line number Diff line change
@@ -1,127 +1,161 @@
/* dialog.c -- common dialog for error messages and cheats input
/* dialog.c -- common dialog for error messages
*
* Copyright (C) 2021 fgsfds, Andy Nguyen
* Copyright (C) 1997-2022 Sam Lantinga <[email protected]>
* Copyright (C) 2022 KAAAsS
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
* This file includes the source code of SDL2, see https://github.com/libsdl-org/SDL/blob/main/LICENSE.txt
* for the original license.
*/

#include <psp2/kernel/processmgr.h>
#include <psp2/ctrl.h>
#include <psp2/ime_dialog.h>
#include <psp2/message_dialog.h>
#include <vitaGL.h>

#include <stdio.h>
#include <stdarg.h>
#include <psp2/display.h>
#include <stdbool.h>
#include <psp2/gxm.h>
#include <psp2/types.h>
#include <psp2/kernel/sysmem.h>

#include "main.h"
#include "dialog.h"

static uint16_t ime_title_utf16[SCE_IME_DIALOG_MAX_TITLE_LENGTH];
static uint16_t ime_initial_text_utf16[SCE_IME_DIALOG_MAX_TEXT_LENGTH];
static uint16_t ime_input_text_utf16[SCE_IME_DIALOG_MAX_TEXT_LENGTH + 1];
static uint8_t ime_input_text_utf8[SCE_IME_DIALOG_MAX_TEXT_LENGTH + 1];

void utf16_to_utf8(const uint16_t *src, uint8_t *dst) {
for (int i = 0; src[i]; i++) {
if ((src[i] & 0xFF80) == 0) {
*(dst++) = src[i] & 0xFF;
} else if ((src[i] & 0xF800) == 0) {
*(dst++) = ((src[i] >> 6) & 0xFF) | 0xC0;
*(dst++) = (src[i] & 0x3F) | 0x80;
} else if ((src[i] & 0xFC00) == 0xD800 && (src[i + 1] & 0xFC00) == 0xDC00) {
*(dst++) = (((src[i] + 64) >> 8) & 0x3) | 0xF0;
*(dst++) = (((src[i] >> 2) + 16) & 0x3F) | 0x80;
*(dst++) = ((src[i] >> 4) & 0x30) | 0x80 | ((src[i + 1] << 2) & 0xF);
*(dst++) = (src[i + 1] & 0x3F) | 0x80;
i += 1;
} else {
*(dst++) = ((src[i] >> 12) & 0xF) | 0xE0;
*(dst++) = ((src[i] >> 6) & 0x3F) | 0x80;
*(dst++) = (src[i] & 0x3F) | 0x80;
}
}
#define VITA_GXM_PENDING_SWAPS 2
#define VITA_GXM_BUFFERS 3
#define VITA_GXM_SCREEN_WIDTH 960
#define VITA_GXM_SCREEN_HEIGHT 544
#define VITA_GXM_SCREEN_STRIDE 960
#define VITA_GXM_PIXEL_FORMAT SCE_DISPLAY_PIXELFORMAT_A8B8G8R8

*dst = '\0';
}
typedef struct {
void *address;
uint8_t wait_vblank;
} VITA_GXM_DisplayData;

void utf8_to_utf16(const uint8_t *src, uint16_t *dst) {
for (int i = 0; src[i];) {
if ((src[i] & 0xE0) == 0xE0) {
*(dst++) = ((src[i] & 0x0F) << 12) | ((src[i + 1] & 0x3F) << 6) | (src[i + 2] & 0x3F);
i += 3;
} else if ((src[i] & 0xC0) == 0xC0) {
*(dst++) = ((src[i] & 0x1F) << 6) | (src[i + 1] & 0x3F);
i += 2;
} else {
*(dst++) = src[i];
i += 1;
}
}
#define ALIGN(x, align) (((x) + ((align) - 1)) & ~((align) - 1))

*dst = '\0';
}
static void *vita_mem_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int attribs, SceUID *uid) {
void *mem;

int init_ime_dialog(const char *title, const char *initial_text) {
memset(ime_title_utf16, 0, sizeof(ime_title_utf16));
memset(ime_initial_text_utf16, 0, sizeof(ime_initial_text_utf16));
memset(ime_input_text_utf16, 0, sizeof(ime_input_text_utf16));
memset(ime_input_text_utf8, 0, sizeof(ime_input_text_utf8));
size = ALIGN(size, 256 * 1024);
*uid = sceKernelAllocMemBlock("gpu_mem", type, size, NULL);

utf8_to_utf16((uint8_t *) title, ime_title_utf16);
utf8_to_utf16((uint8_t *) initial_text, ime_initial_text_utf16);
if (*uid < 0)
return NULL;

if (sceKernelGetMemBlockBase(*uid, &mem) < 0)
return NULL;

SceImeDialogParam param;
sceImeDialogParamInit(&param);
if (sceGxmMapMemory(mem, size, attribs) < 0)
return NULL;

param.supportedLanguages = 0x0001FFFF;
param.languagesForced = SCE_TRUE;
param.type = SCE_IME_TYPE_BASIC_LATIN;
param.title = ime_title_utf16;
param.maxTextLength = SCE_IME_DIALOG_MAX_TEXT_LENGTH;
param.initialText = ime_initial_text_utf16;
param.inputTextBuffer = ime_input_text_utf16;
return mem;
}

return sceImeDialogInit(&param);
static void vita_mem_free(SceUID uid) {
void *mem = NULL;
if (sceKernelGetMemBlockBase(uid, &mem) < 0)
return;
sceGxmUnmapMemory(mem);
sceKernelFreeMemBlock(uid);
}

char *get_ime_dialog_result(void) {
if (sceImeDialogGetStatus() != SCE_COMMON_DIALOG_STATUS_FINISHED)
return NULL;
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();
}
}

SceImeDialogResult result;
memset(&result, 0, sizeof(SceImeDialogResult));
sceImeDialogGetResult(&result);
if (result.button == SCE_IME_DIALOG_BUTTON_ENTER)
utf16_to_utf8(ime_input_text_utf16, ime_input_text_utf8);
sceImeDialogTerm();
// For some reason analog stick stops working after ime
sceCtrlSetSamplingModeExt(SCE_CTRL_MODE_ANALOG_WIDE);

return (char *) ime_input_text_utf8;
static unsigned int back_buffer_index_for_common_dialog = 0;
static unsigned int front_buffer_index_for_common_dialog = 0;
struct {
VITA_GXM_DisplayData displayData;
SceGxmSyncObject *sync;
SceGxmColorSurface surf;
SceUID uid;
} buffer_for_common_dialog[VITA_GXM_BUFFERS];

void gxm_minimal_init_for_common_dialog(void) {
SceGxmInitializeParams initializeParams;
memset(&initializeParams, 0, sizeof(SceGxmInitializeParams));
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);
}

int init_msg_dialog(const char *msg) {
SceMsgDialogUserMessageParam msg_param;
memset(&msg_param, 0, sizeof(msg_param));
msg_param.buttonType = SCE_MSG_DIALOG_BUTTON_TYPE_OK;
msg_param.msg = (SceChar8 *) msg;
void gxm_minimal_term_for_common_dialog(void) {
sceGxmTerminate();
}

SceMsgDialogParam param;
sceMsgDialogParamInit(&param);
_sceCommonDialogSetMagicNumber(&param.commonParam);
param.mode = SCE_MSG_DIALOG_MODE_USER_MSG;
param.userMsgParam = &msg_param;
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_CDRAM_RW,
4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&buffer_for_common_dialog[i].uid);
sceGxmColorSurfaceInit(
&buffer_for_common_dialog[i].surf,
(SceGxmColorFormat) 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();
}

return sceMsgDialogInit(&param);
void gxm_swap_for_common_dialog(void) {
SceCommonDialogUpdateParam updateParam;
memset(&updateParam, 0, sizeof(SceCommonDialogUpdateParam));
updateParam.renderTarget.colorFormat = (SceGxmColorFormat) 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;
}

int get_msg_dialog_result(void) {
if (sceMsgDialogGetStatus() != SCE_COMMON_DIALOG_STATUS_FINISHED)
return 0;
sceMsgDialogTerm();
return 1;
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);
}
}

void fatal_error(const char *fmt, ...) {
Expand All @@ -132,13 +166,54 @@ void fatal_error(const char *fmt, ...) {
vsnprintf(string, sizeof(string), fmt, list);
va_end(list);

// fixme: message box
// vglInit(0);
debugPrintf("[FatalError]: %s\n", string);

SceMsgDialogParam param;
SceMsgDialogUserMessageParam msgParam;
SceMsgDialogButtonsParam buttonParam;
SceDisplayFrameBuf dispparam;

SceMsgDialogResult dialog_result;
SceCommonDialogErrorCode init_result;
bool setup_minimal_gxm = false;

memset(&param, 0, sizeof(param));
sceMsgDialogParamInit(&param);
param.mode = SCE_MSG_DIALOG_MODE_USER_MSG;

memset(&msgParam, 0, sizeof(msgParam));

msgParam.msg = (const SceChar8 *) string;
memset(&buttonParam, 0, sizeof(buttonParam));

init_msg_dialog(string);
msgParam.buttonType = SCE_MSG_DIALOG_BUTTON_TYPE_OK;
param.userMsgParam = &msgParam;

// while (!get_msg_dialog_result())
// vglSwapBuffers(GL_TRUE);
dispparam.size = sizeof(dispparam);

init_result = sceMsgDialogInit(&param);

// 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(&param);
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();
}
sceMsgDialogTerm();
}

gxm_term_for_common_dialog();

if (setup_minimal_gxm) {
gxm_minimal_term_for_common_dialog();
}

sceKernelExitProcess(0);
while (1);
Expand Down
12 changes: 3 additions & 9 deletions loader/dialog.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
#include <sys/cdefs.h>

#ifndef __DIALOG_H__
#define __DIALOG_H__

int init_ime_dialog(const char *title, const char *initial_text);

char *get_ime_dialog_result(void);

int init_msg_dialog(const char *msg);

int get_msg_dialog_result(void);

void fatal_error(const char *fmt, ...) __attribute__((noreturn));
_Noreturn void fatal_error(const char *fmt, ...) __attribute__((noreturn));

#endif

0 comments on commit 3c6bb47

Please sign in to comment.