Successful display of video in QT gui.

This commit is contained in:
Matthew Budd 2020-06-23 22:51:10 -04:00
parent be4c650238
commit 0352483a19
8 changed files with 697 additions and 17 deletions

View File

@ -1,6 +1,7 @@
// GameApp.cpp
//
#include "GameApp.h"
#include "fceuWrapper.h"
gameWin_t::gameWin_t(QWidget *parent)
: QMainWindow( parent )
@ -81,7 +82,9 @@ void gameWin_t::runGameFrame(void)
t = (double)ts.tv_sec + (double)(ts.tv_nsec * 1.0e-9);
//printf("Run Frame %f\n", t);
//
fceuWrapperUpdate();
viewport->repaint();
return;

View File

@ -1,13 +1,39 @@
// GameViewer.cpp
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "gl_win.h"
#include "GameViewer.h"
extern unsigned int gui_draw_area_width;
extern unsigned int gui_draw_area_height;
gameView_t::gameView_t(QWidget *parent)
: QOpenGLWidget( parent )
{
view_width = 0;
view_height = 0;
gltexture = 0;
QSurfaceFormat fmt = QSurfaceFormat::defaultFormat();
fmt.setRedBufferSize(8);
fmt.setGreenBufferSize(8);
fmt.setBlueBufferSize(8);
fmt.setAlphaBufferSize(8);
fmt.setDepthBufferSize( 24 );
setTextureFormat(GL_RGBA8);
printf("R: %i \n", fmt.redBufferSize() );
printf("G: %i \n", fmt.greenBufferSize() );
printf("B: %i \n", fmt.blueBufferSize() );
printf("A: %i \n", fmt.alphaBufferSize() );
printf("SW: %i \n", fmt.swapBehavior() );
setFormat( fmt );
}
gameView_t::~gameView_t(void)
@ -17,18 +43,45 @@ gameView_t::~gameView_t(void)
makeCurrent();
// Free GL texture
if (gltexture)
{
printf("Destroying GLX Texture\n");
glDeleteTextures(1, &gltexture);
gltexture=0;
}
doneCurrent();
}
void gameView_t::initializeGL(void)
{
int ipolate = 0;
initializeOpenGLFunctions();
// Set up the rendering context, load shaders and other resources, etc.:
//QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
printf("GL Init!\n");
glEnable(GL_TEXTURE_2D);
if ( gltexture )
{
printf("GL Texture already exists\n");
}
else
{
glGenTextures(1, &gltexture);
}
printf("Linear Interpolation on GL Texture: %s \n", ipolate ? "Enabled" : "Disabled");
glBindTexture(GL_TEXTURE_2D, gltexture);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,ipolate?GL_LINEAR:GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,ipolate?GL_LINEAR:GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
}
void gameView_t::resizeGL(int w, int h)
@ -36,29 +89,108 @@ void gameView_t::resizeGL(int w, int h)
printf("GL Resize: %i x %i \n", w, h );
glViewport(0, 0, w, h);
view_width = w;
view_height = h;
gui_draw_area_width = w;
gui_draw_area_height = h;
}
void gameView_t::paintGL(void)
{
float x1, y1, x2, y2;
int l=0, r=gl_shm->ncol;
int t=0, b=gl_shm->nrow;
angle += (2.0 * 3.14 * 0.01);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
float xscale = (float)view_width / (float)gl_shm->ncol;
float yscale = (float)view_height / (float)gl_shm->nrow;
x1 = cos( angle );
y1 = sin( angle );
if (xscale < yscale )
{
yscale = xscale;
}
else
{
xscale = yscale;
}
int rw=(int)((r-l)*xscale);
int rh=(int)((b-t)*yscale);
int sx=(view_width-rw)/2;
int sy=(view_height-rh)/2;
x2 = -x1;
y2 = -y1;
glViewport(sx, sy, rw, rh);
//glViewport( 0, 0, screen_width, screen_height);
glColor4f( 1.0, 1.0, 1.0, 1.0 );
glLineWidth(5.0);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glOrtho( -1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
glBegin(GL_LINES);
glVertex2f( x1, y1 );
glVertex2f( x2, y2 );
glDisable(GL_DEPTH_TEST);
glClearColor( 0.0, 0.0f, 0.0f, 0.0f); // Background color to black.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_TEXTURE_2D);
//glBindTexture(GL_TEXTURE_2D, gltexture);
glBindTexture(GL_TEXTURE_2D, gltexture);
//print_pixbuf();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0,
GL_RGBA, GL_UNSIGNED_BYTE, gl_shm->pixbuf );
glBegin(GL_QUADS);
glTexCoord2f(1.0f*l/256, 1.0f*b/256); // Bottom left of picture.
glVertex2f(-1.0f, -1.0f); // Bottom left of target.
glTexCoord2f(1.0f*r/256, 1.0f*b/256);// Bottom right of picture.
glVertex2f( 1.0f, -1.0f); // Bottom right of target.
glTexCoord2f(1.0f*r/256, 1.0f*t/256); // Top right of our picture.
glVertex2f( 1.0f, 1.0f); // Top right of target.
glTexCoord2f(1.0f*l/256, 1.0f*t/256); // Top left of our picture.
glVertex2f(-1.0f, 1.0f); // Top left of target.
glEnd();
glDisable(GL_TEXTURE_2D);
//glColor4f( 1.0, 1.0, 1.0, 1.0 );
//glLineWidth(5.0);
//glBegin(GL_LINES);
//glVertex2f(-1.0f, -1.0f); // Bottom left of target.
//glVertex2f( 1.0f, 1.0f); // Top right of target.
//glEnd();
context()->swapBuffers( context()->surface() );
//if ( double_buffer_ena )
//{
// glXSwapBuffers( dpy, win );
//}
//else
//{
// glFlush();
//}
glFlush();
//float x1, y1, x2, y2;
//angle += (2.0 * 3.14 * 0.01);
//
//glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
//x1 = cos( angle );
//y1 = sin( angle );
//x2 = -x1;
//y2 = -y1;
//glColor4f( 1.0, 1.0, 1.0, 1.0 );
//glLineWidth(5.0);
//glBegin(GL_LINES);
// glVertex2f( x1, y1 );
// glVertex2f( x2, y2 );
//glEnd();
//printf("Paint GL!\n");
}

View File

@ -21,6 +21,10 @@ class gameView_t : public QOpenGLWidget, protected QOpenGLFunctions
void resizeGL(int w, int h);
void paintGL(void);
int view_width;
int view_height;
GLuint gltexture;
private slots:
};

View File

@ -2,6 +2,7 @@
//
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "main.h"
#include "throttle.h"
@ -9,7 +10,9 @@
#include "dface.h"
#include "fceuWrapper.h"
#include "input.h"
#include "sdl.h"
#include "sdl-video.h"
#include "gl_win.h"
#include "unix-netplay.h"
#include "../common/cheat.h"
@ -50,7 +53,10 @@ Config *g_config = NULL;
static int inited = 0;
static int noconfig=0;
static int frameskip=0;
static int periodic_saves = 0;
extern double g_fpsScale;
//*****************************************************************
// Define Global Functions to be shared with FCEU Core
//*****************************************************************
@ -270,6 +276,505 @@ CloseGame(void)
return(1);
}
int fceuWrapperInit( int argc, char *argv[] )
{
int error;
FCEUD_Message("Starting " FCEU_NAME_AND_VERSION "...\n");
// Initialize the configuration system
g_config = InitConfig();
if ( !g_config )
{
printf("Error: Could not initialize configuration system\n");
exit(-1);
}
// initialize the infrastructure
error = FCEUI_Initialize();
if (error != 1)
{
printf("Error: Initializing FCEUI\n");
//ShowUsage(argv[0]);
//SDL_Quit();
return -1;
}
int romIndex = g_config->parse(argc, argv);
// This is here so that a default fceux.cfg will be created on first
// run, even without a valid ROM to play.
// Unless, of course, there's actually --no-config given
// mbg 8/23/2008 - this is also here so that the inputcfg routines can have
// a chance to dump the new inputcfg to the fceux.cfg in case you didnt
// specify a rom filename
g_config->getOption("SDL.NoConfig", &noconfig);
if (!noconfig)
{
g_config->save();
}
std::string s;
g_config->getOption("SDL.InputCfg", &s);
if (s.size() != 0)
{
InitVideo(GameInfo);
InputCfg(s);
}
// update the input devices
UpdateInput(g_config);
// check for a .fcm file to convert to .fm2
g_config->getOption ("SDL.FCMConvert", &s);
g_config->setOption ("SDL.FCMConvert", "");
if (!s.empty())
{
int okcount = 0;
std::string infname = s.c_str();
// produce output filename
std::string outname;
size_t dot = infname.find_last_of (".");
if (dot == std::string::npos)
outname = infname + ".fm2";
else
outname = infname.substr(0,dot) + ".fm2";
MovieData md;
EFCM_CONVERTRESULT result = convert_fcm (md, infname);
if (result == FCM_CONVERTRESULT_SUCCESS) {
okcount++;
// *outf = new EMUFILE;
EMUFILE_FILE* outf = FCEUD_UTF8_fstream (outname, "wb");
md.dump (outf,false);
delete outf;
FCEUD_Message ("Your file has been converted to FM2.\n");
}
else {
FCEUD_Message ("Something went wrong while converting your file...\n");
}
DriverKill();
SDL_Quit();
return 0;
}
// If x/y res set to 0, store current display res in SDL.LastX/YRes
int yres, xres;
g_config->getOption("SDL.XResolution", &xres);
g_config->getOption("SDL.YResolution", &yres);
int autoResume;
g_config->getOption("SDL.AutoResume", &autoResume);
if(autoResume)
{
AutoResumePlay = true;
}
else
{
AutoResumePlay = false;
}
// check to see if recording HUD to AVI is enabled
int rh;
g_config->getOption("SDL.RecordHUD", &rh);
if( rh == 0)
FCEUI_SetAviEnableHUDrecording(true);
else
FCEUI_SetAviEnableHUDrecording(false);
// check to see if movie messages are disabled
int mm;
g_config->getOption("SDL.MovieMsg", &mm);
if( mm == 0)
FCEUI_SetAviDisableMovieMessages(true);
else
FCEUI_SetAviDisableMovieMessages(false);
// check for a .fm2 file to rip the subtitles
g_config->getOption("SDL.RipSubs", &s);
g_config->setOption("SDL.RipSubs", "");
if (!s.empty())
{
MovieData md;
std::string infname;
infname = s.c_str();
FCEUFILE *fp = FCEU_fopen(s.c_str(), 0, "rb", 0);
// load the movie and and subtitles
extern bool LoadFM2(MovieData&, EMUFILE*, int, bool);
LoadFM2(md, fp->stream, INT_MAX, false);
LoadSubtitles(md); // fill subtitleFrames and subtitleMessages
delete fp;
// produce .srt file's name and open it for writing
std::string outname;
size_t dot = infname.find_last_of (".");
if (dot == std::string::npos)
outname = infname + ".srt";
else
outname = infname.substr(0,dot) + ".srt";
FILE *srtfile;
srtfile = fopen(outname.c_str(), "w");
if (srtfile != NULL)
{
extern std::vector<int> subtitleFrames;
extern std::vector<std::string> subtitleMessages;
float fps = (md.palFlag == 0 ? 60.0988 : 50.0069); // NTSC vs PAL
float subduration = 3; // seconds for the subtitles to be displayed
for (int i = 0; i < subtitleFrames.size(); i++)
{
fprintf(srtfile, "%i\n", i+1); // starts with 1, not 0
double seconds, ms, endseconds, endms;
seconds = subtitleFrames[i]/fps;
if (i+1 < subtitleFrames.size()) // there's another subtitle coming after this one
{
if (subtitleFrames[i+1]-subtitleFrames[i] < subduration*fps) // avoid two subtitles at the same time
{
endseconds = (subtitleFrames[i+1]-1)/fps; // frame x: subtitle1; frame x+1 subtitle2
} else {
endseconds = seconds+subduration;
}
} else {
endseconds = seconds+subduration;
}
ms = modf(seconds, &seconds);
endms = modf(endseconds, &endseconds);
// this is just beyond ugly, don't show it to your kids
fprintf(srtfile,
"%02.0f:%02d:%02d,%03d --> %02.0f:%02d:%02d,%03d\n", // hh:mm:ss,ms --> hh:mm:ss,ms
floor(seconds/3600), (int)floor(seconds/60 ) % 60, (int)floor(seconds) % 60, (int)(ms*1000),
floor(endseconds/3600), (int)floor(endseconds/60) % 60, (int)floor(endseconds) % 60, (int)(endms*1000));
fprintf(srtfile, "%s\n\n", subtitleMessages[i].c_str()); // new line for every subtitle
}
fclose(srtfile);
printf("%d subtitles have been ripped.\n", (int)subtitleFrames.size());
} else {
FCEUD_Message("Couldn't create output srt file...\n");
}
DriverKill();
SDL_Quit();
return 0;
}
gl_shm = open_video_shm();
if ( gl_shm == NULL )
{
printf("Error: Failed to open video Shared memory\n");
return -1;
}
// update the emu core
UpdateEMUCore(g_config);
#ifdef CREATE_AVI
g_config->getOption("SDL.VideoLog", &s);
g_config->setOption("SDL.VideoLog", "");
if(!s.empty())
{
NESVideoSetVideoCmd(s.c_str());
LoggingEnabled = 1;
g_config->getOption("SDL.MuteCapture", &mutecapture);
} else {
mutecapture = 0;
}
#endif
{
int id;
g_config->getOption("SDL.InputDisplay", &id);
extern int input_display;
input_display = id;
// not exactly an id as an true/false switch; still better than creating another int for that
g_config->getOption("SDL.SubtitleDisplay", &id);
extern int movieSubtitles;
movieSubtitles = id;
}
// load the hotkeys from the config life
setHotKeys();
if (romIndex >= 0)
{
// load the specified game
error = LoadGame(argv[romIndex]);
if (error != 1)
{
DriverKill();
SDL_Quit();
return -1;
}
g_config->setOption("SDL.LastOpenFile", argv[romIndex]);
g_config->save();
}
// movie playback
g_config->getOption("SDL.Movie", &s);
g_config->setOption("SDL.Movie", "");
if (s != "")
{
if(s.find(".fm2") != std::string::npos || s.find(".fm3") != std::string::npos)
{
static int pauseframe;
g_config->getOption("SDL.PauseFrame", &pauseframe);
g_config->setOption("SDL.PauseFrame", 0);
FCEUI_printf("Playing back movie located at %s\n", s.c_str());
FCEUI_LoadMovie(s.c_str(), false, pauseframe ? pauseframe : false);
}
else
{
FCEUI_printf("Sorry, I don't know how to play back %s\n", s.c_str());
}
g_config->getOption("SDL.MovieLength",&KillFCEUXonFrame);
printf("KillFCEUXonFrame %d\n",KillFCEUXonFrame);
}
int save_state;
g_config->getOption("SDL.PeriodicSaves", &periodic_saves);
g_config->getOption("SDL.AutoSaveState", &save_state);
if(periodic_saves && save_state < 10 && save_state >= 0){
FCEUI_SelectState(save_state, 0);
} else {
periodic_saves = 0;
}
#ifdef _S9XLUA_H
// load lua script if option passed
g_config->getOption("SDL.LuaScript", &s);
g_config->setOption("SDL.LuaScript", "");
if (s != "")
{
#ifdef __linux
// Resolve absolute path to file
char fullpath[2048];
if ( realpath( s.c_str(), fullpath ) != NULL )
{
//printf("Fullpath: '%s'\n", fullpath );
s.assign( fullpath );
}
#endif
FCEU_LoadLuaCode(s.c_str());
}
#endif
{
int id;
g_config->getOption("SDL.NewPPU", &id);
if (id)
newppu = 1;
}
g_config->getOption("SDL.Frameskip", &frameskip);
return 0;
}
int fceuWrapperClose( void )
{
CloseGame();
// exit the infrastructure
FCEUI_Kill();
SDL_Quit();
return 0;
}
/**
* Update the video, audio, and input subsystems with the provided
* video (XBuf) and audio (Buffer) information.
*/
void
FCEUD_Update(uint8 *XBuf,
int32 *Buffer,
int Count)
{
int blitDone = 0;
extern int FCEUDnetplay;
#ifdef CREATE_AVI
if(LoggingEnabled == 2 || (eoptions&EO_NOTHROTTLE))
{
if(LoggingEnabled == 2)
{
int16* MonoBuf = new int16[Count];
int n;
for(n=0; n<Count; ++n)
MonoBuf[n] = Buffer[n] & 0xFFFF;
NESVideoLoggingAudio
(
MonoBuf,
FSettings.SndRate, 16, 1,
Count
);
delete [] MonoBuf;
}
Count /= 2;
if(inited & 1)
{
if(Count > GetWriteSound()) Count = GetWriteSound();
if (!mutecapture)
if(Count > 0 && Buffer) WriteSound(Buffer,Count);
}
if(inited & 2)
FCEUD_UpdateInput();
if(XBuf && (inited & 4)) BlitScreen(XBuf);
//SpeedThrottle();
return;
}
#endif
int ocount = Count;
// apply frame scaling to Count
Count = (int)(Count / g_fpsScale);
if (Count)
{
int32 can=GetWriteSound();
static int uflow=0;
int32 tmpcan;
// don't underflow when scaling fps
if(can >= GetMaxSound() && g_fpsScale==1.0) uflow=1; /* Go into massive underflow mode. */
if(can > Count) can=Count;
else uflow=0;
#ifdef CREATE_AVI
if (!mutecapture)
#endif
WriteSound(Buffer,can);
//if(uflow) puts("Underflow");
tmpcan = GetWriteSound();
// don't underflow when scaling fps
if (g_fpsScale>1.0 || ((tmpcan < Count*0.90) && !uflow))
{
if (XBuf && (inited&4) && !(NoWaiting & 2))
{
BlitScreen(XBuf); blitDone = 1;
}
Buffer+=can;
Count-=can;
if(Count)
{
if(NoWaiting)
{
can=GetWriteSound();
if(Count>can) Count=can;
#ifdef CREATE_AVI
if (!mutecapture)
#endif
WriteSound(Buffer,Count);
}
else
{
while(Count>0)
{
#ifdef CREATE_AVI
if (!mutecapture)
#endif
WriteSound(Buffer,(Count<ocount) ? Count : ocount);
Count -= ocount;
}
}
}
} //else puts("Skipped");
else if (!NoWaiting && FCEUDnetplay && (uflow || tmpcan >= (Count * 1.8)))
{
if (Count > tmpcan) Count=tmpcan;
while(tmpcan > 0)
{
// printf("Overwrite: %d\n", (Count <= tmpcan)?Count : tmpcan);
#ifdef CREATE_AVI
if (!mutecapture)
#endif
WriteSound(Buffer, (Count <= tmpcan)?Count : tmpcan);
tmpcan -= Count;
}
}
}
else
{
if (!NoWaiting && (!(eoptions&EO_NOTHROTTLE) || FCEUI_EmulationPaused()))
{
while (SpeedThrottle())
{
FCEUD_UpdateInput();
}
}
if (XBuf && (inited&4))
{
BlitScreen(XBuf); blitDone = 1;
}
}
if ( !blitDone )
{
if (XBuf && (inited&4))
{
BlitScreen(XBuf); blitDone = 1;
}
}
FCEUD_UpdateInput();
//if(!Count && !NoWaiting && !(eoptions&EO_NOTHROTTLE))
// SpeedThrottle();
//if(XBuf && (inited&4))
//{
// BlitScreen(XBuf);
//}
//if(Count)
// WriteSound(Buffer,Count,NoWaiting);
//FCEUD_UpdateInput();
}
static void DoFun(int frameskip, int periodic_saves)
{
uint8 *gfx;
int32 *sound;
int32 ssize;
static int fskipc = 0;
static int opause = 0;
//TODO peroidic saves, working on it right now
if (periodic_saves && FCEUD_GetTime() % PERIODIC_SAVE_INTERVAL < 30){
FCEUI_SaveState(NULL, false);
}
#ifdef FRAMESKIP
fskipc = (fskipc + 1) % (frameskip + 1);
#endif
if (NoWaiting)
{
gfx = 0;
}
FCEUI_Emulate(&gfx, &sound, &ssize, fskipc);
FCEUD_Update(gfx, sound, ssize);
if(opause!=FCEUI_EmulationPaused())
{
opause=FCEUI_EmulationPaused();
SilenceSound(opause);
}
}
int fceuWrapperUpdate( void )
{
if (GameInfo)
{
DoFun(frameskip, periodic_saves);
}
return 0;
}
// dummy functions
#define DUMMY(__f) \

