1
0
mirror of https://github.com/samstyle/Xpeccy.git synced 2025-04-19 00:04:05 +03:00

build 20180913

[+] Direct image drawing (faster)
[+] AY DAC
This commit is contained in:
samstyle 2018-09-13 17:53:39 +03:00
parent 3ce55c1141
commit 6f9d6cb9f4
22 changed files with 416 additions and 195 deletions

View File

@ -1 +1 @@
0.6.20180819
0.6.20180913

BIN
font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -31,13 +31,16 @@
// main
#if !VID_DIRECT_DRAW
unsigned char screen[4096 * 2048 * 3]; // scaled image (up to fullscreen)
unsigned char scrn[1024 * 512 * 3]; // 2:1 image
unsigned char sbufa[1024 * 512 * 3]; // Emulation render -> (this)buffer -> scrn for postprocessing
unsigned char prvScr[1024 * 512 * 3]; // copy of last 2:1 image (for noflic)
#endif
extern int bytesPerLine;
static QPainter pnt;
static QImage alphabet;
// mainwin
@ -58,8 +61,8 @@ void MainWin::updateHead() {
void MainWin::updateWindow() {
block = 1;
vidSetBorder(comp->vid, conf.brdsize);
sndCalibrate(comp);
vidSetBorder(comp->vid, conf.brdsize); // to call vidUpdateLayout???
// sndCalibrate(comp); // why?
ethread.sndNs = 0;
int szw = comp->vid->vsze.x * conf.vid.scale;
int szh = comp->vid->vsze.y * conf.vid.scale;
@ -68,26 +71,24 @@ void MainWin::updateWindow() {
szw = wsz.width();
szh = wsz.height();
setWindowState(windowState() | Qt::WindowFullScreen);
// grabMice = 1;
// grabMouse();
} else {
setWindowState(windowState() & ~Qt::WindowFullScreen);
// grabMice = 0;
// releaseMouse();
}
// if (grabMice || conf.vid.fullScreen) {
// setCursor(Qt::BlankCursor);
// } else {
// unsetCursor();
// }
setFixedSize(szw, szh);
lineBytes = szw * 3;
frameBytes = szh * lineBytes;
#if VID_DIRECT_DRAW
scrImg = QImage(comp->vid->scrimg, szw, szh, QImage::Format_RGB888);
#else
scrImg = QImage(screen, szw, szh, QImage::Format_RGB888);
#endif
bytesPerLine = scrImg.bytesPerLine();
#if VID_DIRECT_DRAW
vid_set_zoom(conf.vid.scale);
#endif
updateHead();
block = 0;
if (dbg->isVisible()) dbg->fillAll(); // hmmm... why?
// if (dbg->isVisible()) dbg->fillAll(); // hmmm... why?
}
bool MainWin::saveChanged() {
@ -161,6 +162,7 @@ MainWin::MainWin() {
file.close();
msgTimer = 0;
msg.clear();
alphabet.load(":/font.png");
initKeyMap();
conf.scrShot.format = "png";
@ -212,7 +214,9 @@ MainWin::MainWin() {
ethread.conf = &conf;
connect(&ethread,SIGNAL(dbgRequest()),SLOT(doDebug()));
connect(&ethread,SIGNAL(tapeSignal(int,int)),this,SLOT(tapStateChanged(int,int)));
#if !VID_DIRECT_DRAW
connect(&ethread,SIGNAL(picReady()),this,SLOT(convImage()));
#endif
ethread.start();
scrImg = QImage(100,100,QImage::Format_RGB888);
@ -235,6 +239,7 @@ void processPicture(unsigned char*, int);
void MainWin::convImage() {
#if !VID_DIRECT_DRAW
if (!pauseFlags || comp->debug) {
if (ethread.fast || comp->debug) {
memcpy(scrn, comp->vid->scrimg, comp->vid->vBytes);
@ -242,8 +247,7 @@ void MainWin::convImage() {
memcpy(scrn, sbufa, comp->vid->vBytes);
// processPicture(comp->vid->scrimg, comp->vid->vBytes);
}
// scrMix(prvScr, scrn, comp->vid->vBytes, conf.vid.noFlick ? 0.5 : 0.7);
if (conf.vid.grayScale)
if (greyScale)
scrGray(scrn, comp->vid->vBytes);
}
@ -262,9 +266,8 @@ void MainWin::convImage() {
break;
}
}
ethread.waitpic = 1;
// [put leds],make screenshot,[put leds]
if (!conf.scrShot.noLeds) putLeds(); // put leds before screenshot if on
// if (!conf.scrShot.noLeds) putLeds(); // put leds before screenshot if on
if (scrCounter > 0) {
if (scrInterval > 0) {
scrInterval--;
@ -274,16 +277,11 @@ void MainWin::convImage() {
scrInterval = conf.scrShot.interval;
}
}
if (conf.scrShot.noLeds) putLeds(); // put leds if it isn't done yet
// put messages
if (msgTimer > 0) {
if (conf.led.message)
drawMessage();
msgTimer--;
}
// if (conf.scrShot.noLeds) putLeds(); // put leds if it isn't done yet
setUpdatesEnabled(true);
repaint();
setUpdatesEnabled(false);
#endif
}
// gamepad mapper
@ -417,20 +415,10 @@ void MainWin::onTimer() {
setMessage(QString(comp->msg));
comp->msg = NULL;
}
// if window is not active release keys & buttons, release mouse
if (!isActiveWindow()) {
if (!keywin->isVisible())
kbdReleaseAll(comp->keyb);
mouseReleaseAll(comp->mouse);
unsetCursor();
if (grabMice) {
grabMice = 0;
releaseMouse();
}
}
// update satellites
updateSatellites();
// fill fake buffer if paused
#if !VID_DIRECT_DRAW
if (pauseFlags) {
conf.snd.fill = 1;
do {
@ -440,10 +428,26 @@ void MainWin::onTimer() {
} else if (ethread.fast) {
convImage();
}
#else
setUpdatesEnabled(true);
repaint();
setUpdatesEnabled(false);
#endif
emutex.unlock();
}
// if window is not active release keys & buttons, release mouse
void MainWin::focusOutEvent(QFocusEvent* ev) {
if (!keywin->isVisible())
kbdReleaseAll(comp->keyb);
mouseReleaseAll(comp->mouse);
unsetCursor();
if (grabMice) {
grabMice = 0;
releaseMouse();
}
}
void MainWin::menuShow() {
layoutMenu->setDisabled(comp->vid->lockLayout);
pause(true,PR_MENU);
@ -526,6 +530,44 @@ void MainWin::paintEvent(QPaintEvent*) {
if (block) return;
pnt.begin(this);
pnt.drawImage(0,0,scrImg);
// put leds
if (comp->joy->used && conf.led.joy) {
pnt.drawImage(3, 30, QImage(":/images/joystick.png").scaled(16, 16));
}
if (comp->mouse->used && conf.led.mouse) {
pnt.drawImage(3, 50, QImage(":/images/mouse.png").scaled(16, 16));
comp->mouse->used = 0;
}
if (comp->tape->on && conf.led.tape) {
if (comp->tape->rec) {
pnt.drawImage(3, 70, QImage(":/images/tapeRed.png").scaled(16,16));
} else {
pnt.drawImage(3, 70, QImage(":/images/tapeYellow.png").scaled(16,16));
}
}
if (conf.led.disk) {
if (comp->dif->fdc->flp->rd) {
comp->dif->fdc->flp->rd = 0;
pnt.drawImage(3, 90, QImage(":/images/diskGreen.png").scaled(16,16));
} else if (comp->dif->fdc->flp->wr) {
comp->dif->fdc->flp->wr = 0;
pnt.drawImage(3, 90, QImage(":/images/diskRed.png").scaled(16,16));
}
}
// put messages
if (msgTimer > 0) {
if (conf.led.message) {
int chr;
int x = 5;
int y = height() - 20;
for (int i = 0; i < msg.size(); i++) {
chr = msg.at(i).unicode() - 32;
pnt.drawImage(x, y, alphabet, 0, chr * 12, 12, 12);
x += 12;
}
}
msgTimer--;
}
pnt.end();
}
@ -547,7 +589,11 @@ void MainWin::keyPressEvent(QKeyEvent *ev) {
} else if (ev->modifiers() & Qt::AltModifier) {
switch(ev->key()) {
case Qt::Key_Return:
#if VID_DIRECT_DRAW
vid_set_fullscreen(!conf.vid.fullScreen);
#else
conf.vid.fullScreen ^= 1;
#endif
setMessage(conf.vid.fullScreen ? " fullscreen on " : " fullscreen off ");
updateWindow();
saveConfig();
@ -556,28 +602,44 @@ void MainWin::keyPressEvent(QKeyEvent *ev) {
debugAction();
break;
case Qt::Key_1:
#if VID_DIRECT_DRAW
vid_set_zoom(1);
#else
conf.vid.scale = 1;
#endif
updateWindow();
convImage();
saveConfig();
setMessage(" size x1 ");
break;
case Qt::Key_2:
#if VID_DIRECT_DRAW
vid_set_zoom(2);
#else
conf.vid.scale = 2;
#endif
updateWindow();
convImage();
saveConfig();
setMessage(" size x2 ");
break;
case Qt::Key_3:
#if VID_DIRECT_DRAW
vid_set_zoom(3);
#else
conf.vid.scale = 3;
#endif
updateWindow();
convImage();
saveConfig();
setMessage(" size x3 ");
break;
case Qt::Key_4:
#if VID_DIRECT_DRAW
vid_set_zoom(4);
#else
conf.vid.scale = 4;
#endif
updateWindow();
convImage();
saveConfig();
@ -594,6 +656,10 @@ void MainWin::keyPressEvent(QKeyEvent *ev) {
compReset(comp,RES_DOS);
rzxWin->stop();
break;
case Qt::Key_D:
ayDac = !ayDac;
setMessage(QString(" DAC %0 ").arg(ayDac ? "on" : "off"));
break;
case Qt::Key_K:
if (keywin->isVisible()) {
keywin->close();
@ -604,17 +670,23 @@ void MainWin::keyPressEvent(QKeyEvent *ev) {
}
break;
case Qt::Key_N:
if (conf.vid.noflic < 15)
conf.vid.noflic = 25;
else if (conf.vid.noflic < 35)
conf.vid.noflic = 50;
else conf.vid.noflic = 0;
if (noflic < 15)
noflic = 25;
else if (noflic < 35)
noflic = 50;
else noflic = 0;
saveConfig();
#if !VID_DIRECT_DRAW
memcpy(prvScr, scrn, comp->vid->frmsz * 6);
setMessage(QString(" noflick %0% ").arg(conf.vid.noflic * 2));
#endif
setMessage(QString(" noflick %0% ").arg(noflic * 2));
break;
case Qt::Key_R:
#if VID_DIRECT_DRAW
vid_set_ratio(!conf.vid.keepRatio);
#else
conf.vid.keepRatio ^= 1;
#endif
setMessage(conf.vid.keepRatio ? " keep aspect ratio " : " ignore aspect ratio ");
saveConfig();
break;
@ -903,7 +975,11 @@ void MainWin::screenShot() {
fnams.append(QString("xpeccy_%0.%1").arg(QTime::currentTime().toString("HHmmss_zzz")).arg(fext.c_str()));
std::string fnam(fnams.toUtf8().data());
std::ofstream file;
#if VID_DIRECT_DRAW
QImage img(comp->vid->scrimg, width(), height(), QImage::Format_RGB888);
#else
QImage img(screen, width(), height(), QImage::Format_RGB888);
#endif
int x,y,dx,dy;
char* sptr = (char*)(comp->mem->ramData + (comp->vid->curscr << 14));
switch (frm) {
@ -1033,6 +1109,9 @@ void drawChar(QByteArray chr, int scradr) {
int r,g,b;
int adr = 0;
int vadr;
#if VID_DIRECT_DRAW
unsigned char* screen = conf.prof.cur->zx->vid->scrimg;
#endif
for (y = 0; y < 12; y++) {
for (x = 0; x < 12*3; x+=3) {
r = chr.at(adr++);

View File

@ -127,7 +127,7 @@ class MainWin : public QWidget {
//void saveGSRAM();
void saveNESPPU();
void debugAction();
protected:
private:
void closeEvent(QCloseEvent*);
void dragEnterEvent(QDragEnterEvent*);
void dropEvent(QDropEvent*);
@ -138,6 +138,7 @@ class MainWin : public QWidget {
void mouseReleaseEvent(QMouseEvent*);
void mouseMoveEvent(QMouseEvent*);
void wheelEvent(QWheelEvent*);
void focusOutEvent(QFocusEvent*);
};
#endif

View File

@ -8,14 +8,16 @@
QMutex emutex;
unsigned char* blkData = NULL;
#if !VID_DIRECT_DRAW
extern unsigned char sbufa[1024 * 512 * 3];
extern unsigned char scrn[1024 * 512 * 3];
extern unsigned char prvScr[1024 * 512 * 3];
void processPicture(unsigned char* src, int size) {
memcpy(sbufa, src, size);
scrMix(prvScr, sbufa, size, conf.vid.noflic / 100.0);
scrMix(prvScr, sbufa, size, noflic / 100.0);
}
#endif
xThread::xThread() {
sndNs = 0;
@ -60,16 +62,13 @@ void xThread::emuCycle() {
do {
// exec 1 opcode (or handle INT, NMI)
sndNs += compExec(comp);
if (comp->frmStrobe) {
#if !VID_DIRECT_DRAW
if (comp->frmStrobe && !fast) {
comp->frmStrobe = 0;
if (!fast) {
processPicture(comp->vid->scrimg, comp->vid->vBytes);
if (waitpic) {
waitpic = 0;
emit picReady();
}
}
processPicture(comp->vid->scrimg, comp->vid->vBytes);
emit picReady();
}
#endif
// if need - request sound buffer update
if (sndNs > nsPerSample) {
sndSync(comp, 0, fast);
@ -86,7 +85,6 @@ void xThread::emuCycle() {
}
void xThread::run() {
waitpic = 1;
emutex.lock();
do {
#ifdef HAVEZLIB

View File

@ -1,5 +1,5 @@
#ifndef _ETHREAD_H
#define _ETHREAD_H
#ifndef X_ETHREAD_H
#define X_ETHREAD_H
#include <QThread>
#include <QMutex>
@ -14,7 +14,6 @@ class xThread : public QThread {
unsigned silent:1; // don't produce sound
unsigned block:1;
unsigned finish:1;
unsigned waitpic:1; // display thread waits for new picture (basicly: picReady signal enabled)
xConfig* conf;
Computer* comp;
int sndNs;

View File

@ -35,7 +35,7 @@ void scoMapMem(Computer* comp) {
}
unsigned char scoMRd(Computer* comp, unsigned short adr, int m1) {
if (((comp->mem->map[0].num & 3) == 2) && ((adr & 0xfffc) == 0x0100) && !m1 && (comp->cpu->com == 0x6e)) {
if (((comp->mem->map[0].num & 3) == 2) && ((adr & 0xfff3) == 0x0100) && !m1) {
comp->prt2 = ZSLays[(adr & 0x000c) >> 2][comp->prt2 & 3];
comp->hw->mapMem(comp);
}

View File

@ -5,6 +5,7 @@
// tables
int ayDac = 1;
char noizes[0x20000]; // here iz noize values 1/0 [generated at start]
static unsigned char envforms[16][34]={
@ -30,8 +31,25 @@ static unsigned char envforms[16][34]={
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, 0,255} // F: 0->max, invert, stay
};
/*
const SNDCHIP_VOLTAB SNDR_VOL_YM_S =
{ { 0x0000,0x0000,0x00EF,0x01D0,0x0290,0x032A,0x03EE,0x04D2,0x0611,0x0782,0x0912,0x0A36,0x0C31,0x0EB6,0x1130,0x13A0,
0x1751,0x1BF5,0x20E2,0x2594,0x2CA1,0x357F,0x3E45,0x475E,0x5502,0x6620,0x7730,0x8844,0xA1D2,0xC102,0xE0A2,0xFFFF } };
*/
// try to use it somehow :)
//unsigned char ayDACvol[16] = {0,0,0,0,0,1,1,1,1,2,2,3,4,7,10,15}; // from AY manual
#if 0
static unsigned char ayDACvol[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,
0x05,0x06,0x08,0x09,0x0B,0x0D,0x0F,0x11,
0x15,0x19,0x1D,0x22,0x28,0x30,0x38,0x3F}; // from unreal
#else
static unsigned char ayDACvol[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x01,0x01,0x02,0x02,0x03,0x03,0x04,
0x05,0x06,0x07,0x08,0x09,0x0b,0x0d,0x10,
0x13,0x16,0x1a,0x20,0x26,0x2d,0x35,0x3f}; // from manual
#endif
//unsigned char ayDACvol[16] = {0,0,0,0,0,0,0,1,1,3,4,5,7,9,12,15}; // from ayumi
// AY/YM sound chip
@ -123,15 +141,15 @@ void aymSetReg(aymChip* ay, unsigned char val) {
ay->chanC.nen = (val & 32) ? 0 : 1;
break;
case 0x08:
ay->chanA.vol = val & 15;
ay->chanA.vol = (val & 15) << 1;
ay->chanA.een = (val & 16) ? 1 : 0;
break;
case 0x09:
ay->chanB.vol = val & 15;
ay->chanB.vol = (val & 15) << 1;
ay->chanB.een = (val & 16) ? 1 : 0;
break;
case 0x0a:
ay->chanC.vol = val & 15;
ay->chanC.vol = (val & 15) << 1;
ay->chanC.een = (val & 16) ? 1 : 0;
break;
case 0x0b:
@ -226,19 +244,19 @@ void aymSync(aymChip* ay, int ns) {
}
// NOTE : if tone & noise disabled, signal is 1 - take amp/env for digital music
static int vol;
int ayGetChanVol(aymChip* ay, aymChan* ch) {
int vol = ch->een ? ay->chanE.vol : ch->vol;
if (ch->ten || ch->nen) {
vol = ((ch->lev && ch->ten) || (ay->chanN.lev && ch->nen)) ? vol : 0;
}
return vol << 1; // 0..1f (env) -> 0..3e
// return ayDACvol[vol];
if ((ch->lev & ch->ten) || (ch->nen && ay->chanN.lev) || !(ch->ten || ch->nen))
vol = ch->een ? ay->chanE.vol : ch->vol;
else
vol = 0;
return ayDac ? ayDACvol[vol] : vol;
}
sndPair aymGetVolume(aymChip* ay) {
sndPair res;
// ay->chanN.lev = noizes[ay->chanN.step & 0x1ffff] ? 1 : 0; // noise value
// ay->chanE.vol = envforms[ay->eForm][ay->chanE.step]; // envelope value
int volA = ayGetChanVol(ay, &ay->chanA);
int volB = ayGetChanVol(ay, &ay->chanB);
int volC = ayGetChanVol(ay, &ay->chanC);
@ -351,7 +369,7 @@ void tsOut(TSound* ts, int port, unsigned char val) {
if ((val & 0xf8) == 0xf8) {
ts->curChip = (val & 1) ? ts->chipB : ts->chipA;
} else {
ts->curChip->curReg = val; break;
ts->curChip->curReg = val;
}
break;
default:

View File

@ -1,5 +1,5 @@
#ifndef _XPAYYM
#define _XPAYYM
#ifndef X_AYYM_H
#define X_AYYM_H
#ifdef __cplusplus
extern "C" {
@ -11,6 +11,8 @@ extern "C" {
// 1T = 1e9 / frq ns
// sync: decrease current tick ns counter, change channels on tick borders
extern int ayDac;
// ay_type
enum {
SND_NONE = 0,

View File

@ -763,14 +763,6 @@ void vdpExec(Video* vid) {
break;
default:
printf("vdp9938 command %.2X, arg %.2X\n",vid->com, vid->arg);
#ifdef ISDEBUG
printf("src : %i : %i\n", vdp->src.x, vdp->src.y);
printf("dst : %i : %i\n", vdp->dst.x, vdp->dst.y);
printf("siz : %i : %i\n", vdp->size.x, vdp->size.y);
printf("r2C : %.2X\n", vdp->reg[0x2c]);
printf("r2D : %.2X\n", vdp->reg[0x2d]);
assert(0);
#endif
break;
}
}

View File

@ -1,6 +1,8 @@
#ifndef X_VIDCOMMON_H
#define X_VIDCOMMON_H
#define VID_DIRECT_DRAW 0
#ifdef WORDS_BIG_ENDIAN
#define ePair(p,h,l) union{unsigned short p; struct {unsigned char h; unsigned char l;};}
#else
@ -20,6 +22,7 @@ typedef struct {
typedef struct {
unsigned char* ptr;
unsigned char* lptr;
int x;
int y;
int xb;
@ -37,28 +40,24 @@ typedef struct {
#define MADR(_bnk,_adr) ((_bnk) << 14) + (_adr)
#if 1
#define vidPutOneColor(_ray, _pal, _idx, _c)\
if ((*(_ray)->ptr) != _pal[_idx]._c) {*((_ray)->ptr) = _pal[_idx]._c;}\
(_ray)->ptr++;
#if VID_DIRECT_DRAW
#define vidSingleDot(_ray, _pal, _idx) \
vidPutOneColor(_ray, _pal, _idx, r);\
vidPutOneColor(_ray, _pal, _idx, g);\
vidPutOneColor(_ray, _pal, _idx, b);
vid_dot_half(vid, _idx);
#define vidPutDot(_ray, _pal, _idx) \
vid_dot_full(vid, _idx);
#else
#define vidSingleDot(_ray, _pal, _idx) \
*((_ray)->ptr++) = _pal[_idx].r;\
*((_ray)->ptr++) = _pal[_idx].g;\
*((_ray)->ptr++) = _pal[_idx].b;
#endif
#define vidSingleDot(_ray, _pal, _idx) \
memcpy((_ray)->ptr, &(_pal)[_idx], 3);\
(_ray)->ptr += 3;
#define vidPutDot(_ray, _pal, _idx) \
vidSingleDot(_ray, _pal, _idx);\
vidSingleDot(_ray, _pal, _idx);
#endif
#endif

View File

@ -7,7 +7,108 @@
#include "video.h"
// int vidFlag = 0;
int bytesPerLine = 100;
int greyScale = 0;
int noflic = 0;
#if VID_DIRECT_DRAW
static int xpos = 0;
static int ypos = 0;
int xstep = 0x100;
int ystep = 0x100;
int lefSkip = 0;
int rigSkip = 0;
int topSkip = 0;
int botSkip = 0;
static unsigned char pscr[2560 * 1440 * 3];
static unsigned char* pptr = pscr;
static unsigned char pcol;
static xColor xcol;
void vid_dot(Video* vid, unsigned char col) {
xcol = vid->pal[col];
if (greyScale) {
pcol = (xcol.b * 12 + xcol.r * 3 + xcol.g * 58) / 100;
xcol.r = pcol;
xcol.g = pcol;
xcol.b = pcol;
}
pcol = xcol.r;
*(vid->ray.ptr++) = (pcol * (100 - noflic) + *pptr * noflic) / 100;
*(pptr++) = pcol;
pcol = xcol.g;
*(vid->ray.ptr++) = (pcol * (100 - noflic) + *pptr * noflic) / 100;
*(pptr++) = pcol;
pcol = xcol.b;
*(vid->ray.ptr++) = (pcol * (100 - noflic) + *pptr * noflic) / 100;
*(pptr++) = pcol;
}
void vid_dot_full(Video* vid, unsigned char col) {
xpos += xstep;
while (xpos > 0xff) {
xpos -= 0x100;
vid_dot(vid, col);
}
}
void vid_dot_half(Video* vid, unsigned char col) {
xpos += xstep / 2;
while (xpos > 0xff) {
xpos -= 0x100;
vid_dot(vid, col);
}
}
void vid_line(Video* vid) {
vid_dot_full(vid, 0);
if (rigSkip)
memset(vid->ray.ptr, 0x00, rigSkip);
vid->ray.lptr += bytesPerLine;
ypos += ystep;
ypos -= 0x100; // 1 line is already drawn
xpos = 0;
while (ypos > 0) {
ypos -= 0x100;
memcpy(vid->ray.lptr, vid->ray.lptr - bytesPerLine, bytesPerLine);
vid->ray.lptr += bytesPerLine;
}
if (lefSkip)
memset(vid->ray.lptr, 0x00, lefSkip);
vid->ray.ptr = vid->ray.lptr + lefSkip;
}
void vid_line_fill(Video* vid) {
int ytmp = ypos;
unsigned char* ptr = vid->ray.lptr;
ytmp += ystep;
ytmp -= 0x100;
while (ytmp > 0) {
ypos -= 0x100;
memcpy(ptr, ptr - bytesPerLine, bytesPerLine);
ptr += bytesPerLine;
}
}
void vid_frame(Video* vid) {
if (botSkip)
memset(vid->ray.lptr, 0x00, botSkip * bytesPerLine);
ypos = 0;
if (topSkip)
memset(vid->scrimg, 0x00, topSkip * bytesPerLine);
vid->ray.lptr = vid->scrimg + topSkip * bytesPerLine;
if (lefSkip)
memset(vid->ray.lptr, 0x00, lefSkip);
vid->ray.ptr = vid->ray.lptr + lefSkip;
pptr = pscr;
}
#endif
Video* vidCreate(vcbmrd cb, void* dptr) {
Video* vid = (Video*)malloc(sizeof(Video));
@ -34,6 +135,7 @@ Video* vidCreate(vcbmrd cb, void* dptr) {
vid->idx = 0;
vid->ray.ptr = vid->scrimg;
vid->ray.lptr = vid->scrimg;
return vid;
}
@ -61,12 +163,6 @@ void vidReset(Video* vid) {
}
vid->ula->active = 0;
vid->curscr = 5;
vid->ray.x = 0;
vid->ray.y = 0;
vid->ray.xb = vid->blank.x;
vid->ray.yb = vid->blank.y;
vid->idx = 0;
vid->ray.ptr = vid->scrimg;
vid->nsDraw = 0;
vidSetMode(vid, VID_NORMAL);
}
@ -91,10 +187,6 @@ void vidUpdateLayout(Video* vid) {
vid->send.y = vid->bord.y + vid->scrn.y;
vid->vBytes = vid->vsze.x * vid->vsze.y * 6; // real size of image buffer (3 bytes/dot x2:x1)
vidUpdateTimings(vid, vid->nsPerDot);
#ifdef ISDEBUG
printf("%i : ",vid->lay.bord.x);
printf("%i - %i, %i - %i\n",vid->lcut.x, vid->rcut.x, vid->lcut.y, vid->rcut.y);
#endif
}
void vidSetLayout(Video* vid, vLayout lay) {
@ -892,13 +984,21 @@ void vidSync(Video* vid, int ns) {
if (vid->cbLine) vid->cbLine(vid);
}
if (vid->ray.x == vid->vend.x) { // hblank start
#if VID_DIRECT_DRAW
if ((vid->ray.y >= vid->lcut.y) && (vid->ray.y < vid->rcut.y))
vid_line(vid);
#endif
vid->hblank = 1;
vid->hbstrb = 1;
vid->ray.y++;
vid->ray.xb = 0;
vid->ray.yb++;
if (vid->ray.y >= vid->full.y) { // new frame
#if VID_DIRECT_DRAW
vid_frame(vid);
#else
vid->ray.ptr = vid->scrimg;
#endif
vid->vblank = 0;
vid->vbstrb = 0;
vid->ray.y = 0;

View File

@ -62,6 +62,24 @@ enum {
typedef struct Video Video;
extern int bytesPerLine;
extern int greyScale;
extern int noflic;
#if VID_DIRECT_DRAW
extern int xstep;
extern int ystep;
extern int lefSkip;
extern int rigSkip;
extern int topSkip;
extern int botSkip;
void vid_dot_full(Video*, unsigned char);
void vid_dot_half(Video*, unsigned char);
#endif
typedef unsigned char(*vcbmrd)(int, void*);
typedef void(*vcbmwr)(int, unsigned char, void*);
typedef void(*cbvid)(Video*);
@ -256,10 +274,10 @@ struct Video {
unsigned char cbank; // char data offset (reg#18 b4..7)
unsigned char colram[0x1000]; // vicII color ram
unsigned char ram[128 * 1024]; // 128K of video memory
unsigned char oam[0x100]; // nes oam memory
unsigned char ram[MEM_128K]; // 128K of video memory
unsigned char oam[MEM_256]; // nes oam memory
unsigned char reg[256]; // max 256 registers
unsigned char scrimg[2 * 512 * 512 * 3]; // 512x512 rgb (dX x2)
unsigned char scrimg[2560 * 1440 * 3];
ulaPlus* ula;

View File

@ -1 +1 @@
#define VERSION 0.6.20180819
#define VERSION 0.6.20180913

View File

@ -6,7 +6,8 @@
#include <QtCore>
#include "xcore.h"
#include "../xgui/xgui.h"
#include "vscalers.h"
#include "xgui.h"
#include "sound.h"
#ifdef _WIN32
@ -140,9 +141,9 @@ void saveConfig() {
fprintf(cfile, "fullscreen = %s\n", YESNO(conf.vid.fullScreen));
fprintf(cfile, "keepratio = %s\n", YESNO(conf.vid.keepRatio));
fprintf(cfile, "scale = %i\n", conf.vid.scale);
fprintf(cfile, "greyscale = %s\n", YESNO(conf.vid.grayScale));
fprintf(cfile, "greyscale = %s\n", YESNO(greyScale));
fprintf(cfile, "bordersize = %i\n", int(conf.brdsize * 100));
fprintf(cfile, "noflick = %i%%\n", conf.vid.noflic);
fprintf(cfile, "noflick = %i%%\n", noflic);
fprintf(cfile, "\n[ROMSETS]\n");
foreach(xRomset rms, conf.rsList) {
@ -167,6 +168,7 @@ void saveConfig() {
// fprintf(cfile, "dontmute = %s\n", YESNO(conf.snd.mute));
fprintf(cfile, "soundsys = %s\n", sndOutput->name);
fprintf(cfile, "rate = %i\n", conf.snd.rate);
fprintf(cfile, "dac = %s\n", YESNO(ayDac));
fprintf(cfile, "volume.master = %i\n", conf.snd.vol.master);
fprintf(cfile, "volume.beep = %i\n", conf.snd.vol.beep);
fprintf(cfile, "volume.tape = %i\n", conf.snd.vol.tape);
@ -359,9 +361,9 @@ void loadConfig() {
if (conf.vid.scale < 1) conf.vid.scale = 1;
if (conf.vid.scale > 4) conf.vid.scale = 4;
}
if (pnam=="noflic") conf.vid.noflic = str2bool(pval) ? 50 : 25; // old parameter
if (pnam=="noflick") conf.vid.noflic = getRanged(pval.c_str(), 0, 50); // new parameter
if (pnam=="greyscale") conf.vid.grayScale = str2bool(pval) ? 1 : 0;
if (pnam=="noflic") noflic = str2bool(pval) ? 50 : 25; // old parameter
if (pnam=="noflick") noflic = getRanged(pval.c_str(), 0, 50); // new parameter
if (pnam=="greyscale") greyScale = str2bool(pval) ? 1 : 0;
break;
case SECT_ROMSETS:
pos = pval.find_last_of(":");
@ -407,7 +409,7 @@ void loadConfig() {
break;
case SECT_SOUND:
if (pnam=="enabled") conf.snd.enabled = str2bool(pval) ? 1 : 0;
// if (pnam=="dontmute") conf.snd.mute = str2bool(pval) ? 1 : 0;
if (pnam=="dac") ayDac = str2bool(pval.c_str()) ? 1 : 0;
if (pnam=="soundsys") soutnam = pval;
if (pnam=="rate") conf.snd.rate = atoi(pval.c_str());
if (pnam=="volume.master") conf.snd.vol.master = getRanged(pval.c_str(), 0, 100);
@ -446,6 +448,11 @@ void loadConfig() {
}
}
}
#if VID_DIRECT_DRAW
vid_set_zoom(conf.vid.scale);
vid_set_fullscreen(conf.vid.fullScreen);
vid_set_ratio(conf.vid.keepRatio);
#endif
uint i;
for (i=0; i<rsListist.size(); i++) addRomset(rsListist[i]);
prfLoadAll();

View File

@ -25,69 +25,3 @@ void scrMix(unsigned char* src, unsigned char* dst, int size, double mass) {
size--;
}
}
/*
// make image dim
void scrDim(unsigned char* src, int size) {
while(size > 0) {
*src >>= 2;
src++;
size--;
}
}
*/
// TODO: pixel filters like eps, scale2x... etc
/*
void colEPS(unsigned char* ptr, int linSize) {
int cp,ca,cb,cc,cd,c1,c2,c3,c4;
cp = *ptr; ca = *(ptr - linSize); cb = *(ptr + 3); cc = *(ptr - 3); cd = *(ptr + linSize);
c1 = *(ptr - linSize - 3); c2 = ca; c3 = cc; c4 = cp;
if (((ca == cb) && (cb == cc)) || ((ca == cb) && (cb == cd)) || ((ca == cc) && (cc == cd)) || ((cb == cc) && (cc == cd))) {
c1 = c2 = c3 = c4 = cp;
} else {
if (ca == cc) c1 = ca;
if (ca == cb) c2 = cb;
if (cc == cd) c3 = cc;
if (cb == cd) c4 = cd;
}
*(ptr - linSize - 3) = c1;
*(ptr - linSize) = c2;
*(ptr - 3) = c3;
*ptr = c4;
}
void scrEPS(unsigned char* src, int wid, int hig) {
#if 0
int x,y;
int linSize = wid * 3;
unsigned char* sptr = src + linSize + 3; // (1,1) pixel
unsigned char* ptr;
for (y = 1; y < hig - 1; y += 2) {
ptr = sptr;
for (x = 1; x < wid - 1; x += 2) {
colEPS(ptr++, linSize); // r
colEPS(ptr++, linSize); // g
colEPS(ptr++, linSize); // b
ptr += 3;
}
sptr += linSize * 2;
}
#else
int x,y;
int linSize = wid * 3;
unsigned char* sptr = src + 3;
unsigned char* ptr;
for (y = 1; y < hig - 1; y++) {
ptr = sptr;
for (x = 1; x < wid -1; x++) {
*ptr = (*(ptr - 3) >> 2) + (*ptr >> 1) + (*(ptr + 3) >> 2); ptr++;
*ptr = (*(ptr - 3) >> 2) + (*ptr >> 1) + (*(ptr + 3) >> 2); ptr++;
*ptr = (*(ptr - 3) >> 2) + (*ptr >> 1) + (*(ptr + 3) >> 2); ptr++;
}
sptr += linSize;
}
#endif
}
*/

View File

@ -5,8 +5,6 @@
#include "xcore.h"
int bytesPerLine = 100; // update on scrImg size changed
// resize srcw x srch @ src -> dstw x dsth @ dst
void scrFS(unsigned char* src, int srcw, int srch, unsigned char* dst, int dstw, int dsth) {
int scalex = (dstw << 8) / srcw;
@ -136,3 +134,60 @@ void scrX1(unsigned char* src, int srcw, int srch, unsigned char* dst) {
srch--;
}
}
#if VID_DIRECT_DRAW
#include <QApplication>
#include <QDesktopWidget>
void vid_upd_scale() {
int dwid;
int dhei;
if (conf.vid.fullScreen) {
dwid = QApplication::desktop()->width();
dhei = QApplication::desktop()->height();
xstep = dwid * 0x100 / conf.prof.cur->zx->vid->vsze.x;
ystep = dhei * 0x100 / conf.prof.cur->zx->vid->vsze.y;
if (conf.vid.keepRatio) {
int mstep = (xstep < ystep) ? xstep : ystep;
lefSkip = (xstep - mstep) * conf.prof.cur->zx->vid->vsze.x / 512 * 3;
rigSkip = lefSkip;
topSkip = (ystep - mstep) * conf.prof.cur->zx->vid->vsze.y / 512;
botSkip = topSkip;
xstep = mstep;
ystep = mstep;
} else {
lefSkip = 0;
rigSkip = 0;
topSkip = 0;
botSkip = 0;
}
} else {
lefSkip = 0;
rigSkip = 0;
topSkip = 0;
botSkip = 0;
xstep = conf.vid.scale << 8;
ystep = xstep;
}
// printf("%i x %i : %i %i %i : %X %X : %i %i %i %i\n",dwid,dhei,conf.vid.fullScreen, conf.vid.keepRatio, conf.vid.scale, xstep, ystep, topSkip, botSkip, lefSkip, rigSkip);
}
void vid_set_zoom(int zoom) {
if (zoom < 1) return;
if (zoom > 4) return;
conf.vid.scale = zoom;
vid_upd_scale();
}
void vid_set_fullscreen(int f) {
conf.vid.fullScreen = f ? 1 : 0;
vid_upd_scale();
}
void vid_set_ratio(int f) {
conf.vid.keepRatio = f ? 1 : 0;
vid_upd_scale();
}
#endif

View File

@ -1,5 +1,7 @@
#ifndef _VSCALERS_H
#define _VSCALERS_H
#ifndef X_VSCALERS_H
#define X_VSCALERS_H
#include "../libxpeccy/video/vidcommon.h"
void scrX1(unsigned char*, int, int, unsigned char*);
void scrX2(unsigned char*, int, int, unsigned char*);
@ -7,4 +9,12 @@ void scrX3(unsigned char*, int, int, unsigned char*);
void scrX4(unsigned char*, int, int, unsigned char*);
void scrFS(unsigned char*, int, int, unsigned char*, int, int);
#if VID_DIRECT_DRAW
void vid_set_zoom(int);
void vid_set_fullscreen(int);
void vid_set_ratio(int);
#endif
#endif

View File

@ -226,11 +226,11 @@ struct xConfig {
xProfile* cur;
} prof;
struct {
unsigned grayScale:1;
// unsigned grayScale:1;
unsigned fullScreen:1; // use fullscreen
unsigned keepRatio:1; // keep ratio in fullscreen (add black borders)
int scale; // x1..x4
int noflic; // 0 (noflic) .. 50 (full flick)
// int noflic; // 0 (noflic) .. 50 (full flick)
int fps;
} vid;
struct {

View File

@ -356,8 +356,8 @@ void SetupWin::start(xProfile* p) {
ui.cbFullscreen->setChecked(conf.vid.fullScreen);
ui.cbKeepRatio->setChecked(conf.vid.keepRatio);
ui.sbScale->setValue(conf.vid.scale);
ui.sldNoflic->setValue(conf.vid.noflic); chaflc();
ui.grayscale->setChecked(conf.vid.grayScale);
ui.sldNoflic->setValue(noflic); chaflc();
ui.grayscale->setChecked(greyScale);
ui.border4T->setChecked(comp->vid->brdstep & 0x06);
ui.contMem->setChecked(comp->contMem);
ui.contIO->setChecked(comp->contIO);
@ -377,6 +377,7 @@ void SetupWin::start(xProfile* p) {
// sound
ui.tbGS->setChecked(comp->gs->enable);
ui.gsrbox->setChecked(comp->gs->reset);
ui.cbdac->setChecked(ayDac);
ui.sdrvBox->setCurrentIndex(ui.sdrvBox->findData(comp->sdrv->type));
@ -507,8 +508,8 @@ void SetupWin::apply() {
conf.vid.keepRatio = ui.cbKeepRatio->isChecked() ? 1 : 0;
conf.vid.scale = ui.sbScale->value();
// conf.vid.noFlick = ui.noflichk->isChecked() ? 1 : 0;
conf.vid.noflic = ui.sldNoflic->value();
conf.vid.grayScale = ui.grayscale->isChecked() ? 1 : 0;
noflic = ui.sldNoflic->value();
greyScale = ui.grayscale->isChecked() ? 1 : 0;
conf.scrShot.dir = std::string(ui.pathle->text().toLocal8Bit().data());
conf.scrShot.format = getRFText(ui.ssfbox);
conf.scrShot.count = ui.scntbox->value();
@ -524,7 +525,7 @@ void SetupWin::apply() {
// sound
std::string nname = getRFText(ui.outbox);
conf.snd.enabled = ui.senbox->isChecked() ? 1 : 0;
// conf.snd.mute = ui.mutbox->isChecked() ? 1 : 0;
ayDac = ui.cbdac->isChecked() ? 1 : 0;
conf.snd.rate = getRFIData(ui.ratbox);
conf.snd.vol.master = ui.sbMasterVol->value();

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>505</width>
<height>412</height>
<width>545</width>
<height>443</height>
</rect>
</property>
<property name="sizePolicy">
@ -760,6 +760,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbdac">
<property name="text">
<string>DAC</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_3">
<property name="orientation">

View File

@ -74,5 +74,6 @@
<file>images/tapeRed.png</file>
<file>images/tapeYellow.png</file>
<file>images/mouseWhite.png</file>
<file>font.png</file>
</qresource>
</RCC>