diff --git a/Release b/Release index e73cc2e8..b444cb8c 100644 --- a/Release +++ b/Release @@ -1 +1 @@ -0.6.20180819 +0.6.20180913 diff --git a/font.png b/font.png new file mode 100644 index 00000000..a1f68ab9 Binary files /dev/null and b/font.png differ diff --git a/src/emulwin.cpp b/src/emulwin.cpp index 6fafee03..103f6742 100644 --- a/src/emulwin.cpp +++ b/src/emulwin.cpp @@ -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(ðread,SIGNAL(dbgRequest()),SLOT(doDebug())); connect(ðread,SIGNAL(tapeSignal(int,int)),this,SLOT(tapStateChanged(int,int))); +#if !VID_DIRECT_DRAW connect(ðread,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++); diff --git a/src/emulwin.h b/src/emulwin.h index c8f7cf73..4e9fef30 100644 --- a/src/emulwin.h +++ b/src/emulwin.h @@ -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 diff --git a/src/ethread.cpp b/src/ethread.cpp index b8f5c270..42862a0b 100644 --- a/src/ethread.cpp +++ b/src/ethread.cpp @@ -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 diff --git a/src/ethread.h b/src/ethread.h index 7f7c6176..5b58d79f 100644 --- a/src/ethread.h +++ b/src/ethread.h @@ -1,5 +1,5 @@ -#ifndef _ETHREAD_H -#define _ETHREAD_H +#ifndef X_ETHREAD_H +#define X_ETHREAD_H #include #include @@ -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; diff --git a/src/libxpeccy/hardware/scorpion.c b/src/libxpeccy/hardware/scorpion.c index 5d744e0d..795498f4 100644 --- a/src/libxpeccy/hardware/scorpion.c +++ b/src/libxpeccy/hardware/scorpion.c @@ -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); } diff --git a/src/libxpeccy/sound/ayym.c b/src/libxpeccy/sound/ayym.c index 1e7a795d..e9d7b30e 100644 --- a/src/libxpeccy/sound/ayym.c +++ b/src/libxpeccy/sound/ayym.c @@ -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: diff --git a/src/libxpeccy/sound/ayym.h b/src/libxpeccy/sound/ayym.h index ebe82d36..be533988 100644 --- a/src/libxpeccy/sound/ayym.h +++ b/src/libxpeccy/sound/ayym.h @@ -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, diff --git a/src/libxpeccy/video/v9938.c b/src/libxpeccy/video/v9938.c index 55d979fb..23e256da 100644 --- a/src/libxpeccy/video/v9938.c +++ b/src/libxpeccy/video/v9938.c @@ -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; } } diff --git a/src/libxpeccy/video/vidcommon.h b/src/libxpeccy/video/vidcommon.h index c2936e5d..78e70049 100644 --- a/src/libxpeccy/video/vidcommon.h +++ b/src/libxpeccy/video/vidcommon.h @@ -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 diff --git a/src/libxpeccy/video/video.c b/src/libxpeccy/video/video.c index 1c82d0c8..635c1f14 100644 --- a/src/libxpeccy/video/video.c +++ b/src/libxpeccy/video/video.c @@ -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; diff --git a/src/libxpeccy/video/video.h b/src/libxpeccy/video/video.h index 5a825009..e69ff0c5 100644 --- a/src/libxpeccy/video/video.h +++ b/src/libxpeccy/video/video.h @@ -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; diff --git a/src/version.h b/src/version.h index ad354cdb..57e90b2d 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define VERSION 0.6.20180819 +#define VERSION 0.6.20180913 diff --git a/src/xcore/config.cpp b/src/xcore/config.cpp index 4de19bfa..e2266ecb 100644 --- a/src/xcore/config.cpp +++ b/src/xcore/config.cpp @@ -6,7 +6,8 @@ #include #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 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 -} -*/ diff --git a/src/xcore/vscalers.cpp b/src/xcore/vscalers.cpp index d73f6b65..057546be 100644 --- a/src/xcore/vscalers.cpp +++ b/src/xcore/vscalers.cpp @@ -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 +#include + +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 diff --git a/src/xcore/vscalers.h b/src/xcore/vscalers.h index 75b2df7a..95379e1a 100644 --- a/src/xcore/vscalers.h +++ b/src/xcore/vscalers.h @@ -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 diff --git a/src/xcore/xcore.h b/src/xcore/xcore.h index b446fa9c..94bf7f45 100644 --- a/src/xcore/xcore.h +++ b/src/xcore/xcore.h @@ -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 { diff --git a/src/xgui/options/setupwin.cpp b/src/xgui/options/setupwin.cpp index e98a40be..a5b6ca98 100644 --- a/src/xgui/options/setupwin.cpp +++ b/src/xgui/options/setupwin.cpp @@ -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(); diff --git a/ui/setupwin.ui b/ui/setupwin.ui index fd372dcd..dca498ab 100755 --- a/ui/setupwin.ui +++ b/ui/setupwin.ui @@ -6,8 +6,8 @@ 0 0 - 505 - 412 + 545 + 443 @@ -760,6 +760,13 @@ + + + + DAC + + + diff --git a/xpeccy.qrc b/xpeccy.qrc index 35d5c85f..789f2245 100755 --- a/xpeccy.qrc +++ b/xpeccy.qrc @@ -74,5 +74,6 @@ images/tapeRed.png images/tapeYellow.png images/mouseWhite.png + font.png