Merge pull request #1136 from camthehaxman/3ds-dualscreen

Dual screen mode for 3DS
This commit is contained in:
UnknownShadow200 2024-02-03 12:57:14 +11:00 committed by GitHub
commit 164958df36
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 217 additions and 64 deletions

View File

@ -286,6 +286,7 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_BEARSSL
#define CC_BUILD_LOWMEM
#define CC_BUILD_CONSOLE
#define CC_BUILD_TOUCH
#undef CC_BUILD_FREETYPE
#elif defined GEKKO
#define CC_BUILD_GCWII

View File

@ -238,6 +238,9 @@ void Gfx_OnWindowResize(void);
/* NOTE: Each line is separated by \n */
void Gfx_GetApiInfo(cc_string* info);
void Gfx_3DS_DrawToTopScreen(void);
void Gfx_3DS_DrawToBottomScreen(void);
/* Raises ContextLost event and updates state for lost contexts */
void Gfx_LoseContext(const char* reason);
/* Raises ContextRecreated event and restores internal state */

View File

@ -106,7 +106,8 @@ static void SwitchProgram(void) {
/*########################################################################################################################*
*---------------------------------------------------------General---------------------------------------------------------*
*#########################################################################################################################*/
static C3D_RenderTarget* target;
static C3D_RenderTarget* topTarget;
static C3D_RenderTarget* bottomTarget;
static void AllocShaders(void) {
Shader_Alloc(&shaders[0], coloured_shbin, coloured_shbin_size);
@ -129,9 +130,16 @@ static void SetDefaultState(void) {
static void InitCitro3D(void) {
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
C3D_RenderTargetSetOutput(target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);
topTarget = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
C3D_RenderTargetSetOutput(topTarget, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);
// Even though the bottom screen is 320 pixels wide, we use 400 here so that the same ortho matrix
// can be used for both screens. The output is clipped to the actual screen width, anyway.
bottomTarget = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
C3D_RenderTargetSetOutput(bottomTarget, GFX_BOTTOM, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);
gfxSetDoubleBuffering(GFX_TOP, true);
SetDefaultState();
AllocShaders();
}
@ -173,6 +181,14 @@ void Gfx_FreeState(void) {
Gfx_DeleteTexture(&white_square);
}
void Gfx_3DS_DrawToTopScreen(void) {
C3D_FrameDrawOn(topTarget);
}
void Gfx_3DS_DrawToBottomScreen(void) {
C3D_FrameDrawOn(bottomTarget);
}
/*########################################################################################################################*
*---------------------------------------------------------Textures--------------------------------------------------------*
*#########################################################################################################################*/
@ -355,11 +371,12 @@ void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) {
void Gfx_BeginFrame(void) {
int flags = gfx_vsync ? C3D_FRAME_SYNCDRAW : 0;
C3D_FrameBegin(flags);
C3D_FrameDrawOn(topTarget);
}
void Gfx_Clear(void) {
C3D_RenderTargetClear(target, C3D_CLEAR_ALL, clear_color, 0);
C3D_FrameDrawOn(target);
C3D_RenderTargetClear(topTarget, C3D_CLEAR_ALL, clear_color, 0);
C3D_RenderTargetClear(bottomTarget, C3D_CLEAR_ALL, 0, 0);
}
void Gfx_EndFrame(void) {
@ -780,4 +797,4 @@ void Gfx_Draw2DTexture(const struct Texture* tex, PackedCol color) {
C3D_ImmSendAttrib(v[0].U, v[0].V, 0.0f, 0.0f);
C3D_ImmDrawEnd();
}
#endif
#endif

View File

@ -21,7 +21,9 @@
struct _GuiData Gui;
struct Screen* Gui_Screens[GUI_MAX_SCREENS];
static cc_uint8 priorities[GUI_MAX_SCREENS];
#ifdef __3DS__
static struct Texture touchBgTex;
#endif
/*########################################################################################################################*
*----------------------------------------------------------Gui------------------------------------------------------------*
@ -32,10 +34,14 @@ static CC_NOINLINE int GetWindowScale(void) {
/* Use larger UI scaling on mobile */
/* TODO move this DPI scaling elsewhere.,. */
#ifndef __3DS__
if (!Input_TouchMode) {
#endif
widthScale /= DisplayInfo.ScaleX;
heightScale /= DisplayInfo.ScaleY;
#ifndef __3DS__
}
#endif
return 1 + (int)(min(widthScale, heightScale));
}
@ -137,12 +143,16 @@ void Gui_LayoutAll(void) {
struct Screen* s;
int i;
enum Screen3DS scr = Window_3DS_SetRenderScreen(BOTTOM_SCREEN);
for (i = 0; i < Gui.ScreensCount; i++)
{
s = Gui_Screens[i];
s->VTABLE->Layout(s);
s->dirty = true;
}
Window_3DS_SetRenderScreen(scr);
}
void Gui_RefreshAll(void) {
@ -152,10 +162,14 @@ void Gui_RefreshAll(void) {
}
void Gui_Refresh(struct Screen* s) {
enum Screen3DS scr = Window_3DS_SetRenderScreen(BOTTOM_SCREEN);
s->VTABLE->ContextLost(s);
s->VTABLE->ContextRecreated(s);
s->VTABLE->Layout(s);
s->dirty = true;
Window_3DS_SetRenderScreen(scr);
}
static void Gui_AddCore(struct Screen* s, int priority) {
@ -179,6 +193,8 @@ static void Gui_AddCore(struct Screen* s, int priority) {
priorities[i] = priority;
Gui.ScreensCount++;
enum Screen3DS scr = Window_3DS_SetRenderScreen(BOTTOM_SCREEN);
s->dirty = true;
s->VTABLE->Init(s);
s->VTABLE->ContextRecreated(s);
@ -189,6 +205,8 @@ static void Gui_AddCore(struct Screen* s, int priority) {
{
s->VTABLE->HandlesPointerMove(s, i, Pointers[i].x, Pointers[i].y);
}
Window_3DS_SetRenderScreen(scr);
}
/* Returns index of the given screen in the screens list, -1 if not */
@ -283,6 +301,12 @@ void Gui_RenderGui(double delta) {
struct Screen* s;
int i;
enum Screen3DS scr = Window_3DS_SetRenderScreen(BOTTOM_SCREEN);
#ifdef __3DS__
Texture_Render(&touchBgTex);
#endif
/* Draw back to front so highest priority screen is on top */
for (i = Gui.ScreensCount - 1; i >= 0; i--)
{
@ -292,6 +316,8 @@ void Gui_RenderGui(double delta) {
if (s->dirty) { s->VTABLE->BuildMesh(s); s->dirty = false; }
s->VTABLE->Render(s, delta);
}
Window_3DS_SetRenderScreen(scr);
}
@ -449,22 +475,26 @@ int Screen_DoPointerDown(void* screen, int id, int x, int y) {
struct Screen* s = (struct Screen*)screen;
struct Widget** widgets = s->widgets;
int i, count = s->numWidgets;
enum Screen3DS scr = Window_3DS_SetRenderScreen(BOTTOM_SCREEN);
/* iterate backwards (because last elements rendered are shown over others) */
for (i = count - 1; i >= 0; i--)
{
struct Widget* w = widgets[i];
if (!w || !Widget_Contains(w, x, y)) continue;
if (w->flags & WIDGET_FLAG_DISABLED) return i;
if (w->flags & WIDGET_FLAG_DISABLED) break;
if (w->MenuClick) {
w->MenuClick(s, w);
} else {
Elem_HandlesPointerDown(w, id, x, y);
}
return i;
break;
}
return -1;
Window_3DS_SetRenderScreen(scr);
return i;
}
int Screen_Index(void* screen, void* widget) {
@ -568,7 +598,6 @@ static void TouchPngProcess(struct Stream* stream, const cc_string* name) {
}
static struct TextureEntry touch_entry = { "touch.png", TouchPngProcess };
static void OnFontChanged(void* obj) { Gui_RefreshAll(); }
static void OnKeyPress(void* obj, int cp) {
@ -612,6 +641,19 @@ static void OnInit(void) {
TextureEntry_Register(&icons_entry);
TextureEntry_Register(&touch_entry);
#ifdef __3DS__
struct Context2D ctx;
Context2D_Alloc(&ctx, 32, 32);
Gradient_Noise(&ctx, BitmapColor_RGB(0x40, 0x30, 0x20), 6, 0, 0, ctx.width, ctx.height);
Context2D_MakeTexture(&touchBgTex, &ctx);
Context2D_Free(&ctx);
// Tile the texture to fill the entire screen
int tilesX = (320 + ctx.width - 1) / ctx.width;
int tilesY = (240 + ctx.height - 1) / ctx.height;
touchBgTex.Width *= tilesX; touchBgTex.Height *= tilesY;
touchBgTex.uv.U2 *= tilesX; touchBgTex.uv.V2 *= tilesY;
#endif
Event_Register_(&ChatEvents.FontChanged, NULL, OnFontChanged);
Event_Register_(&GfxEvents.ContextLost, NULL, OnContextLost);
Event_Register_(&GfxEvents.ContextRecreated, NULL, OnContextRecreated);

View File

@ -114,6 +114,7 @@ cc_bool Launcher_StartGame(const cc_string* user, const cc_string* mppass, const
if (res) { Logger_SysWarn(res, "starting game"); return false; }
Launcher_ShouldExit = Platform_SingleProcess || Options_GetBool(LOPT_AUTO_CLOSE, false);
return true;
}
@ -235,6 +236,8 @@ void Launcher_Run(void) {
}
#endif
enum Screen3DS scr = Window_3DS_SetRenderScreen(BOTTOM_SCREEN);
Drawer2D_Component.Init();
SystemFonts_Component.Init();
Drawer2D.BitmappedText = false;
@ -295,6 +298,8 @@ void Launcher_Run(void) {
if (Window_Main.Exists) Window_RequestClose();
#endif
Window_3DS_SetRenderScreen(scr);
}
@ -527,17 +532,43 @@ void Launcher_DrawTitle(struct FontDesc* font, const char* text, struct Context2
cc_string title = String_FromReadonly(text);
struct DrawTextArgs args;
int x;
int y;
/* Skip dragging logo when very small window to save space */
if (Window_Main.Height < 240) return;
#ifdef __3DS__
/* Put title on top screen */
enum Screen3DS scr = Window_3DS_SetRenderScreen(TOP_SCREEN);
struct Bitmap bmp;
struct Context2D topCtx;
ctx = &topCtx;
bmp.width = max(Window_Main.Width, 1);
bmp.height = max(Window_Main.Height, 1);
Window_AllocFramebuffer(&bmp);
Context2D_Wrap(ctx, &bmp);
Launcher_DrawBackgroundAll(ctx);
#endif
DrawTextArgs_Make(&args, &title, font, false);
x = ctx->width / 2 - Drawer2D_TextWidth(&args) / 2;
y = 0;
#ifdef __3DS__
// vertically center the title
y = ctx->height / 2 - Drawer2D_TextHeight(&args) / 2;
#endif
Drawer2D.Colors['f'] = BITMAPCOLOR_BLACK;
Context2D_DrawText(ctx, &args, x + Display_ScaleX(4), Display_ScaleY(4));
Context2D_DrawText(ctx, &args, x + Display_ScaleX(4), y + Display_ScaleY(4));
Drawer2D.Colors['f'] = BITMAPCOLOR_WHITE;
Context2D_DrawText(ctx, &args, x, 0);
Context2D_DrawText(ctx, &args, x, y);
#ifdef __3DS__
Window_DrawFramebuffer((Rect2D){ 0, 0, bmp.width, bmp.height });
Window_3DS_SetRenderScreen(scr);
#endif
}
void Launcher_MakeTitleFont(struct FontDesc* font) {

View File

@ -56,6 +56,10 @@ void Platform_Log(const char* msg, int len) {
write(STDOUT_FILENO, msg, len);
write(STDOUT_FILENO, "\n", 1);
// output to debug service (visible in Citra with log level set to "*:Debug", or on console via remote gdb)
svcOutputDebugString(msg, len);
svcOutputDebugString("\n", 1);
}
#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH + (time.tv_usec / 1000))

View File

@ -202,9 +202,11 @@ static void HUDScreen_ContextRecreated(void* screen) {
}
static int HUDScreen_LayoutHotbar(void) {
enum Screen3DS scr = Window_3DS_SetRenderScreen(BOTTOM_SCREEN);
struct HUDScreen* s = &HUDScreen_Instance;
s->hotbar.scale = Gui_GetHotbarScale();
Widget_Layout(&s->hotbar);
Window_3DS_SetRenderScreen(scr);
return s->hotbar.height;
}
@ -337,6 +339,7 @@ static void HUDScreen_BuildCrosshairsMesh(struct VertexTextured** ptr) {
/* Only top quarter of icons.png is used */
static struct Texture tex = { 0, Tex_Rect(0,0,0,0), Tex_UV(0.0f,0.0f, 15/256.0f,15/64.0f) };
int extent;
enum Screen3DS scr = Window_3DS_SetRenderScreen(TOP_SCREEN);
extent = (int)(CH_EXTENT * Gui_Scale(Window_Main.Height / 480.0f));
tex.x = (Window_Main.Width / 2) - extent;
@ -345,6 +348,8 @@ static void HUDScreen_BuildCrosshairsMesh(struct VertexTextured** ptr) {
tex.Width = extent * 2;
tex.Height = extent * 2;
Gfx_Make2DQuad(&tex, PACKEDCOL_WHITE, ptr);
Window_3DS_SetRenderScreen(scr);
}
static void HUDScreen_BuildMesh(void* screen) {
@ -369,6 +374,8 @@ static void HUDScreen_Render(void* screen, double delta) {
struct HUDScreen* s = (struct HUDScreen*)screen;
if (Game_HideGui) return;
enum Screen3DS scr = Window_3DS_SetRenderScreen(TOP_SCREEN);
Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED);
Gfx_BindDynamicVb(s->vb);
if (Gui.ShowFPS) Widget_Render2(&s->line1, 4);
@ -382,15 +389,18 @@ static void HUDScreen_Render(void* screen, double delta) {
/* TODO swap these two lines back */
}
if (Gui_GetBlocksWorld()) return;
Gfx_BindDynamicVb(s->vb);
Widget_Render2(&s->hotbar, 12);
if (!Gui_GetBlocksWorld()) {
Gfx_BindDynamicVb(s->vb);
Widget_Render2(&s->hotbar, 12);
if (Gui.IconsTex && !tablist_active) {
Gfx_BindTexture(Gui.IconsTex);
Gfx_BindDynamicVb(s->vb); /* Have to rebind for mobile right now... */
Gfx_DrawVb_IndexedTris(4);
if (Gui.IconsTex && !tablist_active) {
Gfx_BindTexture(Gui.IconsTex);
Gfx_BindDynamicVb(s->vb); /* Have to rebind for mobile right now... */
Gfx_DrawVb_IndexedTris(4);
}
}
Window_3DS_SetRenderScreen(scr);
}
static const struct ScreenVTABLE HUDScreen_VTABLE = {
@ -494,6 +504,8 @@ static void TabListOverlay_Layout(void* screen) {
int i, x, y, width = 0, height = 0;
int columns = Math_CeilDiv(s->usedCount, LIST_NAMES_PER_COLUMN);
enum Screen3DS scr = Window_3DS_SetRenderScreen(TOP_SCREEN);
for (i = 0; i < columns; i++)
{
width += TabListOverlay_GetColumnWidth(s, i);
@ -530,6 +542,8 @@ static void TabListOverlay_Layout(void* screen) {
s->title.horAnchor = ANCHOR_CENTRE;
s->title.yOffset = s->y + paddingY / 2;
Widget_Layout(&s->title);
Window_3DS_SetRenderScreen(scr);
}
static void TabListOverlay_AddName(struct TabListOverlay* s, EntityID id, int index) {
@ -804,6 +818,9 @@ static void TabListOverlay_Render(void* screen, double delta) {
PackedCol bottomCol = PackedCol_Make(50, 50, 50, 205);
if (Game_HideGui || !IsOnlyChatActive()) return;
enum Screen3DS scr = Window_3DS_SetRenderScreen(TOP_SCREEN);
Gfx_Draw2DGradient(s->x, s->y, s->width, s->height, topCol, bottomCol);
Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED);
@ -818,6 +835,8 @@ static void TabListOverlay_Render(void* screen, double delta) {
Gfx_DrawVb_IndexedTris_Range(4, offset);
offset += 4;
}
Window_3DS_SetRenderScreen(scr);
}
static void TabListOverlay_Free(void* screen) {
@ -1152,9 +1171,11 @@ static void ChatScreen_DrawChat(struct ChatScreen* s, double delta) {
#ifdef CC_BUILD_TOUCH
if (!Input_TouchMode) return;
enum Screen3DS scr = Window_3DS_SetRenderScreen(BOTTOM_SCREEN);
Elem_Render(&s->more, delta);
Elem_Render(&s->send, delta);
Elem_Render(&s->cancel, delta);
Window_3DS_SetRenderScreen(scr);
#endif
}
}
@ -1218,6 +1239,8 @@ static void ChatScreen_BuildMesh(void* screen) {
}
static void ChatScreen_Layout(void* screen) {
enum Screen3DS scr = Window_3DS_SetRenderScreen(TOP_SCREEN);
struct ChatScreen* s = (struct ChatScreen*)screen;
if (ChatScreen_ChatUpdateFont(s)) ChatScreen_Redraw(s);
@ -1248,6 +1271,8 @@ static void ChatScreen_Layout(void* screen) {
s->smallAnnouncement.yOffset = Window_Main.Height / 20;
Widget_Layout(&s->smallAnnouncement);
Window_3DS_SetRenderScreen(scr);
#ifdef CC_BUILD_TOUCH
if (Window_Main.SoftKeyboard == SOFT_KEYBOARD_SHIFT) {
Widget_SetLocation(&s->send, ANCHOR_MAX, ANCHOR_MAX, 10, 60);
@ -1456,17 +1481,19 @@ static void ChatScreen_Init(void* screen) {
static void ChatScreen_Render(void* screen, double delta) {
struct ChatScreen* s = (struct ChatScreen*)screen;
enum Screen3DS scr = Window_3DS_SetRenderScreen(TOP_SCREEN);
if (Game_HideGui && s->grabsInput) {
Elem_Render(&s->input.base, delta);
}
if (Game_HideGui) return;
if (!Game_HideGui) {
if (s->grabsInput && !Gui.ClassicChat) {
ChatScreen_DrawChatBackground(s);
}
if (s->grabsInput && !Gui.ClassicChat) {
ChatScreen_DrawChatBackground(s);
ChatScreen_DrawChat(s, delta);
}
ChatScreen_DrawChat(s, delta);
Window_3DS_SetRenderScreen(scr);
}
static void ChatScreen_Free(void* screen) {

View File

@ -448,16 +448,21 @@ static void HotbarWidget_RenderEntries(struct HotbarWidget* w, int offset) {
}
static int HotbarWidget_Render2(void* widget, int offset) {
enum Screen3DS scr = Window_3DS_SetRenderScreen(BOTTOM_SCREEN);
struct HotbarWidget* w = (struct HotbarWidget*)widget;
HotbarWidget_RenderOutline(w, offset );
HotbarWidget_RenderEntries(w, offset + 8);
#ifdef CC_BUILD_TOUCH
if (!Input_TouchMode) return HOTBAR_MAX_VERTICES;
w->ellipsisTex.x = HotbarWidget_TileX(w, HOTBAR_MAX_INDEX) - w->ellipsisTex.Width / 2;
w->ellipsisTex.y = w->y + (w->height / 2) - w->ellipsisTex.Height / 2;
Texture_Render(&w->ellipsisTex);
if (Input_TouchMode) {
w->ellipsisTex.x = HotbarWidget_TileX(w, HOTBAR_MAX_INDEX) - w->ellipsisTex.Width / 2;
w->ellipsisTex.y = w->y + (w->height / 2) - w->ellipsisTex.Height / 2;
Texture_Render(&w->ellipsisTex);
}
#endif
Window_3DS_SetRenderScreen(scr);
return HOTBAR_MAX_VERTICES;
}

View File

@ -233,4 +233,14 @@ void GLContext_SetFpsLimit(cc_bool vsync, float minFrameMs);
/* Gets OpenGL context specific graphics information. */
void GLContext_GetApiInfo(cc_string* info);
#endif
enum Screen3DS { TOP_SCREEN, BOTTOM_SCREEN };
#ifdef __3DS__
/* Selects which screen on the 3DS to render to. Returns the previous screen */
enum Screen3DS Window_3DS_SetRenderScreen(enum Screen3DS screen);
#else
static inline
enum Screen3DS Window_3DS_SetRenderScreen(enum Screen3DS screen) { return TOP_SCREEN; }
#endif
#endif

View File

@ -12,9 +12,9 @@
#include "ExtMath.h"
#include <3ds.h>
static int touchActive, touchBegX, touchBegY;
static cc_bool launcherMode;
static Result irrst_result;
static enum Screen3DS renderScreen = TOP_SCREEN;
struct _DisplayData DisplayInfo;
struct _WindowData WindowInfo;
@ -32,7 +32,7 @@ void Window_Init(void) {
gfxInit(GSP_BGR8_OES, GSP_BGR8_OES, false);
//gfxInit(GSP_RGBA8_OES,GSP_RGBA8_OES,false);
consoleInit(GFX_BOTTOM, NULL);
//consoleInit(GFX_BOTTOM, NULL);
u16 width, height;
gfxGetFramebuffer(GFX_TOP, GFX_LEFT, &width, &height);
@ -48,6 +48,7 @@ void Window_Init(void) {
Window_Main.Focused = true;
Window_Main.Exists = true;
Input_SetTouchMode(true);
Input.Sources = INPUT_SOURCE_GAMEPAD;
irrst_result = irrstInit();
@ -58,6 +59,21 @@ void Window_Init(void) {
void Window_Free(void) { irrstExit(); }
enum Screen3DS Window_3DS_SetRenderScreen(enum Screen3DS screen) {
enum Screen3DS prev = renderScreen;
if (screen != prev)
{
renderScreen = screen;
DisplayInfo.Width = (screen == TOP_SCREEN) ? 400 : 320;
WindowInfo.Width = DisplayInfo.Width;
if (screen == TOP_SCREEN)
Gfx_3DS_DrawToTopScreen();
else
Gfx_3DS_DrawToBottomScreen();
}
return prev;
}
void Window_Create2D(int width, int height) { launcherMode = true; }
void Window_Create3D(int width, int height) { launcherMode = false; }
@ -112,27 +128,27 @@ static void ProcessJoystickInput(circlePosition* pos, double delta) {
}
static void ProcessTouchInput(int mods) {
static int currX, currY; // current touch position
touchPosition touch;
hidTouchRead(&touch);
touchActive = mods & KEY_TOUCH;
if (touchActive) {
// rescale X from [0, bottom_FB_width) to [0, top_FB_width)
int x = touch.px * Window_Main.Width / GSP_SCREEN_HEIGHT_BOTTOM;
int y = touch.py;
Pointer_SetPosition(0, x, y);
if (hidKeysDown() & KEY_TOUCH) { // stylus went down
currX = touch.px;
currY = touch.py;
Input_AddTouch(0, currX, currY);
}
// Set starting position for camera movement
if (hidKeysDown() & KEY_TOUCH) {
touchBegX = touch.px;
touchBegY = touch.py;
else if (mods & KEY_TOUCH) { // stylus is down
currX = touch.px;
currY = touch.py;
Input_UpdateTouch(0, currX, currY);
}
else if (hidKeysUp() & KEY_TOUCH) { // stylus was lifted
Input_RemoveTouch(0, currX, currY);
}
}
void Window_ProcessEvents(double delta) {
hidScanInput();
/* TODO implement */
if (!aptMainLoop()) {
Window_Main.Exists = false;
Window_RequestClose();
@ -141,8 +157,7 @@ void Window_ProcessEvents(double delta) {
u32 mods = hidKeysDown() | hidKeysHeld();
HandleButtons(mods);
Input_SetNonRepeatable(CCMOUSE_L, mods & KEY_TOUCH);
ProcessTouchInput(mods);
if (Input.RawMode) {
@ -163,33 +178,29 @@ void Cursor_SetPosition(int x, int y) { } // Makes no sense for 3DS
void Window_EnableRawMouse(void) { Input.RawMode = true; }
void Window_DisableRawMouse(void) { Input.RawMode = false; }
void Window_UpdateRawMouse(void) {
if (!touchActive) return;
touchPosition touch;
hidTouchRead(&touch);
Event_RaiseRawMove(&PointerEvents.RawMoved,
touch.px - touchBegX, touch.py - touchBegY);
touchBegX = touch.px;
touchBegY = touch.py;
}
void Window_UpdateRawMouse(void) { }
/*########################################################################################################################*
*------------------------------------------------------Framebuffer--------------------------------------------------------*
*#########################################################################################################################*/
static struct Bitmap fb_bmp;
static struct Bitmap top_fb_bmp;
static struct Bitmap bottom_fb_bmp;
void Window_AllocFramebuffer(struct Bitmap* bmp) {
bmp->scan0 = (BitmapCol*)Mem_Alloc(bmp->width * bmp->height, 4, "window pixels");
fb_bmp = *bmp;
if (renderScreen == TOP_SCREEN) {
top_fb_bmp = *bmp;
}
else {
bottom_fb_bmp = *bmp;
}
}
void Window_DrawFramebuffer(Rect2D r) {
u16 width, height;
gfxSetDoubleBuffering(GFX_TOP, false);
u8* fb = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, &width, &height);
gfxScreen_t screen = (renderScreen == TOP_SCREEN) ? GFX_TOP : GFX_BOTTOM;
gfxSetDoubleBuffering(screen, false);
u8* fb = gfxGetFramebuffer(screen, GFX_LEFT, &width, &height);
struct Bitmap *bmp = (renderScreen == TOP_SCREEN) ? &top_fb_bmp : &bottom_fb_bmp;
// SRC y = 0 to 240
// SRC x = 0 to 400
// DST X = 0 to 240
@ -198,7 +209,7 @@ void Window_DrawFramebuffer(Rect2D r) {
for (int y = r.y; y < r.y + r.Height; y++)
for (int x = r.x; x < r.x + r.Width; x++)
{
BitmapCol color = Bitmap_GetPixel(&fb_bmp, x, y);
BitmapCol color = Bitmap_GetPixel(bmp, x, y);
int addr = (width - 1 - y + x * width) * 3; // TODO -1 or not
fb[addr+0] = BitmapCol_B(color);
fb[addr+1] = BitmapCol_G(color);
@ -209,10 +220,12 @@ void Window_DrawFramebuffer(Rect2D r) {
gfxFlushBuffers();
//gfxSwapBuffers();
// TODO: tearing??
/*
gfxSetDoubleBuffering(GFX_TOP, false);
gfxScreenSwapBuffers(GFX_TOP, true);
gfxSetDoubleBuffering(GFX_TOP, true);
gfxScreenSwapBuffers(GFX_BOTTOM, true);
*/
}
void Window_FreeFramebuffer(struct Bitmap* bmp) {