GTK: make OSD scalable (#769)

* gtk: make OSD scalable

* Scale save slot indicator (oops), make text outlines look smoother, use
larger font when not scaling

* Save and load HUD layout, prefer raster font on low resolution, select
vector font size close to raster one, make OSDCLASS::scale floating point

* Build fix

* Add reset HUD layout action, only require fontconfig if libagg is found.

* Try another font in case we could not locate monospace

* Detect screen bytes per pixel instead of hardcoding it, define
AGG2D_USE_VECTORFONTS if fontconfig is found.

* Different pixel formats are handled by different draw target
implementations
This commit is contained in:
Max Fedotov 2024-02-14 11:20:57 +03:00 committed by GitHub
parent 6508c2b115
commit 45738beb88
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 470 additions and 121 deletions

View File

@ -1370,6 +1370,17 @@ AGG2D_TEMPLATE void TAGG2D::text(double x, double y, const wchar_t* str, unsigne
}
}
AGG2D_TEMPLATE double TAGG2D::textWidth(const char* str)
{
return textWidth(str, (unsigned int)strlen(str));
}
AGG2D_TEMPLATE void TAGG2D::text(double x, double y, const char* str, bool roundOff, double dx, double dy)
{
text(x, y, str, (unsigned int)strlen(str), roundOff, dx, dy);
}
#endif
//------------------------------------------------------------------------
@ -1945,11 +1956,11 @@ AGG2D_TEMPLATE void TAGG2D::render(FontRasterizer& ras, FontScanline& sl)
{
if(m_blendMode == BlendAlpha)
{
Agg2DRenderer::render(*this, m_renBase, m_renSolid, ras, sl);
Agg2DRenderer<PixFormatSet, PixFormatSet>::render(*this, m_renBase, m_renSolid, ras, sl);
}
else
{
Agg2DRenderer::render(*this, m_renBaseComp, m_renSolidComp, ras, sl);
Agg2DRenderer<PixFormatSet, PixFormatSet>::render(*this, m_renBaseComp, m_renSolidComp, ras, sl);
}
}

View File

