-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
179 additions
and
108 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(¶m); | ||
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(¶m); | ||
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(¶m); | ||
_sceCommonDialogSetMagicNumber(¶m.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(¶m); | ||
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, ...) { | ||
|
@@ -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(¶m, 0, sizeof(param)); | ||
sceMsgDialogParamInit(¶m); | ||
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(¶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(); | ||
} | ||
sceMsgDialogTerm(); | ||
} | ||
|
||
gxm_term_for_common_dialog(); | ||
|
||
if (setup_minimal_gxm) { | ||
gxm_minimal_term_for_common_dialog(); | ||
} | ||
|
||
sceKernelExitProcess(0); | ||
while (1); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |