Wednesday, July 15, 2020

Basics on the code PART 5

This entry is about the input method editor (IME). This will give us the power to make screen dialog windows with user input answers.

To understand the functions, we have to use the dialog section in the vitasdk documentation. for this particular sample, we will use specificly this user section.

SAMPLE "ime"

ime: Graphical dialog sample.

#include <string.h>
#include <stdbool.h>

#include <psp2/types.h>
#include <psp2/kernel/processmgr.h>
#include <psp2/message_dialog.h>
#include <psp2/ime_dialog.h>
#include <psp2/display.h>
#include <psp2/apputil.h>
#include <psp2/gxm.h>
#include <psp2/kernel/sysmem.h>


// screen constants
#define ALIGN(x, a)    (((x) + ((a) - 1)) & ~((a) - 1))
#define DISPLAY_WIDTH            960
#define DISPLAY_HEIGHT            544
#define DISPLAY_STRIDE_IN_PIXELS    1024
#define DISPLAY_BUFFER_COUNT        2
#define DISPLAY_MAX_PENDING_SWAPS    1




// dialog window structure
typedef struct{
    void*data;
    SceGxmSyncObject*sync;
    SceGxmColorSurface surf;
    SceUID uid;
}displayBuffer;

// variables for the text box
unsigned int backBufferIndex = 0;
unsigned int frontBufferIndex = 0;
/* could be converted as struct displayBuffer[] */
displayBuffer dbuf[DISPLAY_BUFFER_COUNT];

// memory allocation for the window object
void *dram_alloc(unsigned int size, SceUID *uid){
    void *mem;
    *uid = sceKernelAllocMemBlock("gpu_mem", SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, ALIGN(size,256*1024), NULL);
    sceKernelGetMemBlockBase(*uid, &mem);
    sceGxmMapMemory(mem, ALIGN(size,256*1024), SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE);
    return mem;
}

//
VSync (to match the graphics processor's frames with the refresh rate of the monitor to fix any syncing issues)
void gxm_vsync_cb(const void *callback_data){
    sceDisplaySetFrameBuf(&(SceDisplayFrameBuf){sizeof(SceDisplayFrameBuf),
        *((void **)callback_data),DISPLAY_STRIDE_IN_PIXELS, 0,
        DISPLAY_WIDTH,DISPLAY_HEIGHT}, SCE_DISPLAY_SETBUF_NEXTFRAME);
}

// gxm (Graphics eXpansion Modules) initialization
void gxm_init(){
    sceGxmInitialize(&(SceGxmInitializeParams){0,DISPLAY_MAX_PENDING_SWAPS,gxm_vsync_cb,sizeof(void *),SCE_GXM_DEFAULT_PARAMETER_BUFFER_SIZE});
    unsigned int i;
    for (i = 0; i < DISPLAY_BUFFER_COUNT; i++) {
        dbuf[i].data = dram_alloc(4*DISPLAY_STRIDE_IN_PIXELS*DISPLAY_HEIGHT, &dbuf[i].uid);
 
// applying gxm     sceGxmColorSurfaceInit(&dbuf[i].surf,SCE_GXM_COLOR_FORMAT_A8B8G8R8,SCE_GXM_COLOR_SURFACE_LINEAR,SCE_GXM_COLOR_SURFACE_SCALE_NONE,SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT,DISPLAY_WIDTH,DISPLAY_HEIGHT,DISPLAY_STRIDE_IN_PIXELS,dbuf[i].data);
        sceGxmSyncObjectCreate(&dbuf[i].sync);
    }
}
void gxm_swap(){
    sceGxmPadHeartbeat(&dbuf[backBufferIndex].surf, dbuf[backBufferIndex].sync);
    sceGxmDisplayQueueAddEntry(dbuf[frontBufferIndex].sync, dbuf[backBufferIndex].sync, &dbuf[backBufferIndex].data);
    frontBufferIndex = backBufferIndex;
    backBufferIndex = (backBufferIndex + 1) % DISPLAY_BUFFER_COUNT;
}
void gxm_term(){
    sceGxmTerminate();

// freeing memory
    for (int i=0; i<DISPLAY_BUFFER_COUNT; ++i)
        sceKernelFreeMemBlock(dbuf[i].uid);
}


// main program
int main(int argc, const char *argv[]) {

// declare and init the actual dialog window with its parameters
    uint16_t input[SCE_IME_DIALOG_MAX_TEXT_LENGTH + 1] = {0};
    SceImeDialogParam param;
    int shown_dial = 0; // var to keep the main loop , the display of  the keyboard
    bool said_yes = false; // var to keep looping (waiting) until the user says yes

    sceAppUtilInit(&(SceAppUtilInitParam){}, &(SceAppUtilBootParam){});
    sceCommonDialogSetConfigParam(&(SceCommonDialogConfigParam){});

   // initialize the gxm
    gxm_init();


   // keep the dialog windows open until the user answers "yes" in the text box
    while (!said_yes) {
        //clear current screen buffer
        memset(dbuf[backBufferIndex].data,0xff000000,DISPLAY_HEIGHT*DISPLAY_STRIDE_IN_PIXELS*4);

// parameters of the text and boxes of the window

      if (!shown_dial) {
            sceImeDialogParamInit(&param);

            param.supportedLanguages = SCE_IME_LANGUAGE_ENGLISH;
            param.languagesForced = SCE_TRUE;
            param.type = SCE_IME_DIALOG_TEXTBOX_MODE_DEFAULT;
            param.option = 0;
            param.textBoxMode = SCE_IME_DIALOG_TEXTBOX_MODE_DEFAULT;

            param.title = u"say yes!"; // var with the text displayed to the user above the bracket to write

            param.maxTextLength = SCE_IME_DIALOG_MAX_TEXT_LENGTH;

            param.initialText = u"nah"; // dafault text in the bracket for user input

            param.inputTextBuffer = input; // buffer to store the user input

            shown_dial = sceImeDialogInit(&param) > 0;
        }

    // get the input answers, and update (terminate or refresh) the dialog
        if (sceImeDialogGetStatus() == SCE_COMMON_DIALOG_STATUS_FINISHED) {
            SceImeDialogResult result={};      
            sceImeDialogGetResult(&result);

            uint16_t*last_input = (result.button == SCE_IME_DIALOG_BUTTON_ENTER) ? input:u"";

            said_yes=!memcmp(last_input,u"yes",4*sizeof(u' ')); // check if the answer is "yes"

            sceImeDialogTerm();
            shown_dial = 0;/*< to respawn sceImeDialogInit on next loop */
        }
    
        // show the user's input in the text box
        sceCommonDialogUpdate(&(SceCommonDialogUpdateParam){{
            NULL,dbuf[backBufferIndex].data,0,0,
            DISPLAY_WIDTH,DISPLAY_HEIGHT,DISPLAY_STRIDE_IN_PIXELS},
            dbuf[backBufferIndex].sync});

        gxm_swap();
        sceDisplayWaitVblankStart(); //
Wait for vertical blank start (a.k.a. Refreshing), should avoid blinking
    }


    gxm_term();
    sceKernelExitProcess(0); 
// close the vita proccess runing, usually close the app
    return 0;
}



-----------

Screenshot from the sample running on the vita:




And that's all for this sample.

No comments:

Post a Comment