@ -50,13 +50,23 @@ static s64 hudTimer;
static void SetHudDummy (HudCoordinates *hud)
{
hud->x=666;
hud->y=666;
hud->x=-666;
hud->y=-666;
}
static bool IsHudDummy (HudCoordinates *hud)
{
return (hud->x == 666 && hud->y == 666);
return (hud->x == -666 && hud->y == -666);
}
static int ScreenWidth()
{
return 256*osd->scale;
}
static int ScreenHeight()
{
return 192*osd->scale;
}
template<typename T>
@ -64,21 +74,47 @@ static T calcY(T y) // alters a GUI element y coordinate as necessary to obey sw
{
if(osd->singleScreen)
{
if(y >= 192)
y -= 192;
if(y >= ScreenHeight())
y -= ScreenHeight();
if(osd->swapScreens)
y += 192;
y += ScreenHeight();
}
else if(osd->swapScreens)
{
if(y >= 192)
y -= 192;
if(y >= ScreenHeight())
y -= ScreenHeight();
else
y += 192;
y += ScreenHeight();
}
return y;
}
static void RenderTextAutoVector(double x, double y, const std::string& str, bool shadow = true, double shadowOffset = 1.0)
{
#ifdef AGG2D_USE_VECTORFONTS
bool render_vect = false;
if(osd)
if(osd->useVectorFonts)
render_vect = true;
if(render_vect)
{
if(shadow)
aggDraw.hud->renderVectorFontTextDropshadowed(x, y, str, shadowOffset);
else
aggDraw.hud->renderVectorFontText(x, y, str);
}
else
{
#endif
if(shadow)
aggDraw.hud->renderTextDropshadowed(x, y, str);
else
aggDraw.hud->renderText(x, y, str);
#ifdef AGG2D_USE_VECTORFONTS
}
#endif
}
void EditHud(s32 x, s32 y, HudStruct *hudstruct) {
u32 i = 0;
@ -108,8 +144,10 @@ void EditHud(s32 x, s32 y, HudStruct *hudstruct) {
//sanity checks
if(hud.x < 0) hud.x = 0;
if(hud.y < 0) hud.y = 0;
if(hud.x > 245)hud.x = 245; //margins
if(hud.y > 384-16)hud.y = 384-16;
if(hud.x > ScreenWidth()-11*osd->scale)
hud.x = ScreenWidth()-11*osd->scale; //margins
if(hud.y > ScreenHeight()*2-16*osd->scale)
hud.y = ScreenHeight()*2-16*osd->scale;
if(hud.clicked)
{
@ -136,45 +174,47 @@ void HudClickRelease(HudStruct *hudstruct) {
void HudStruct::reset()
{
double sc=(osd ? osd->scale : 1.0);
FpsDisplay.x=0;
FpsDisplay.y=5;
FpsDisplay.xsize=166;
FpsDisplay.ysize=10;
FpsDisplay.y=5*sc;
FpsDisplay.xsize=166*sc;
FpsDisplay.ysize=10*sc;
FrameCounter.x=0;
FrameCounter.y=25;
FrameCounter.xsize=60;
FrameCounter.ysize=10;
FrameCounter.y=25*sc;
FrameCounter.xsize=60*sc;
FrameCounter.ysize=10*sc;
InputDisplay.x=0;
InputDisplay.y=45;
InputDisplay.xsize=220;
InputDisplay.ysize=10;
InputDisplay.y=45*sc;
InputDisplay.xsize=220*sc;
InputDisplay.ysize=10*sc;
GraphicalInputDisplay.x=8;
GraphicalInputDisplay.y=328;
GraphicalInputDisplay.xsize=102;
GraphicalInputDisplay.ysize=50;
GraphicalInputDisplay.x=8*sc;
GraphicalInputDisplay.y=328*sc;
GraphicalInputDisplay.xsize=102*sc;
GraphicalInputDisplay.ysize=50*sc;
LagFrameCounter.x=0;
LagFrameCounter.y=65;
LagFrameCounter.xsize=30;
LagFrameCounter.ysize=10;
LagFrameCounter.y=65*sc;
LagFrameCounter.xsize=30*sc;
LagFrameCounter.ysize=10*sc;
Microphone.x=0;
Microphone.y=85;
Microphone.xsize=20;
Microphone.ysize=10;
Microphone.y=85*sc;
Microphone.xsize=20*sc;
Microphone.ysize=10*sc;
RTCDisplay.x=0;
RTCDisplay.y=105;
RTCDisplay.xsize=220;
RTCDisplay.ysize=10;
RTCDisplay.y=105*sc;
RTCDisplay.xsize=220*sc;
RTCDisplay.ysize=10*sc;
SavestateSlots.x = 8;
SavestateSlots.y = 160;
SavestateSlots.xsize = 240;
SavestateSlots.ysize = 24;
SavestateSlots.x = 8*sc;
SavestateSlots.y = 160*sc;
SavestateSlots.xsize = 240*sc;
SavestateSlots.ysize = 24*sc;
#ifdef _MSC_VER
#define AGG_OSD_SETTING(which,comp) which.comp = GetPrivateProfileInt("HudEdit", #which "." #comp, which.comp, IniName);
@ -186,6 +226,51 @@ void HudStruct::reset()
clicked = false;
}
void HudStruct::rescale(double oldScale, double newScale)
{
double sc=newScale/oldScale;
FpsDisplay.x*=sc;
FpsDisplay.y*=sc;
FpsDisplay.xsize*=sc;
FpsDisplay.ysize*=sc;
FrameCounter.x*=sc;
FrameCounter.y*=sc;
FrameCounter.xsize*=sc;
FrameCounter.ysize*=sc;
InputDisplay.x*=sc;
InputDisplay.y*=sc;
InputDisplay.xsize*=sc;
InputDisplay.ysize*=sc;
GraphicalInputDisplay.x*=sc;
GraphicalInputDisplay.y*=sc;
GraphicalInputDisplay.xsize*=sc;
GraphicalInputDisplay.ysize*=sc;
LagFrameCounter.x*=sc;
LagFrameCounter.y*=sc;
LagFrameCounter.xsize*=sc;
LagFrameCounter.ysize*=sc;
Microphone.x*=sc;
Microphone.y*=sc;
Microphone.xsize*=sc;
Microphone.ysize*=sc;
RTCDisplay.x*=sc;
RTCDisplay.y*=sc;
RTCDisplay.xsize*=sc;
RTCDisplay.ysize*=sc;
SavestateSlots.x*=sc;
SavestateSlots.y*=sc;
SavestateSlots.xsize*=sc;
SavestateSlots.ysize*=sc;
}
static void joyFill(int n) {
bool pressedForGame = NDS_getFinalUserInput().buttons.array[n];
@ -235,8 +320,8 @@ static void drawPad(double x, double y, double ratio) {
// aligning to odd half-pixel boundaries prevents agg2d from blurring thin straight lines
x = floor(x) + 0.5;
y = floor(calcY(y)) + 0.5;
double xc = 41 - 0.5;
double yc = 20 - 0.5;
double xc = 41*osd->scale - 0.5;
double yc = 20*osd->scale - 0.5;
aggDraw.hud->lineColor(128,128,128,255);
@ -252,12 +337,12 @@ static void drawPad(double x, double y, double ratio) {
aggDraw.hud->roundedRect (screenLeft, screenTop, screenRight, screenBottom, 1);
joyEllipse(.89,.45,xc,yc,x,y,ratio,1,6);//B
joyEllipse(.89,.22,xc,yc,x,y,ratio,1,3);//X
joyEllipse(.83,.34,xc,yc,x,y,ratio,1,4);//Y
joyEllipse(.95,.34,xc,yc,x,y,ratio,1,5);//A
joyEllipse(.82,.716,xc,yc,x,y,ratio,.5,7);//Start
joyEllipse(.82,.842,xc,yc,x,y,ratio,.5,8);//Select
joyEllipse(.89,.45,xc,yc,x,y,ratio,osd->scale,6);//B
joyEllipse(.89,.22,xc,yc,x,y,ratio,osd->scale,3);//X
joyEllipse(.83,.34,xc,yc,x,y,ratio,osd->scale,4);//Y
joyEllipse(.95,.34,xc,yc,x,y,ratio,osd->scale,5);//A
joyEllipse(.82,.716,xc,yc,x,y,ratio,osd->scale * .5,7);//Start
joyEllipse(.82,.842,xc,yc,x,y,ratio,osd->scale * .5,8);//Select
double dpadPoints [][2] = {
@ -311,29 +396,29 @@ static void drawPad(double x, double y, double ratio) {
// touch pad
{
BOOL gameTouchOn = nds.isTouch;
double gameTouchX = screenLeft+1 + (nds.scr_touchX * 0.0625) * (screenRight - screenLeft - 2) / 256.0;
double gameTouchY = screenTop+1 + (nds.scr_touchY * 0.0625) * (screenBottom - screenTop - 2) / 192.0;
double gameTouchX = screenLeft+1 + (nds.scr_touchX * osd->scale * 0.0625) * (screenRight - screenLeft - 2) / (double)ScreenWidth();
double gameTouchY = screenTop+1 + (nds.scr_touchY * osd->scale * 0.0625) * (screenBottom - screenTop - 2) / (double)ScreenHeight();
bool physicalTouchOn = NDS_getRawUserInput().touch.isTouch;
double physicalTouchX = screenLeft+1 + (NDS_getRawUserInput().touch.touchX * 0.0625) * (screenRight - screenLeft - 2) / 256.0;
double physicalTouchY = screenTop+1 + (NDS_getRawUserInput().touch.touchY * 0.0625) * (screenBottom - screenTop - 2) / 192.0;
double physicalTouchX = screenLeft+1 + (NDS_getRawUserInput().touch.touchX * osd->scale * 0.0625) * (screenRight - screenLeft - 2) / (double)ScreenWidth();
double physicalTouchY = screenTop+1 + (NDS_getRawUserInput().touch.touchY * osd->scale * 0.0625) * (screenBottom - screenTop - 2) / (double)ScreenHeight();
if(gameTouchOn && physicalTouchOn && gameTouchX == physicalTouchX && gameTouchY == physicalTouchY)
{
aggDraw.hud->fillColor(0,0,0,255);
aggDraw.hud->ellipse(gameTouchX, gameTouchY, ratio*0.37, ratio*0.37);
aggDraw.hud->ellipse(gameTouchX, gameTouchY, osd->scale*ratio*0.37, osd->scale*ratio*0.37);
}
else
{
if(physicalTouchOn)
{
aggDraw.hud->fillColor(0,0,0,128);
aggDraw.hud->ellipse(physicalTouchX, physicalTouchY, ratio*0.5, ratio*0.5);
aggDraw.hud->ellipse(physicalTouchX, physicalTouchY, osd->scale*ratio*0.5, osd->scale*ratio*0.5);
aggDraw.hud->fillColor(0,255,0,255);
aggDraw.hud->ellipse(physicalTouchX, physicalTouchY, ratio*0.37, ratio*0.37);
aggDraw.hud->ellipse(physicalTouchX, physicalTouchY, osd->scale*ratio*0.37, osd->scale*ratio*0.37);
}
if(gameTouchOn)
{
aggDraw.hud->fillColor(255,0,0,255);
aggDraw.hud->ellipse(gameTouchX, gameTouchY, ratio*0.37, ratio*0.37);
aggDraw.hud->ellipse(gameTouchX, gameTouchY, osd->scale*ratio*0.37, osd->scale*ratio*0.37);
}
}
}
@ -380,7 +465,7 @@ static void TextualInputDisplay() {
std::string str(buttonChars+i, 2);
str[1] = '\0';
aggDraw.hud->renderTextDropshadowed(x, calcY(Hud.InputDisplay.y), str);
RenderTextAutoVector(x, calcY(Hud.InputDisplay.y), str, true, osd ? osd->scale : 1);
}
// touch pad
@ -396,7 +481,7 @@ static void TextualInputDisplay() {
{
sprintf(str, "%d,%d", gameTouchX, gameTouchY);
aggDraw.hud->lineColor(255,255,255,255);
aggDraw.hud->renderTextDropshadowed(x, calcY(Hud.InputDisplay.y), str);
RenderTextAutoVector(x, calcY(Hud.InputDisplay.y), str, true, osd ? osd->scale : 1);
}
else
{
@ -404,13 +489,13 @@ static void TextualInputDisplay() {
{
sprintf(str, "%d,%d", gameTouchX, gameTouchY);
aggDraw.hud->lineColor(255,48,48,255);
aggDraw.hud->renderTextDropshadowed(x, calcY(Hud.InputDisplay.y)-(physicalTouchOn?8:0), str);
RenderTextAutoVector(x, calcY(Hud.InputDisplay.y)-(physicalTouchOn?8:0), str, true, osd ? osd->scale : 1);
}
if(physicalTouchOn)
{
sprintf(str, "%d,%d", physicalTouchX, physicalTouchY);
aggDraw.hud->lineColor(0,192,0,255);
aggDraw.hud->renderTextDropshadowed(x, calcY(Hud.InputDisplay.y)+(gameTouchOn?8:0), str);
RenderTextAutoVector(x, calcY(Hud.InputDisplay.y)+(gameTouchOn?8:0), str, true, osd ? osd->scale : 1);
}
}
}
@ -418,10 +503,10 @@ static void TextualInputDisplay() {
static void OSD_HandleTouchDisplay() {
// note: calcY should not be used in this function.
aggDraw.hud->lineWidth(1.0);
aggDraw.hud->lineWidth(osd->scale);
temptouch.X = NDS_getRawUserInput().touch.touchX >> 4;
temptouch.Y = NDS_getRawUserInput().touch.touchY >> 4;
temptouch.X = (NDS_getRawUserInput().touch.touchX >> 4) * osd->scale;
temptouch.Y = (NDS_getRawUserInput().touch.touchY >> 4) * osd->scale;
if(touchshadow) {
@ -432,27 +517,27 @@ static void OSD_HandleTouchDisplay() {
temptouch = touch[i];
if(temptouch.X != 0 || temptouch.Y != 0) {
aggDraw.hud->lineColor(0, 255, 0, touchalpha[i]);
aggDraw.hud->line(temptouch.X - 256, temptouch.Y + 192, temptouch.X + 256, temptouch.Y + 192); //horiz
aggDraw.hud->line(temptouch.X, temptouch.Y - 256, temptouch.X, temptouch.Y + 384); //vert
aggDraw.hud->line(temptouch.X - ScreenWidth(), temptouch.Y + ScreenHeight(), temptouch.X + ScreenWidth(), temptouch.Y + ScreenHeight()); //horiz
aggDraw.hud->line(temptouch.X, temptouch.Y - ScreenWidth(), temptouch.X, temptouch.Y + ScreenHeight()*2); //vert
aggDraw.hud->fillColor(0, 0, 0, touchalpha[i]);
aggDraw.hud->rectangle(temptouch.X-1, temptouch.Y + 192-1, temptouch.X+1, temptouch.Y + 192+1);
aggDraw.hud->rectangle(temptouch.X-1, temptouch.Y + ScreenHeight()-1, temptouch.X+1, temptouch.Y + ScreenHeight()+1);
}
}
}
else
if(NDS_getRawUserInput().touch.isTouch) {
aggDraw.hud->lineColor(0, 255, 0, 128);
aggDraw.hud->line(temptouch.X - 256, temptouch.Y + 192, temptouch.X + 256, temptouch.Y + 192); //horiz
aggDraw.hud->line(temptouch.X, temptouch.Y - 256, temptouch.X, temptouch.Y + 384); //vert
aggDraw.hud->line(temptouch.X - ScreenWidth(), temptouch.Y + ScreenHeight(), temptouch.X + ScreenWidth(), temptouch.Y + ScreenHeight()); //horiz
aggDraw.hud->line(temptouch.X, temptouch.Y - ScreenWidth(), temptouch.X, temptouch.Y + ScreenHeight()*2); //vert
}
if(nds.isTouch)
{
temptouch.X = nds.scr_touchX / 16;
temptouch.Y = nds.scr_touchY / 16;
temptouch.X = nds.scr_touchX / 16 * osd->scale;
temptouch.Y = nds.scr_touchY / 16 * osd->scale;
aggDraw.hud->lineColor(255, 0, 0, 128);
aggDraw.hud->line(temptouch.X - 256, temptouch.Y + 192, temptouch.X + 256, temptouch.Y + 192); //horiz
aggDraw.hud->line(temptouch.X, temptouch.Y - 256, temptouch.X, temptouch.Y + 384); //vert
aggDraw.hud->line(temptouch.X - ScreenWidth(), temptouch.Y + ScreenHeight(), temptouch.X + ScreenWidth(), temptouch.Y + ScreenHeight()); //horiz
aggDraw.hud->line(temptouch.X, temptouch.Y - ScreenWidth(), temptouch.X, temptouch.Y + ScreenHeight()*2); //vert
}
}
@ -476,24 +561,24 @@ static void DrawStateSlots(){
if(alpha!=0)
{
aggDraw.hud->lineWidth(1.0);
aggDraw.hud->lineWidth(osd->scale);
aggDraw.hud->lineColor(0, 0, 0, alpha);
aggDraw.hud->fillColor(255, 255, 255, alpha);
for ( int i = 0, xpos=0; i < 10; xpos=xpos+24) {
for ( int i = 0, xpos=0; i < 10; xpos=xpos+24*osd->scale) {
int yheight=0;
aggDraw.hud->fillLinearGradient(xloc + xpos, yloc - yheight, xloc + 22 + xpos, yloc + 20 + yheight+20, agg::rgba8(100,200,255,alpha), agg::rgba8(255,255,255,0));
aggDraw.hud->fillLinearGradient(xloc + xpos, yloc - yheight, xloc + 22*osd->scale + xpos, yloc + 20*osd->scale + yheight+20*osd->scale, agg::rgba8(100,200,255,alpha), agg::rgba8(255,255,255,0));
if(lastSaveState == i) {
yheight = 5;
aggDraw.hud->fillLinearGradient(xloc + xpos, yloc - yheight, 22 + xloc + xpos, yloc + 20 + yheight+20, agg::rgba8(100,255,255,alpha), agg::rgba8(255,255,255,0));
yheight = 5*osd->scale;
aggDraw.hud->fillLinearGradient(xloc + xpos, yloc - yheight, 22*osd->scale + xloc + xpos, yloc + 20*osd->scale + yheight+20*osd->scale, agg::rgba8(100,255,255,alpha), agg::rgba8(255,255,255,0));
}
aggDraw.hud->rectangle(xloc + xpos , yloc - yheight, xloc + 22 + xpos , yloc + 20 + yheight);
aggDraw.hud->rectangle(xloc + xpos , yloc - yheight, xloc + 22*osd->scale + xpos , yloc + 20*osd->scale + yheight);
snprintf(number, 10, "%d", i);
aggDraw.hud->renderText(xloc + 1 + xpos + 4, yloc+4, std::string(number));
RenderTextAutoVector(xloc + osd->scale + xpos + 4*osd->scale, yloc+4*osd->scale, std::string(number), true, osd->scale);
i++;
}
}
@ -511,10 +596,10 @@ static void DrawEditableElementIndicators()
HudCoordinates &hud = Hud.hud(i);
aggDraw.hud->fillColor(0,0,0,0);
aggDraw.hud->lineColor(0,0,0,64);
aggDraw.hud->lineWidth(2.0);
aggDraw.hud->lineWidth(2.0*osd->scale);
aggDraw.hud->rectangle(hud.x,calcY(hud.y),hud.x+hud.xsize+1.0,calcY(hud.y)+hud.ysize+1.0);
aggDraw.hud->lineColor(255,hud.clicked?127:255,0,255);
aggDraw.hud->lineWidth(1.0);
aggDraw.hud->lineWidth(osd->scale);
aggDraw.hud->rectangle(hud.x-0.5,calcY(hud.y)-0.5,hud.x+hud.xsize+0.5,calcY(hud.y)+hud.ysize+0.5);
i++;
}
@ -624,9 +709,11 @@ OSDCLASS::OSDCLASS(u8 core)
singleScreen = false;
swapScreens = false;
scale = 1.0;
needUpdate = false;
#ifdef AGG2D_USE_VECTORFONTS
useVectorFonts = false;
#endif
if (core==0)
strcpy(name,"Core A");
else
@ -707,7 +794,7 @@ void OSDCLASS::update()
for (int i=0; i < lastLineText; i++)
{
aggDraw.hud->lineColor(lineColor[i]);
aggDraw.hud->renderTextDropshadowed(lineText_x,lineText_y+(i*16),lineText[i]);
RenderTextAutoVector(lineText_x, lineText_y+(i*16), lineText[i], true, osd->scale);
}
}
else
@ -789,7 +876,7 @@ void OSDCLASS::addFixed(u16 x, u16 y, const char *fmt, ...)
va_end(list);
aggDraw.hud->lineColor(255,255,255);
aggDraw.hud->renderTextDropshadowed(x,calcY(y),msg);
RenderTextAutoVector(x, calcY(y), msg, true, osd->scale);
needUpdate = true;
}

View File

@ -73,6 +73,7 @@ public:
HudCoordinates &hud(int i) { return ((HudCoordinates*)this)[i]; }
void reset();
void rescale(double oldScale, double newScale);
int fps, fps3d, cpuload[2], cpuloopIterationCount;
char rtcString[25];
@ -111,6 +112,10 @@ public:
char name[7]; // for debuging
bool singleScreen;
bool swapScreens;
double scale;
#ifdef AGG2D_USE_VECTORFONTS
bool useVectorFonts;
#endif
OSDCLASS(u8 core);
~OSDCLASS();

View File

@ -118,20 +118,17 @@ static void Agg_init_fonts()
AggDraw_Desmume aggDraw;
#if defined(WIN32) || defined(HOST_LINUX)
T_AGG_RGBA agg_targetScreen(0, 256, 384, 1024);
#else
T_AGG_RGB555 agg_targetScreen(0, 256, 384, 1512);
#endif
T_AGG_RGBA agg_targetScreen_32bit(0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2, GPU_FRAMEBUFFER_NATIVE_WIDTH*4);
T_AGG_RGB555 agg_targetScreen_16bit(0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2, GPU_FRAMEBUFFER_NATIVE_WIDTH*2);
static u32 luaBuffer[256*192*2];
T_AGG_RGBA agg_targetLua((u8*)luaBuffer, 256, 384, 1024);
static std::vector<u32> luaBuffer(GPU_FRAMEBUFFER_NATIVE_WIDTH*GPU_FRAMEBUFFER_NATIVE_HEIGHT*2);
T_AGG_RGBA agg_targetLua((u8*)luaBuffer.data(), GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2, GPU_FRAMEBUFFER_NATIVE_WIDTH*4);
static u32 hudBuffer[256*192*2];
T_AGG_RGBA agg_targetHud((u8*)hudBuffer, 256, 384, 1024);
static std::vector<u32> hudBuffer(GPU_FRAMEBUFFER_NATIVE_WIDTH*GPU_FRAMEBUFFER_NATIVE_HEIGHT*2);
T_AGG_RGBA agg_targetHud((u8*)hudBuffer.data(), GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT*2, GPU_FRAMEBUFFER_NATIVE_WIDTH*4);
static AggDrawTarget* targets[] = {
&agg_targetScreen,
&agg_targetScreen_32bit,
&agg_targetHud,
&agg_targetLua,
};
@ -139,6 +136,16 @@ static AggDrawTarget* targets[] = {
void Agg_init()
{
Agg_init_fonts();
switch(aggDraw.screenBytesPerPixel)
{
case 2:
targets[0]=&agg_targetScreen_16bit;
break;
case 4:
targets[0]=&agg_targetScreen_32bit;
break;
}
aggDraw.screen = targets[0];
aggDraw.hud = targets[1];
aggDraw.lua = targets[2];
@ -149,19 +156,35 @@ void Agg_init()
//and the more clever compositing isnt supported in non-windows
#ifdef WIN32
if(CommonSettings.single_core())
aggDraw.hud = &agg_targetScreen;
aggDraw.hud = aggDraw.screen;
#else
aggDraw.hud = &agg_targetScreen;
aggDraw.hud = aggDraw.screen;
#endif
aggDraw.hud->setFont("verdana18_bold");
}
AggDraw_Desmume::AggDraw_Desmume()
{
screenBytesPerPixel = 4;
}
void AggDraw_Desmume::setTarget(AggTarget newTarget)
{
target = targets[newTarget];
}
void Agg_setCustomSize(int w, int h)
{
hudBuffer.resize(w*h);
luaBuffer.resize(w*h);
if(aggDraw.screen)
aggDraw.screen->setDrawTargetDims(0, w, h, w*aggDraw.screenBytesPerPixel);
if(aggDraw.hud)
aggDraw.hud->setDrawTargetDims((u8*)hudBuffer.data(), w, h, w*4);
if(aggDraw.lua)
aggDraw.lua->setDrawTargetDims((u8*)luaBuffer.data(), w, h, w*4);
}
////temporary, just for testing the lib

View File

@ -243,6 +243,8 @@ public:
virtual void clear() = 0;
virtual void setDrawTargetDims(agg::int8u* buf, int width, int height, int stride) = 0;
virtual agg::rendering_buffer & buf() = 0;
//returns an image for this target. you must provide the pixel type, but if it is wrong,
@ -408,6 +410,9 @@ public:
virtual Agg2DBase::ImageResample imageResample() = 0;
static const agg::int8u* lookupFont(const std::string& name);
virtual void setFont(const std::string& name) = 0;
#ifdef AGG2D_USE_VECTORFONTS
virtual void setVectorFont(const std::string& fileName, int size, bool bold) = 0;
#endif
virtual void renderText(double dstX, double dstY, const std::string& str) = 0;
virtual void renderTextDropshadowed(double dstX, double dstY, const std::string& str)
{
@ -427,6 +432,30 @@ public:
lineColor(lineColorOld);
renderText(dstX,dstY,str);
}
#ifdef AGG2D_USE_VECTORFONTS
virtual void renderVectorFontText(double dstX, double dstY, const std::string& str) = 0;
virtual void renderVectorFontTextDropshadowed(double dstX, double dstY, const std::string& str, double shadowOffset = 1.0)
{
shadowOffset*=0.5;
AggColor lineColorOld = lineColor();
if(lineColorOld.r+lineColorOld.g+lineColorOld.b<192)
lineColor(255-lineColorOld.r,255-lineColorOld.g,255-lineColorOld.b);
else
lineColor(0,0,0);
fillColor(lineColor());
renderVectorFontText(dstX-shadowOffset,dstY-shadowOffset,str);
renderVectorFontText(dstX,dstY-shadowOffset,str);
renderVectorFontText(dstX+shadowOffset,dstY-shadowOffset,str);
renderVectorFontText(dstX-shadowOffset,dstY,str);
renderVectorFontText(dstX+shadowOffset,dstY,str);
renderVectorFontText(dstX-shadowOffset,dstY+shadowOffset,str);
renderVectorFontText(dstX,dstY+shadowOffset,str);
renderVectorFontText(dstX+shadowOffset,dstY+shadowOffset,str);
lineColor(lineColorOld);
fillColor(lineColor());
renderVectorFontText(dstX,dstY,str);
}
#endif
// Auxiliary
@ -459,6 +488,13 @@ public:
}
}
virtual void setDrawTargetDims(agg::int8u* buf, int width, int height, int stride)
{
BASE::attach(buf,width,height,stride);
BASE::viewport(0, 0, width-1, height-1, 0, 0, width-1, height-1, TAGG2D::Anisotropic);
}
virtual agg::rendering_buffer & buf() { dirty(); return BASE::buf(); } // buf() might not always require calling dirty()
typename BASE::MyImage image() { return BASE::MyImage(buf()); }
@ -578,6 +614,9 @@ public:
virtual void polyline(double* xy, int numPoints) {dirty(); BASE::polyline(xy, numPoints);};
virtual void setFont(const std::string& name) { BASE::font(lookupFont(name)); }
#ifdef AGG2D_USE_VECTORFONTS
virtual void setVectorFont(const std::string& fileName, int size, bool bold) {BASE::font(fileName.c_str(), size, bold); }
#endif
virtual void renderText(double dstX, double dstY, const std::string& str) {
dirty();
int height = BASE::font()[0];
@ -585,6 +624,13 @@ public:
int offset = height-base*2;
BASE::renderText(dstX, dstY + offset, str);
}
#ifdef AGG2D_USE_VECTORFONTS
virtual void renderVectorFontText(double dstX, double dstY, const std::string& str) {
dirty();
BASE::flipText(true);
BASE::text(dstX, dstY + BASE::fontHeight(), str.c_str());
}
#endif
// Path commands
virtual void resetPath() {BASE::resetPath();};
@ -659,15 +705,18 @@ enum AggTarget
class AggDraw_Desmume : public AggDraw
{
public:
AggDraw_Desmume();
void setTarget(AggTarget newTarget);
//void composite(void* dest);
AggDrawTarget *screen, *hud, *lua;
int screenBytesPerPixel;
};
extern AggDraw_Desmume aggDraw;
void Agg_init();
void Agg_setCustomSize(int w, int h);
struct font_type
{

View File

@ -97,6 +97,25 @@ void value<string>::save() {
g_key_file_set_string(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), this->mData.c_str());
}
/* class value<vector<int> > */
template<>
void value<vector<int> >::load() {
gsize l;
int* val = g_key_file_get_integer_list(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), &l, NULL);
if(val)
{
this->mData.resize(l);
std::copy(val, val+l, this->mData.begin());
g_free(val);
}
}
template<>
void value<vector<int> >::save() {
g_key_file_set_integer_list(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), this->mData.data(), this->mData.size());
}
/* class Config */
Config::Config()

View File

@ -49,6 +49,7 @@ OPT(hud_input, bool, false, HudDisplay, Input)
OPT(hud_graphicalInput, bool, false, HudDisplay, GraphicalInput)
OPT(hud_rtc, bool, false, HudDisplay, RTC)
OPT(hud_mic, bool, false, HudDisplay, Mic)
OPT(hud_layout, std::vector<int>, std::vector<int>(), HudDisplay, Layout)
/* Config */
OPT(fpslimiter, bool, true, Config, FpsLimiter)

View File

@ -31,6 +31,9 @@
#include <SDL.h>
#include <X11/Xlib.h>
#include <vector>
#ifdef AGG2D_USE_VECTORFONTS
#include <fontconfig/fontconfig.h>
#endif
#include "types.h"
#include "firmware.h"
@ -127,6 +130,15 @@ enum {
SUB_OBJ
};
#ifdef AGG2D_USE_VECTORFONTS
#define VECTOR_FONT_BASE_SIZE 16
static FcConfig* fontConfig;
static std::string vectorFontFile;
static std::string FindFontFile(const char* fontName, bool bold);
#endif
gboolean EmuLoop(gpointer data);
static AVOutX264 avout_x264;
@ -190,6 +202,9 @@ static void HudLagCounter(GSimpleAction *action, GVariant *parameter, gpointer u
static void HudRtc(GSimpleAction *action, GVariant *parameter, gpointer user_data);
static void HudMic(GSimpleAction *action, GVariant *parameter, gpointer user_data);
static void HudEditor(GSimpleAction *action, GVariant *parameter, gpointer user_data);
static void HudResetLayout(GSimpleAction *action, GVariant *parameter, gpointer user_data);
static void HudSaveLayout();
static void HudLoadLayout();
#endif
#ifdef DESMUME_GTK_FIRMWARE_BROKEN
static void SelectFirmwareFile(GSimpleAction *action, GVariant *parameter, gpointer user_data);
@ -247,6 +262,7 @@ static const GActionEntry app_entries[] = {
{ "hud_rtc", HudRtc, NULL, "false" },
{ "hud_mic", HudMic, NULL, "false" },
{ "hud_editor", HudEditor, NULL, "false" },
{ "hud_reset_layout", HudResetLayout},
#endif
// Config
@ -1449,7 +1465,7 @@ static void RedrawScreen() {
GPU->GetDisplayInfo().isCustomSizeRequested ? (u16*)(GPU->GetDisplayInfo().masterCustomBuffer) : GPU->GetDisplayInfo().masterNativeBuffer16,
(uint32_t *)video->GetSrcBufferPtr(), real_framebuffer_width * real_framebuffer_height * 2);
#ifdef HAVE_LIBAGG
aggDraw.hud->attach((u8*)video->GetSrcBufferPtr(), real_framebuffer_width, real_framebuffer_height * 2, 1024 * gpu_scale_factor);
aggDraw.hud->setDrawTargetDims((u8*)video->GetSrcBufferPtr(), real_framebuffer_width, real_framebuffer_height * 2, real_framebuffer_width * 4);
osd->update();
DrawHUD();
osd->clear();
@ -1471,33 +1487,33 @@ static gboolean rotoscaled_hudedit(gint x, gint y, gboolean start)
devX = x;
devY = y;
cairo_matrix_transform_point(&nds_screen.topscreen_matrix, &devX, &devY);
topX = devX;
topY = devY;
topX = devX * gpu_scale_factor;
topY = devY * gpu_scale_factor;
}
if (nds_screen.orientation != ORIENT_SINGLE || nds_screen.swap) {
devX = x;
devY = y;
cairo_matrix_transform_point(&nds_screen.touch_matrix, &devX, &devY);
botX = devX;
botY = devY;
botX = devX * gpu_scale_factor;
botY = devY * gpu_scale_factor;
}
if (topX >= 0 && topY >= 0 && topX < 256 && topY < 192) {
if (topX >= 0 && topY >= 0 && topX < real_framebuffer_width && topY < real_framebuffer_height) {
X = topX;
Y = topY + (nds_screen.swap ? 192 : 0);
Y = topY + (nds_screen.swap ? real_framebuffer_height : 0);
startScreen = 0;
} else if (botX >= 0 && botY >= 0 && botX < 256 && botY < 192) {
} else if (botX >= 0 && botY >= 0 && botX < real_framebuffer_width && botY < real_framebuffer_height) {
X = botX;
Y = botY + (nds_screen.swap ? 0 : 192);
Y = botY + (nds_screen.swap ? 0 : real_framebuffer_height);
startScreen = 1;
} else if (!start) {
if (startScreen == 0) {
X = CLAMP(topX, 0, 255);
Y = CLAMP(topY, 0, 191) + (nds_screen.swap ? 192 : 0);
X = CLAMP(topX, 0, real_framebuffer_width-1);
Y = CLAMP(topY, 0, real_framebuffer_height-1) + (nds_screen.swap ? real_framebuffer_height : 0);
} else {
X = CLAMP(botX, 0, 255);
Y = CLAMP(botY, 0, 191) + (nds_screen.swap ? 0 : 192);
X = CLAMP(botX, 0, real_framebuffer_width-1);
Y = CLAMP(botY, 0, real_framebuffer_height-1) + (nds_screen.swap ? 0 : real_framebuffer_height);
}
} else {
LOG("TopX=%d, TopY=%d, BotX=%d, BotY=%d\n", topX, topY, botX, botY);
@ -2098,6 +2114,7 @@ static void GraphicsSettingsDialog(GSimpleAction *action, GVariant *parameter, g
default:
break;
}
double old_scale_factor = gpu_scale_factor;
gpu_scale_factor = gtk_spin_button_get_value(wGPUScale);
if(gpu_scale_factor < GPU_SCALE_FACTOR_MIN)
gpu_scale_factor = GPU_SCALE_FACTOR_MIN;
@ -2109,6 +2126,21 @@ static void GraphicsSettingsDialog(GSimpleAction *action, GVariant *parameter, g
real_framebuffer_height = GPU_FRAMEBUFFER_NATIVE_HEIGHT * gpu_scale_factor;
GPU->SetCustomFramebufferSize(real_framebuffer_width, real_framebuffer_height);
video->SetSourceSize(real_framebuffer_width, real_framebuffer_height * 2);
#ifdef HAVE_LIBAGG
#ifdef AGG2D_USE_VECTORFONTS
if(vectorFontFile.size() > 0)
{
aggDraw.hud->setVectorFont(vectorFontFile, VECTOR_FONT_BASE_SIZE * gpu_scale_factor, true);
osd->useVectorFonts=(gpu_scale_factor >= 1.1);
}
else
osd->useVectorFonts=false;
#endif
Agg_setCustomSize(real_framebuffer_width, real_framebuffer_height*2);
osd->scale=gpu_scale_factor;
Hud.rescale(old_scale_factor, gpu_scale_factor);
HudSaveLayout();
#endif
CommonSettings.GFX3D_Renderer_TextureDeposterize = config.textureDeposterize = gtk_toggle_button_get_active(wPosterize);
CommonSettings.GFX3D_Renderer_TextureSmoothing = config.textureSmoothing = gtk_toggle_button_get_active(wSmoothing);
CommonSettings.GFX3D_Renderer_TextureScalingFactor = config.textureUpscale = scale;
@ -2773,6 +2805,8 @@ static void ToggleHudDisplay(hud_display_enum hudId, gboolean active)
break;
case HUD_DISPLAY_EDITOR:
HudEditorMode = active;
if(!active)
HudSaveLayout();
break;
default:
g_printerr("Unknown HUD toggle %u!", hudId);
@ -2799,6 +2833,60 @@ HudMacro(HudRtc, HUD_DISPLAY_RTC)
HudMacro(HudMic, HUD_DISPLAY_MIC)
HudMacro(HudEditor, HUD_DISPLAY_EDITOR)
static void HudResetLayout(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
Hud.reset();
HudSaveLayout();
}
static void HudSaveCoordsToVector(HudCoordinates* pCoords, int* pDest)
{
pDest[0]=pCoords->x;
pDest[1]=pCoords->y;
pDest[2]=pCoords->xsize;
pDest[3]=pCoords->ysize;
}
static void HudLoadCoordsFromVector(HudCoordinates* pCoords, int* pSrc)
{
pCoords->x=pSrc[0];
pCoords->y=pSrc[1];
pCoords->xsize=pSrc[2];
pCoords->ysize=pSrc[3];
}
static void HudSaveLayout()
{
std::vector<int> vec(8*4); //8 HudCoordinates
HudSaveCoordsToVector(&Hud.SavestateSlots, vec.data());
HudSaveCoordsToVector(&Hud.FpsDisplay, vec.data()+4);
HudSaveCoordsToVector(&Hud.FrameCounter, vec.data()+8);
HudSaveCoordsToVector(&Hud.InputDisplay, vec.data()+12);
HudSaveCoordsToVector(&Hud.GraphicalInputDisplay, vec.data()+16);
HudSaveCoordsToVector(&Hud.LagFrameCounter, vec.data()+20);
HudSaveCoordsToVector(&Hud.Microphone, vec.data()+24);
HudSaveCoordsToVector(&Hud.RTCDisplay, vec.data()+28);
config.hud_layout=vec;
}
static void HudLoadLayout()
{
std::vector<int> vec=config.hud_layout;
if(vec.size()==8*4)
{
HudLoadCoordsFromVector(&Hud.SavestateSlots, vec.data());
HudLoadCoordsFromVector(&Hud.FpsDisplay, vec.data()+4);
HudLoadCoordsFromVector(&Hud.FrameCounter, vec.data()+8);
HudLoadCoordsFromVector(&Hud.InputDisplay, vec.data()+12);
HudLoadCoordsFromVector(&Hud.GraphicalInputDisplay, vec.data()+16);
HudLoadCoordsFromVector(&Hud.LagFrameCounter, vec.data()+20);
HudLoadCoordsFromVector(&Hud.Microphone, vec.data()+24);
HudLoadCoordsFromVector(&Hud.RTCDisplay, vec.data()+28);
}
else
Hud.reset();
}
static void desmume_gtk_menu_view_hud(GtkApplication *app)
{
const struct {
@ -2998,6 +3086,10 @@ common_gtk_main(GApplication *app, gpointer user_data)
/* Init the hud / osd stuff */
#ifdef HAVE_LIBAGG
SDL_DisplayMode cur_mode;
if(!SDL_GetCurrentDisplayMode(0, &cur_mode))
aggDraw.screenBytesPerPixel = SDL_BYTESPERPIXEL(cur_mode.format);
Desmume_InitOnce();
Hud.reset();
osd = new OSDCLASS(-1);
@ -3067,6 +3159,20 @@ common_gtk_main(GApplication *app, gpointer user_data)
g_printerr("Using %d threads for video filter.\n", CommonSettings.num_cores);
GPU->SetCustomFramebufferSize(real_framebuffer_width, real_framebuffer_height);
video = new VideoFilter(real_framebuffer_width, real_framebuffer_height * 2, VideoFilterTypeID_None, CommonSettings.num_cores);
#ifdef HAVE_LIBAGG
#ifdef AGG2D_USE_VECTORFONTS
if(vectorFontFile.size() > 0)
{
aggDraw.hud->setVectorFont(vectorFontFile, VECTOR_FONT_BASE_SIZE * gpu_scale_factor, true);
osd->useVectorFonts=(gpu_scale_factor >= 1.1);
}
else
osd->useVectorFonts=false;
#endif
Agg_setCustomSize(real_framebuffer_width, real_framebuffer_height*2);
osd->scale=gpu_scale_factor;
HudLoadLayout();
#endif
/* Fetch the main elements from the window */
GtkBuilder *builder = gtk_builder_new_from_resource("/org/desmume/DeSmuME/main.ui");
@ -3601,7 +3707,9 @@ common_gtk_main(GApplication *app, gpointer user_data)
static void Teardown() {
delete video;
#ifdef HAVE_LIBAGG
HudSaveLayout();
#endif
config.save();
avout_x264.end();
avout_flac.end();
@ -3644,10 +3752,46 @@ handle_open(GApplication *application,
common_gtk_main(application, user_data);
}
#ifdef AGG2D_USE_VECTORFONTS
static std::string FindFontFile(const char* fontName, bool bold)
{
std::string fontFile;
FcPattern* pat = FcNameParse((const FcChar8*)fontName);
if(bold)
FcPatternAddInteger(pat, FC_WEIGHT, FC_WEIGHT_BOLD);
FcConfigSubstitute(fontConfig, pat, FcMatchPattern);
FcDefaultSubstitute(pat);
// find the font
FcResult res;
FcPattern* font = FcFontMatch(fontConfig, pat, &res);
if (font)
{
FcChar8* file = NULL;
if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch)
{
// save the file to another std::string
fontFile = (char*)file;
}
FcPatternDestroy(font);
}
FcPatternDestroy(pat);
return fontFile;
}
#endif
int main (int argc, char *argv[])
{
configured_features my_config;
#ifdef AGG2D_USE_VECTORFONTS
fontConfig = FcInitLoadConfigAndFonts();
vectorFontFile = FindFontFile("mono", true);
if(!vectorFontFile.size())
vectorFontFile = FindFontFile("sans", true);
#endif
// The global menu screws up the window size...
unsetenv("UBUNTU_MENUPROXY");

View File

@ -834,6 +834,10 @@
<attribute name='label' translatable='yes'>_Editor mode</attribute>
<attribute name='action'>app.hud_editor</attribute>
</item>
<item>
<attribute name='label' translatable='yes'>Reset layout</attribute>
<attribute name='action'>app.hud_reset_layout</attribute>
</item>
</section>
</menu>
<menu id='hud_unsupported'>

View File

@ -20,6 +20,7 @@ dep_openal = dependency('openal', required: get_option('openal'))
dep_alsa = dependency('alsa', required: false)
dep_soundtouch = dependency('soundtouch', required: false)
dep_agg = dependency('libagg', required: false)
dep_fontconfig = dependency('fontconfig', required: false)
# XXX: something wrong with this one.
#dep_lua = dependency('lua-5.1', required: false)
@ -203,6 +204,11 @@ endif
if dep_agg.found()
dependencies += dep_agg
add_global_arguments('-DHAVE_LIBAGG', language: ['c', 'cpp'])
if dep_fontconfig.found()
dependencies += dep_fontconfig
add_global_arguments('-DAGG2D_USE_VECTORFONTS', language: ['c', 'cpp'])
add_global_link_arguments('-laggfontfreetype', language: ['c', 'cpp'])
endif
libdesmume_src += [
'../modules/osd/agg/aggdraw.cpp',
'../modules/osd/agg/agg_osd.cpp',