View File

@ -21,3 +21,8 @@ extern Config *g_config;
int LoadGame(const char *path);
int CloseGame(void);
int fceuWrapperInit( int argc, char *argv[] );
int fceuWrapperClose( void );
int fceuWrapperUpdate( void );

View File

@ -1,13 +1,16 @@
#include <QApplication>
#include "GameApp.h"
#include "fceuWrapper.h"
int main( int argc, char *argv[] )
{
QApplication app(argc, argv);
gameWin_t win;
win.resize( 200, 200 );
fceuWrapperInit( argc, argv );
win.resize( 512, 512 );
win.show();
return app.exec();

View File

@ -45,6 +45,10 @@
#include <cstring>
#include <cstdlib>
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define LSB_FIRST
#endif
// GLOBALS
extern Config *g_config;
@ -322,6 +326,21 @@ void LockConsole(){}
///Currently unimplemented.
void UnlockConsole(){}
static int testPattern = 0;
static void WriteTestPattern(void)
{
int i, j, k;
k=0;
for (i=0; i<GL_NES_WIDTH; i++)
{
for (j=0; j<GL_NES_HEIGHT; j++)
{
gl_shm->pixbuf[k] = 0xffffffff; k++;
}
}
}
/**
* Pushes the given buffer of bits to the screen.
*/
@ -352,7 +371,14 @@ BlitScreen(uint8 *XBuf)
if ( dest == NULL ) return;
Blit8ToHigh(XBuf + NOFFSET, dest, NWIDTH, s_tlines, pitch, 1, 1);
if ( testPattern )
{
WriteTestPattern();
}
else
{
Blit8ToHigh(XBuf + NOFFSET, dest, NWIDTH, s_tlines, pitch, 1, 1);
}
//guiPixelBufferReDraw();

View File

@ -43,7 +43,9 @@ unix {
QMAKE_CXXFLAGS += -D_S9XLUA_H
}
QMAKE_CXXFLAGS += -Wall -Wno-write-strings -Wno-sign-compare -Wno-parentheses -Wno-unused-local-typedefs
QMAKE_CXXFLAGS -= -O2
QMAKE_CXXFLAGS += -O0 -g3 -Wall -Wno-write-strings -Wno-sign-compare -Wno-parentheses -Wno-unused-local-typedefs
QMAKE_CXXFLAGS_RELEASE -= -O2
}
# Input