mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-14 01:55:19 -04:00
Dreamcast: Initial WIP on showing on-screen keyboard when no keyboard connected
This commit is contained in:
parent
4d8cd3e49e
commit
8bd5e66f46
41
src/Bitmap.c
41
src/Bitmap.c
@ -303,7 +303,7 @@ static Png_RowExpander Png_GetExpander(cc_uint8 col, cc_uint8 bitsPerSample) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Sets alpha to 0 for any pixels in the bitmap whose RGB is same as col */
|
||||
/* Sets alpha to 0 for any pixels in the bitmap whose RGB is same as colorspace */
|
||||
static void ComputeTransparency(struct Bitmap* bmp, BitmapCol col) {
|
||||
BitmapCol trnsRGB = col & BITMAPCOLOR_RGB_MASK;
|
||||
int x, y, width = bmp->width, height = bmp->height;
|
||||
@ -324,27 +324,27 @@ cc_result Png_Decode(struct Bitmap* bmp, struct Stream* stream) {
|
||||
|
||||
/* header variables */
|
||||
static const cc_uint8 samplesPerPixel[] = { 1, 0, 3, 1, 2, 0, 4 };
|
||||
cc_uint8 col, bitsPerSample, bytesPerPixel = 0;
|
||||
cc_uint8 colorspace, bitsPerSample, bytesPerPixel = 0;
|
||||
Png_RowExpander rowExpander = NULL;
|
||||
cc_uint32 scanlineSize = 0, scanlineBytes = 0;
|
||||
|
||||
/* palette data */
|
||||
BitmapCol trnsCol;
|
||||
BitmapCol trnsColor;
|
||||
BitmapCol palette[PNG_PALETTE];
|
||||
cc_uint32 i;
|
||||
|
||||
/* idat state */
|
||||
cc_uint32 begY, rowY = 0, endY;
|
||||
cc_uint8 buffer[PNG_PALETTE * 3];
|
||||
cc_uint32 bufferIdx, bufferLen;
|
||||
cc_uint32 read, left;
|
||||
cc_uint32 read, bufferIdx = 0;
|
||||
cc_uint32 left, bufferLen = 0;
|
||||
int curY;
|
||||
|
||||
/* idat decompressor */
|
||||
struct InflateState inflate;
|
||||
struct Stream compStream, datStream;
|
||||
struct ZLibHeader zlibHeader;
|
||||
cc_uint8* data;
|
||||
cc_uint8* data = NULL;
|
||||
|
||||
bmp->width = 0; bmp->height = 0;
|
||||
bmp->scan0 = NULL;
|
||||
@ -353,8 +353,8 @@ cc_result Png_Decode(struct Bitmap* bmp, struct Stream* stream) {
|
||||
if (res) return res;
|
||||
if (!Png_Detect(tmp, PNG_SIG_SIZE)) return PNG_ERR_INVALID_SIG;
|
||||
|
||||
col = 0xFF; /* Unknown colour space */
|
||||
trnsCol = BITMAPCOLOR_BLACK;
|
||||
colorspace = 0xFF; /* Unknown colour space */
|
||||
trnsColor = BITMAPCOLOR_BLACK;
|
||||
for (i = 0; i < PNG_PALETTE; i++) { palette[i] = BITMAPCOLOR_BLACK; }
|
||||
|
||||
Inflate_MakeStream2(&compStream, &inflate, stream);
|
||||
@ -378,25 +378,24 @@ cc_result Png_Decode(struct Bitmap* bmp, struct Stream* stream) {
|
||||
if (bmp->width < 0 || bmp->width > PNG_MAX_DIMS) return PNG_ERR_TOO_WIDE;
|
||||
if (bmp->height < 0 || bmp->height > PNG_MAX_DIMS) return PNG_ERR_TOO_TALL;
|
||||
|
||||
bitsPerSample = tmp[8]; col = tmp[9];
|
||||
bitsPerSample = tmp[8]; colorspace = tmp[9];
|
||||
if (bitsPerSample == 16) return PNG_ERR_16BITSAMPLES;
|
||||
|
||||
rowExpander = Png_GetExpander(col, bitsPerSample);
|
||||
rowExpander = Png_GetExpander(colorspace, bitsPerSample);
|
||||
if (!rowExpander) return PNG_ERR_INVALID_COL_BPP;
|
||||
|
||||
if (tmp[10] != 0) return PNG_ERR_COMP_METHOD;
|
||||
if (tmp[11] != 0) return PNG_ERR_FILTER;
|
||||
if (tmp[12] != 0) return PNG_ERR_INTERLACED;
|
||||
|
||||
bytesPerPixel = ((samplesPerPixel[col] * bitsPerSample) + 7) >> 3;
|
||||
scanlineSize = ((samplesPerPixel[col] * bitsPerSample * bmp->width) + 7) >> 3;
|
||||
bytesPerPixel = ((samplesPerPixel[colorspace] * bitsPerSample) + 7) >> 3;
|
||||
scanlineSize = ((samplesPerPixel[colorspace] * bitsPerSample * bmp->width) + 7) >> 3;
|
||||
scanlineBytes = scanlineSize + 1; /* Add 1 byte for filter byte of each scanline */
|
||||
|
||||
data = Mem_TryAlloc(bmp->height, max(scanlineBytes, bmp->width * 4));
|
||||
bmp->scan0 = (BitmapCol*)data;
|
||||
if (!bmp->scan0) return ERR_OUT_OF_MEMORY;
|
||||
|
||||
bufferIdx = 0;
|
||||
bufferLen = bmp->height * scanlineBytes;
|
||||
} break;
|
||||
|
||||
@ -418,15 +417,15 @@ cc_result Png_Decode(struct Bitmap* bmp, struct Stream* stream) {
|
||||
|
||||
/* 11.3.2.1 tRNS Transparency */
|
||||
case PNG_FourCC('t','R','N','S'): {
|
||||
if (col == PNG_COLOR_GRAYSCALE) {
|
||||
if (colorspace == PNG_COLOR_GRAYSCALE) {
|
||||
if (dataSize != 2) return PNG_ERR_TRANS_COUNT;
|
||||
|
||||
res = Stream_Read(stream, buffer, dataSize);
|
||||
if (res) return res;
|
||||
|
||||
/* RGB is always two bytes */
|
||||
trnsCol = BitmapCol_Make(buffer[1], buffer[1], buffer[1], 0);
|
||||
} else if (col == PNG_COLOR_INDEXED) {
|
||||
trnsColor = BitmapCol_Make(buffer[1], buffer[1], buffer[1], 0);
|
||||
} else if (colorspace == PNG_COLOR_INDEXED) {
|
||||
if (dataSize > PNG_PALETTE) return PNG_ERR_TRANS_COUNT;
|
||||
|
||||
res = Stream_Read(stream, buffer, dataSize);
|
||||
@ -437,14 +436,14 @@ cc_result Png_Decode(struct Bitmap* bmp, struct Stream* stream) {
|
||||
palette[i] &= BITMAPCOLOR_RGB_MASK; /* set A to 0 */
|
||||
palette[i] |= buffer[i] << BITMAPCOLOR_A_SHIFT;
|
||||
}
|
||||
} else if (col == PNG_COLOR_RGB) {
|
||||
} else if (colorspace == PNG_COLOR_RGB) {
|
||||
if (dataSize != 6) return PNG_ERR_TRANS_COUNT;
|
||||
|
||||
res = Stream_Read(stream, buffer, dataSize);
|
||||
if (res) return res;
|
||||
|
||||
/* R,G,B are always two bytes */
|
||||
trnsCol = BitmapCol_Make(buffer[1], buffer[3], buffer[5], 0);
|
||||
trnsColor = BitmapCol_Make(buffer[1], buffer[3], buffer[5], 0);
|
||||
} else {
|
||||
return PNG_ERR_TRANS_INVALID;
|
||||
}
|
||||
@ -488,7 +487,7 @@ cc_result Png_Decode(struct Bitmap* bmp, struct Stream* stream) {
|
||||
/* With the RGBA colourspace, each scanline is (1 + width*4) bytes wide */
|
||||
/* Therefore once a row has been reconstructed, the prior row can be converted */
|
||||
/* immediately into the destination colour format */
|
||||
if (col == PNG_COLOR_RGB_A) {
|
||||
if (colorspace == PNG_COLOR_RGB_A) {
|
||||
/* Prior line is no longer needed and can be overwritten now */
|
||||
rowExpander(bmp->width, palette, &prior[1], Bitmap_GetRow(bmp, rowY - 1));
|
||||
/* Current line is also no longer needed and can be overwritten now */
|
||||
@ -505,14 +504,14 @@ cc_result Png_Decode(struct Bitmap* bmp, struct Stream* stream) {
|
||||
/* Therefore image expansion can only be done after all the rows have been reconstructed, and must */
|
||||
/* be done backwards to avoid overwriting any source data that has yet to be processed */
|
||||
/* This is slightly slower, but the majority of images ClassiCube encounters are RGBA anyways */
|
||||
if (col != PNG_COLOR_RGB_A) {
|
||||
if (colorspace != PNG_COLOR_RGB_A) {
|
||||
for (curY = bmp->height - 1; curY >= 0; curY--) {
|
||||
cc_uint8* scanline = &data[curY * scanlineBytes];
|
||||
rowExpander(bmp->width, palette, &scanline[1], Bitmap_GetRow(bmp, curY));
|
||||
}
|
||||
}
|
||||
|
||||
if (!BitmapCol_A(trnsCol)) ComputeTransparency(bmp, trnsCol);
|
||||
if (!BitmapCol_A(trnsColor)) ComputeTransparency(bmp, trnsColor);
|
||||
return 0;
|
||||
} break;
|
||||
|
||||
|
@ -187,6 +187,8 @@ static cc_bool IsShutdown(int key) {
|
||||
}
|
||||
|
||||
static void OnInputDown(void* obj, int key, cc_bool was) {
|
||||
if (Window_Main.SoftKeyboardFocus) return;
|
||||
|
||||
if (IsShutdown(key)) Launcher_ShouldExit = true;
|
||||
Launcher_Active->KeyDown(Launcher_Active, key, was);
|
||||
}
|
||||
|
@ -1,16 +1,22 @@
|
||||
#include "Core.h"
|
||||
#include "Drawer2D.h"
|
||||
#include "Funcs.h"
|
||||
#include "Drawer2D.h"
|
||||
#include "Event.h"
|
||||
#include "ExtMath.h"
|
||||
#include "String.h"
|
||||
#include "Input.h"
|
||||
#include "Utils.h"
|
||||
#include "LBackend.h"
|
||||
#include "Window.h"
|
||||
|
||||
static cc_bool kb_inited, kb_showing, kb_shift;
|
||||
static cc_bool kb_inited, kb_showing, kb_shift, kb_needsHook;
|
||||
static struct FontDesc kb_font;
|
||||
static int kb_selected;
|
||||
static const char** kb_table;
|
||||
static float kb_padXAcc, kb_padYAcc;
|
||||
static char kb_buffer[512];
|
||||
static cc_string kb_str = String_FromArray(kb_buffer);
|
||||
static void (*KB_MarkDirty)(void);
|
||||
|
||||
#define KB_CELLS_PER_ROW 13
|
||||
#define KB_LAST_CELL (KB_CELLS_PER_ROW - 1)
|
||||
@ -24,15 +30,15 @@ static cc_string kb_str = String_FromArray(kb_buffer);
|
||||
|
||||
static const char* kb_table_lower[] =
|
||||
{
|
||||
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "\x11 BSP",
|
||||
"q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "(", ")", "& ",
|
||||
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "Backspace",
|
||||
"q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "(", ")", "& ",
|
||||
"a", "s", "d", "f", "g", "h", "j", "k", "l", "?", ";", "'", "Enter",
|
||||
"z", "x", "c", "v", "b", "n", "m", ".", ",","\\", "!", "@", "/ ",
|
||||
"Caps", "Shift", "Space"
|
||||
};
|
||||
static const char* kb_table_upper[] =
|
||||
{
|
||||
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "< BSP",
|
||||
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "Backspace",
|
||||
"Q", "W", "E", "R", "T", "Y", "U", "I", "o", "p", "(", ")", "& ",
|
||||
"A", "S", "D", "F", "G", "H", "J", "K", "L", "?", ";", "'", "Enter",
|
||||
"Z", "X", "C", "V", "B", "N", "M", ".", ",","\\", "!", "@", "/ ",
|
||||
@ -49,7 +55,7 @@ static void VirtualKeyboard_Init(void) {
|
||||
}
|
||||
|
||||
static int VirtualKeyboard_Width(void) {
|
||||
return (KB_CELLS_PER_ROW + 4) * KB_TILE_SIZE;
|
||||
return (KB_CELLS_PER_ROW + 3) * KB_TILE_SIZE;
|
||||
}
|
||||
|
||||
static int VirtualKeyboard_Height(void) {
|
||||
@ -57,6 +63,7 @@ static int VirtualKeyboard_Height(void) {
|
||||
}
|
||||
|
||||
static void VirtualKeyboard_Close(void);
|
||||
static void VirtualKeyboard_Hook(void);
|
||||
|
||||
|
||||
#define KB_NORMAL_COLOR BitmapCol_Make(0x7F, 0x7F, 0x7F, 0x90)
|
||||
@ -69,6 +76,7 @@ static void VirtualKeyboard_Draw(struct Context2D* ctx) {
|
||||
int row, cell;
|
||||
int i, x, y, w, h, dx, dy;
|
||||
Drawer2D.Colors['f'] = Drawer2D.Colors['0'];
|
||||
if (kb_needsHook) VirtualKeyboard_Hook();
|
||||
|
||||
for (row = 0, y = 0; row < KB_TOTAL_ROWS; row++)
|
||||
{
|
||||
@ -103,15 +111,16 @@ static void VirtualKeyboard_Scroll(int delta) {
|
||||
kb_selected += delta;
|
||||
if (kb_selected < 0) kb_selected += KB_TOTAL_CHARS;
|
||||
Math_Clamp(kb_selected, 0, KB_TOTAL_CHARS - 1);
|
||||
KB_MarkDirty();
|
||||
}
|
||||
|
||||
static void VirtualKeyboard_ToggleTable(void) {
|
||||
kb_table = kb_table == kb_table_lower ? kb_table_upper : kb_table_lower;
|
||||
KB_MarkDirty();
|
||||
}
|
||||
|
||||
static void VirtualKeyboard_AppendChar(char c) {
|
||||
String_Append(&kb_str, c);
|
||||
Platform_Log1("%s", &kb_str);
|
||||
|
||||
Event_RaiseString(&InputEvents.TextChanged, &kb_str);
|
||||
if (kb_shift) { VirtualKeyboard_ToggleTable(); kb_shift = false; }
|
||||
@ -125,8 +134,10 @@ static void VirtualKeyboard_ClickSelected(void) {
|
||||
case KB_INDEX(KB_LAST_CELL, 0):
|
||||
if (kb_str.length) kb_str.length--;
|
||||
Event_RaiseString(&InputEvents.TextChanged, &kb_str);
|
||||
KB_MarkDirty();
|
||||
break;
|
||||
case KB_INDEX(KB_LAST_CELL, 2):
|
||||
KB_MarkDirty();
|
||||
Window_CloseKeyboard();
|
||||
Input_SetPressed(CCKEY_ENTER);
|
||||
Input_SetReleased(CCKEY_ENTER);
|
||||
@ -158,8 +169,10 @@ static void VirtualKeyboard_ProcessDown(void* obj, int key, cc_bool was) {
|
||||
VirtualKeyboard_Scroll(-KB_CELLS_PER_ROW);
|
||||
} else if (Input_IsDownButton(key)) {
|
||||
VirtualKeyboard_Scroll(+KB_CELLS_PER_ROW);
|
||||
} else if (Input_IsEnterButton(key) || key == CCPAD_A) {
|
||||
} else if (Input_IsEnterButton(key) || key == CCPAD_A) {
|
||||
VirtualKeyboard_ClickSelected();
|
||||
} else if (Input_IsEscapeButton(key) || key == CCPAD_B) {
|
||||
VirtualKeyboard_Close();
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,10 +187,28 @@ static void VirtualKeyboard_PadAxis(void* obj, int axis, float x, float y) {
|
||||
}
|
||||
|
||||
|
||||
static void VirtualKeyboard_Display(struct OpenKeyboardArgs* args) {
|
||||
static void VirtualKeyboard_MarkDirty2D(void) {
|
||||
LBackend_Redraw();
|
||||
}
|
||||
|
||||
static void VirtualKeyboard_MarkDirty3D(void) {
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
static void VirtualKeyboard_Hook(void) {
|
||||
/* Don't hook immediately into events, otherwise the initial up/down press that opened */
|
||||
/* the virtual keyboard in the first place gets mistakenly processed */
|
||||
kb_needsHook = false;
|
||||
|
||||
Event_Register_(&InputEvents.Down, NULL, VirtualKeyboard_ProcessDown);
|
||||
Event_Register_(&ControllerEvents.AxisUpdate, NULL, VirtualKeyboard_PadAxis);
|
||||
}
|
||||
|
||||
static void VirtualKeyboard_Open(struct OpenKeyboardArgs* args, cc_bool launcher) {
|
||||
VirtualKeyboard_Close();
|
||||
VirtualKeyboard_Init();
|
||||
kb_showing = true;
|
||||
kb_showing = true;
|
||||
kb_needsHook = true;
|
||||
|
||||
kb_table = kb_table_lower;
|
||||
kb_selected = -1;
|
||||
@ -187,9 +218,14 @@ static void VirtualKeyboard_Display(struct OpenKeyboardArgs* args) {
|
||||
|
||||
kb_str.length = 0;
|
||||
if (args) String_AppendConst(&kb_str, args->placeholder);
|
||||
|
||||
Event_Register_(&InputEvents.Down, NULL, VirtualKeyboard_ProcessDown);
|
||||
Event_Register_(&ControllerEvents.AxisUpdate, NULL, VirtualKeyboard_PadAxis);
|
||||
|
||||
if (launcher) {
|
||||
KB_MarkDirty = VirtualKeyboard_MarkDirty2D;
|
||||
} else {
|
||||
KB_MarkDirty = VirtualKeyboard_MarkDirty3D;
|
||||
}
|
||||
|
||||
Window_Main.SoftKeyboardFocus = true;
|
||||
}
|
||||
|
||||
static void VirtualKeyboard_SetText(const cc_string* text) {
|
||||
@ -197,7 +233,34 @@ static void VirtualKeyboard_SetText(const cc_string* text) {
|
||||
}
|
||||
|
||||
static void VirtualKeyboard_Close(void) {
|
||||
if (KB_MarkDirty) KB_MarkDirty();
|
||||
Event_Unregister_(&InputEvents.Down, NULL, VirtualKeyboard_ProcessDown);
|
||||
Event_Unregister_(&ControllerEvents.AxisUpdate, NULL, VirtualKeyboard_PadAxis);
|
||||
kb_showing = false;
|
||||
Window_Main.SoftKeyboardFocus = false;
|
||||
|
||||
KB_MarkDirty = NULL;
|
||||
kb_showing = false;
|
||||
kb_needsHook = false;
|
||||
}
|
||||
|
||||
static void VirtualKeyboard_Display2D(Rect2D* r, struct Bitmap* bmp) {
|
||||
struct Context2D ctx;
|
||||
struct Bitmap copy = *bmp;
|
||||
int x, y;
|
||||
|
||||
/* Mark entire framebuffer as needing to be redrawn */
|
||||
r->x = 0; r->width = bmp->width;
|
||||
r->y = 0; r->height = bmp->height;
|
||||
|
||||
/* Draw virtual keyboard at centre of window bottom */
|
||||
y = bmp->height - 1 - VirtualKeyboard_Height();
|
||||
y = max(y, 0);
|
||||
copy.scan0 = Bitmap_GetRow(bmp, y);
|
||||
|
||||
x = (bmp->width - VirtualKeyboard_Width()) / 2;
|
||||
x = max(x, 0);
|
||||
copy.scan0 += x;
|
||||
|
||||
Context2D_Wrap(&ctx, ©);
|
||||
VirtualKeyboard_Draw(&ctx);
|
||||
}
|
@ -84,6 +84,8 @@ struct _WindowData {
|
||||
/* Whether this window is backgrounded / inactivated */
|
||||
/* (rendering is not performed when window is inactive) */
|
||||
cc_bool Inactive;
|
||||
/* Whether input should be ignored due to soft keyboard being open */
|
||||
cc_bool SoftKeyboardFocus;
|
||||
};
|
||||
|
||||
/* Data for the game/launcher window */
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "Bitmap.h"
|
||||
#include "Errors.h"
|
||||
#include "ExtMath.h"
|
||||
#include "VirtualKeyboard.h"
|
||||
#include <kos.h>
|
||||
static cc_bool launcherMode;
|
||||
cc_bool window_inited;
|
||||
@ -31,6 +32,7 @@ void Window_Init(void) {
|
||||
Input.Sources = INPUT_SOURCE_GAMEPAD;
|
||||
DisplayInfo.ContentOffsetX = 10;
|
||||
DisplayInfo.ContentOffsetY = 20;
|
||||
Window_Main.SoftKeyboard = SOFT_KEYBOARD_VIRTUAL;
|
||||
|
||||
vid_set_mode(DEFAULT_VID_MODE, DEFAULT_PIXEL_MODE);
|
||||
vid_flip(0);
|
||||
@ -262,6 +264,7 @@ void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) {
|
||||
// https://dcemulation.org/phpBB/viewtopic.php?t=99999
|
||||
// https://dcemulation.org/phpBB/viewtopic.php?t=43214
|
||||
vid_waitvbl();
|
||||
if (kb_showing) VirtualKeyboard_Display2D(&r, bmp);
|
||||
|
||||
for (int y = r.y; y < r.y + r.height; y++)
|
||||
{
|
||||
@ -285,9 +288,20 @@ void Window_FreeFramebuffer(struct Bitmap* bmp) {
|
||||
/*########################################################################################################################*
|
||||
*------------------------------------------------------Soft keyboard------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
void Window_OpenKeyboard(struct OpenKeyboardArgs* args) { /* TODO implement */ }
|
||||
void Window_SetKeyboardText(const cc_string* text) { }
|
||||
void Window_CloseKeyboard(void) { /* TODO implement */ }
|
||||
void Window_OpenKeyboard(struct OpenKeyboardArgs* args) {
|
||||
if (Input.Sources & INPUT_SOURCE_NORMAL) return;
|
||||
VirtualKeyboard_Open(args, launcherMode);
|
||||
}
|
||||
|
||||
void Window_SetKeyboardText(const cc_string* text) {
|
||||
if (!kb_showing) return;
|
||||
VirtualKeyboard_SetText(text);
|
||||
}
|
||||
|
||||
void Window_CloseKeyboard(void) {
|
||||
if (Input.Sources & INPUT_SOURCE_NORMAL) return;
|
||||
VirtualKeyboard_Close();
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
|
Loading…
x
Reference in New Issue
Block a user