prepare for 0.6.2

This commit is contained in:
tildearrow 2024-03-31 23:35:59 -05:00
parent 90859be901
commit 90c628612e
28 changed files with 4946 additions and 46 deletions

Binary file not shown.

View file

@ -190,7 +190,6 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data)
// Bind texture, Draw
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
SDL_SetTextureScaleMode(tex, SDL_ScaleModeBest); // ???
SDL_RenderGeometryRaw(bd->SDLRenderer, tex,
xy, (int)sizeof(ImDrawVert),
color, (int)sizeof(ImDrawVert),

44
extern/opn/ym3438.c vendored
View file

@ -39,6 +39,42 @@ enum {
eg_num_release = 3
};
/* msw table */
static const Bit16u mswrom[256] = {
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600, 0x600,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000
};
/* logsin table */
static const Bit16u logsinrom[256] = {
0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471,
@ -1052,7 +1088,7 @@ static void OPN2_FMGenerate(ym3438_t *chip)
{
quarter = phase & 0xff;
}
level = logsinrom[quarter];
level = chip->msw ? mswrom[quarter] : logsinrom[quarter];
/* Apply envelope */
level += chip->eg_out[slot] << 2;
/* Transform */
@ -1198,6 +1234,7 @@ void OPN2_Reset(ym3438_t *chip)
Bit32u i;
memset(chip, 0, sizeof(ym3438_t));
chip->chip_type = ym3438_mode_readmode;
chip->msw = 0;
for (i = 0; i < 24; i++)
{
chip->eg_out[i] = 0x3ff;
@ -1217,6 +1254,11 @@ void OPN2_SetChipType(ym3438_t *chip, Bit32u type)
chip->chip_type = type;
}
void OPN2_SetMSW(ym3438_t *chip, Bit32u msw)
{
chip->msw = msw;
}
void OPN2_Clock(ym3438_t *chip, Bit16s *buffer)
{
Bit32u slot = chip->cycles;

2
extern/opn/ym3438.h vendored
View file

@ -124,6 +124,7 @@ typedef struct
Bit8u eg_read_inc;
/* Settings */
Bit8u chip_type;
Bit8u msw;
/* FM */
Bit16s fm_op1[6][2];
Bit16s fm_op2[6];
@ -201,6 +202,7 @@ typedef struct
void OPN2_Reset(ym3438_t *chip);
void OPN2_SetChipType(ym3438_t *chip, Bit32u type);
void OPN2_SetMSW(ym3438_t *chip, Bit32u msw);
void OPN2_Clock(ym3438_t *chip, Bit16s *buffer);
void OPN2_Write(ym3438_t *chip, Bit32u port, Bit8u data);
void OPN2_SetTestPin(ym3438_t *chip, Bit32u value);

2
res/make-tile.sh Executable file
View file

@ -0,0 +1,2 @@
#!/bin/bash
xxd -i -n tileDataC tile.gif | sed -r "s/^ +//g;s/, /,/g;s/ = /=/g;s/unsigned/static const unsigned/g" > ../src/gui/tileData.h

BIN
res/tile.data.pal Normal file

Binary file not shown.

BIN
res/tile.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -253,6 +253,12 @@ void DivEngine::walkSong(int& loopOrder, int& loopRow, int& loopEnd) {
}
}
void DivEngine::setNumTimesPlayed(int count) {
numTimesPlayed=count;
crossedPatterns=count;
if (count==-1) crossedPatterns=0;
}
#define EXPORT_BUFSIZE 2048
double DivEngine::benchmarkPlayback() {
@ -2144,6 +2150,9 @@ void DivEngine::reset() {
elapsedBeats=0;
nextSpeed=speeds.val[0];
divider=curSubSong->hz;
if (numTimesPlayed>=0) {
divider*=1.0+(double)(MAX(numTimesPlayed-6,0))*0.04;
}
globalPitch=0;
for (int i=0; i<song.systemLen; i++) {
disCont[i].dispatch->reset();
@ -3366,6 +3375,8 @@ bool DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
int finalChan=midiBaseChan;
int finalChanType=getChannelType(finalChan);
if (note==84 && numTimesPlayed>=0) return false;
if (!playing) {
reset();
freelance=true;
@ -3493,6 +3504,9 @@ void DivEngine::setSongRate(float hz) {
saveLock.lock();
curSubSong->hz=hz;
divider=curSubSong->hz;
if (numTimesPlayed>=0) {
divider*=1.0+(double)(MAX(numTimesPlayed-6,0))*0.04;
}
saveLock.unlock();
BUSY_END;
}

View file

@ -436,6 +436,8 @@ class DivEngine {
int cycles;
double clockDrift;
int midiClockCycles;
int numTimesPlayed;
int crossedPatterns;
double midiClockDrift;
int midiTimeCycles;
double midiTimeDrift;
@ -747,6 +749,9 @@ class DivEngine {
// find song loop position
void walkSong(int& loopOrder, int& loopRow, int& loopEnd);
// set number of times the song has played
void setNumTimesPlayed(int count);
// play (returns whether successful)
bool play();
@ -1325,6 +1330,8 @@ class DivEngine {
cycles(0),
clockDrift(0),
midiClockCycles(0),
numTimesPlayed(0),
crossedPatterns(0),
midiClockDrift(0),
midiTimeCycles(0),
midiTimeDrift(0),

View file

@ -1661,6 +1661,7 @@ void DivPlatformGenesis::reset() {
OPN2_SetChipType(&fm,0);
break;
}
OPN2_SetMSW(&fm,msw?1:0);
if (dumpWrites) {
addWrite(0xffffffff,0);
}
@ -1766,6 +1767,7 @@ void DivPlatformGenesis::setFlags(const DivConfig& flags) {
}
noExtMacros=flags.getBool("noExtMacros",false);
fbAllOps=flags.getBool("fbAllOps",false);
msw=flags.getBool("msw",false);
switch (chipType) {
case 1: // YM2612
OPN2_SetChipType(&fm,ym3438_mode_ym2612);
@ -1777,6 +1779,7 @@ void DivPlatformGenesis::setFlags(const DivConfig& flags) {
OPN2_SetChipType(&fm,0);
break;
}
OPN2_SetMSW(&fm,msw?1:0);
CHECK_CUSTOM_CLOCK;
if (useYMFM==1) {
if (fm_ymfm!=NULL) delete fm_ymfm;

View file

@ -87,7 +87,7 @@ class DivPlatformGenesis: public DivPlatformOPN {
int softPCMTimer;
bool extMode, softPCM, noExtMacros, canWriteDAC;
bool extMode, softPCM, noExtMacros, canWriteDAC, msw;
unsigned char useYMFM;
unsigned char chipType;
short dacWrite;

View file

@ -36,6 +36,17 @@ void DivEngine::nextOrder() {
endOfSong=true;
memset(walked,0,8192);
curOrder=0;
if (numTimesPlayed>=0) {
numTimesPlayed++;
divider=curSubSong->hz*(1.0+(double)(MAX(numTimesPlayed-6,0))*0.04);
}
}
if (numTimesPlayed>2 && !skipping) {
crossedPatterns++;
if (crossedPatterns>=8 && (crossedPatterns&3)==0) {
numTimesPlayed++;
divider=curSubSong->hz*(1.0+(double)(MAX(numTimesPlayed-6,0))*0.04);
}
}
}
@ -621,6 +632,14 @@ void DivEngine::processRow(int i, bool afterDelay) {
} else if (!(pat->data[whatRow][0]==0 && pat->data[whatRow][1]==0)) {
chan[i].oldNote=chan[i].note;
chan[i].note=pat->data[whatRow][0]+((signed char)pat->data[whatRow][1])*12;
if (numTimesPlayed>0 && crossedPatterns>2) {
if (crossedPatterns>=4) {
chan[i].note+=(int)(MAX(0,pow(MAX(0,crossedPatterns-4),1.2)))>>2;
}
if ((rand()%MAX(1,60-crossedPatterns))==0) {
chan[i].note=12+(rand()&63);
}
}
if (!chan[i].keyOn) {
if (disCont[dispatchOfChan[i]].dispatch->keyOffAffectsArp(dispatchChanOfChan[i])) {
chan[i].arp=0;
@ -890,6 +909,9 @@ void DivEngine::processRow(int i, bool afterDelay) {
break;
case 0xc0: case 0xc1: case 0xc2: case 0xc3: // set Hz
divider=(double)(((effect&0x3)<<8)|effectVal);
if (numTimesPlayed>=0) {
divider*=1.0+(double)(MAX(numTimesPlayed-6,0))*0.04;
}
if (divider<1) divider=1;
cycles=got.rate*pow(2,MASTER_CLOCK_PREC)/divider;
clockDrift=0;
@ -1022,6 +1044,9 @@ void DivEngine::processRow(int i, bool afterDelay) {
break;
case 0xf0: // set Hz by tempo
divider=(double)effectVal*2.0/5.0;
if (numTimesPlayed>=0) {
divider*=1.0+(double)(MAX(numTimesPlayed-6,0))*0.04;
}
if (divider<1) divider=1;
cycles=got.rate*pow(2,MASTER_CLOCK_PREC)/divider;
clockDrift=0;

View file

@ -374,6 +374,16 @@ void FurnaceGUI::drawAbout() {
while (aboutSin>=2400) aboutSin-=2400;
if (aboutScroll>(42*dpiScale*aboutCount+canvasH)) aboutScroll=-20*dpiScale;
if (ImGui::IsKeyPressed(ImGuiKey_Space) && !shaderEditor) {
aboutOpen=false;
if (modified) {
showWarning("Unsaved changes! Save changes before playing?",GUI_WARN_CV);
} else {
cvOpen=true;
cvNotSerious=true;
}
}
WAKE_UP;
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_ABOUT;

View file

@ -592,6 +592,10 @@ void FurnaceGUI::drawMobileControls() {
memoryOpen=!memoryOpen;
}
if (ImGui::Button("CV")) {
cvOpen=!cvOpen;
}
ImGui::Separator();
ImGui::Button("Panic");
@ -614,9 +618,6 @@ void FurnaceGUI::drawMobileControls() {
mobileMenuPos=0.0f;
aboutOpen=true;
}
if (ImGui::Button("Shader Editor")) {
shaderEditor=!shaderEditor;
}
if (ImGui::Button("Switch to Desktop Mode")) {
toggleMobileUI(!mobileUI);
}

302
src/gui/gif_load.h Normal file
View file

@ -0,0 +1,302 @@
#ifndef GIF_LOAD_H
#define GIF_LOAD_H
/** gif_load: A slim, fast and header-only GIF loader written in C.
Original author: hidefromkgb (hidefromkgb@gmail.com)
_________________________________________________________________________
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
_________________________________________________________________________
**/
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h> /** imports uint8_t, uint16_t and uint32_t **/
#ifndef GIF_MGET
#include <stdlib.h>
#define GIF_MGET(m,s,a,c) m = (uint8_t*)realloc((c)? 0 : m, (c)? s : 0UL);
#endif
#ifndef GIF_BIGE
#define GIF_BIGE 0
#endif
#ifndef GIF_EXTR
#define GIF_EXTR static
#endif
#define _GIF_SWAP(h) ((GIF_BIGE)? ((uint16_t)(h << 8) | (h >> 8)) : h)
#pragma pack(push, 1)
struct GIF_WHDR { /** ======== frame writer info: ======== **/
long xdim, ydim, clrs, /** global dimensions, palette size **/
bkgd, tran, /** background index, transparent index **/
intr, mode, /** interlace flag, frame blending mode **/
frxd, fryd, frxo, fryo, /** current frame dimensions and offset **/
time, ifrm, nfrm; /** delay, frame number, frame count **/
uint8_t *bptr; /** frame pixel indices or metadata **/
struct { /** [==== GIF RGB palette element: ====] **/
uint8_t R, G, B; /** [color values - red, green, blue ] **/
} *cpal; /** current palette **/
};
#pragma pack(pop)
enum {GIF_NONE = 0, GIF_CURR = 1, GIF_BKGD = 2, GIF_PREV = 3};
/** [ internal function, do not use ] **/
static long _GIF_SkipChunk(uint8_t **buff, long size) {
long skip;
for (skip = 2, ++size, ++(*buff); ((size -= skip) > 0) && (skip > 1);
*buff += (skip = 1 + **buff));
return size;
}
/** [ internal function, do not use ] **/
static long _GIF_LoadHeader(unsigned gflg, uint8_t **buff, void **rpal,
unsigned fflg, long *size, long flen) {
if (flen && (!(*buff += flen) || ((*size -= flen) <= 0)))
return -2; /** v--[ 0x80: "palette is present" flag ]--, **/
if (flen && (fflg & 0x80)) { /** local palette has priority | **/
*rpal = *buff; /** [ 3L: 3 uint8_t color channels ]--, | **/
*buff += (flen = 2 << (fflg & 7)) * 3L; /** <--| | **/
return ((*size -= flen * 3L) > 0)? flen : -1; /** <--' | **/
} /** no local palette found, checking for the global one | **/
return (gflg & 0x80)? (2 << (gflg & 7)) : 0; /** <-----' **/
}
/** [ internal function, do not use ] **/
static long _GIF_LoadFrame(uint8_t **buff, long *size,
uint8_t *bptr, uint8_t *blen) {
typedef uint16_t GIF_H;
const long GIF_HLEN = sizeof(GIF_H), /** to rid the scope of sizeof **/
GIF_CLEN = 1 << 12; /** code table length: 4096 items **/
GIF_H accu, mask; /** bit accumulator / bit mask **/
long ctbl, iter, /** last code table index / index string iterator **/
prev, curr, /** codes from the stream: previous / current **/
ctsz, ccsz, /** code table bit sizes: min LZW / current **/
bseq, bszc; /** counters: block sequence / bit size **/
uint32_t *code = (uint32_t*)bptr - GIF_CLEN; /** code table pointer **/
/** preparing initial values **/
if ((--(*size) <= GIF_HLEN) || !*++(*buff))
return -4; /** unexpected end of the stream: insufficient size **/
mask = (GIF_H)((1 << (ccsz = (ctsz = *(*buff - 1)) + 1)) - 1);
if ((ctsz < 2) || (ctsz > 8))
return -3; /** min LZW size is out of its nominal [2; 8] bounds **/
if ((ctbl = (1L << ctsz)) != (mask & _GIF_SWAP(*(GIF_H*)(*buff + 1))))
return -2; /** initial code is not equal to min LZW size **/
for (curr = ++ctbl; curr; code[--curr] = 0); /** actual color codes **/
/** getting codes from stream (--size makes up for end-of-stream mark) **/
for (--(*size), bszc = -ccsz, prev = curr = 0;
((*size -= (bseq = *(*buff)++) + 1) >= 0) && bseq; *buff += bseq)
for (; bseq > 0; bseq -= GIF_HLEN, *buff += GIF_HLEN)
for (accu = (GIF_H)(_GIF_SWAP(*(GIF_H*)*buff)
& ((bseq < GIF_HLEN)? ((1U << (8 * bseq)) - 1U) : ~0U)),
curr |= accu << (ccsz + bszc), accu = (GIF_H)(accu >> -bszc),
bszc += 8 * ((bseq < GIF_HLEN)? bseq : GIF_HLEN);
bszc >= 0; bszc -= ccsz, prev = curr, curr = accu,
accu = (GIF_H)(accu >> ccsz))
if (((curr &= mask) & ~1L) == (1L << ctsz)) {
if (~(ctbl = curr + 1) & 1) /** end-of-data code (ED). **/
/** -1: no end-of-stream mark after ED; 1: decoded **/
return (*((*buff += bseq + 1) - 1))? -1 : 1;
mask = (GIF_H)((1 << (ccsz = ctsz + 1)) - 1);
} /** ^- table drop code (TD). TD = 1 << ctsz, ED = TD + 1 **/
else { /** single-pixel (SP) or multi-pixel (MP) code. **/
if (ctbl < GIF_CLEN) { /** is the code table full? **/
if ((ctbl == mask) && (ctbl < GIF_CLEN - 1)) {
mask = (GIF_H)(mask + mask + 1);
ccsz++; /** yes; extending **/
} /** prev = TD? => curr < ctbl = prev **/
code[ctbl] = (uint32_t)prev + (code[prev] & 0xFFF000);
} /** appending SP / MP decoded pixels to the frame **/
prev = (long)code[iter = (ctbl > curr)? curr : prev];
if ((bptr += (prev = (prev >> 12) & 0xFFF)) > blen)
continue; /** skipping pixels above frame capacity **/
for (prev++; (iter &= 0xFFF) >> ctsz;
*bptr-- = (uint8_t)((iter = (long)code[iter]) >> 24));
(bptr += prev)[-prev] = (uint8_t)iter;
if (ctbl < GIF_CLEN) { /** appending the code table **/
if (ctbl == curr)
*bptr++ = (uint8_t)iter;
else if (ctbl < curr)
return -5; /** wrong code in the stream **/
code[ctbl++] += ((uint32_t)iter << 24) + 0x1000;
}
} /** 0: no ED before end-of-stream mark; -4: see above **/
return (++(*size) >= 0)? 0 : -4; /** ^- N.B.: 0 error is recoverable **/
}
/** _________________________________________________________________________
The main loading function. Returns the total number of frames if the data
includes proper GIF ending, and otherwise it returns the number of frames
loaded per current call, multiplied by -1. So, the data may be incomplete
and in this case the function can be called again when more data arrives,
just remember to keep SKIP up to date.
_________________________________________________________________________
DATA: raw data chunk, may be partial
SIZE: size of the data chunk that`s currently present
GWFR: frame writer function, MANDATORY
EAMF: metadata reader function, set to 0 if not needed
ANIM: implementation-specific data (e.g. a structure or a pointer to it)
SKIP: number of frames to skip before resuming
**/
GIF_EXTR long GIF_Load(void *data, long size,
void (*gwfr)(void*, struct GIF_WHDR*),
void (*eamf)(void*, struct GIF_WHDR*),
void *anim, long skip) {
const long GIF_BLEN = (1 << 12) * sizeof(uint32_t);
const uint8_t GIF_EHDM = 0x21, /** extension header mark **/
GIF_FHDM = 0x2C, /** frame header mark **/
GIF_EOFM = 0x3B, /** end-of-file mark **/
GIF_EGCM = 0xF9, /** extension: graphics control mark **/
GIF_EAMM = 0xFF; /** extension: app metadata mark **/
#pragma pack(push, 1)
struct GIF_GHDR { /** ========== GLOBAL GIF HEADER: ========== **/
uint8_t head[6]; /** 'GIF87a' / 'GIF89a' header signature **/
uint16_t xdim, ydim; /** total image width, total image height **/
uint8_t flgs; /** FLAGS:
GlobalPlt bit 7 1: global palette exists
0: local in each frame
ClrRes bit 6-4 bits/channel = ClrRes+1
[reserved] bit 3 0
PixelBits bit 2-0 |Plt| = 2 * 2^PixelBits
**/
uint8_t bkgd, aspr; /** background color index, aspect ratio **/
} *ghdr = (struct GIF_GHDR*)data;
struct GIF_FHDR { /** ======= GIF FRAME MASTER HEADER: ======= **/
uint16_t frxo, fryo; /** offset of this frame in a "full" image **/
uint16_t frxd, fryd; /** frame width, frame height **/
uint8_t flgs; /** FLAGS:
LocalPlt bit 7 1: local palette exists
0: global is used
Interlaced bit 6 1: interlaced frame
0: non-interlaced frame
Sorted bit 5 usually 0
[reserved] bit 4-3 [undefined]
PixelBits bit 2-0 |Plt| = 2 * 2^PixelBits
**/
} *fhdr;
struct GIF_EGCH { /** ==== [EXT] GRAPHICS CONTROL HEADER: ==== **/
uint8_t flgs; /** FLAGS:
[reserved] bit 7-5 [undefined]
BlendMode bit 4-2 000: not set; static GIF
001: leave result as is
010: restore background
011: restore previous
1--: [undefined]
UserInput bit 1 1: show frame till input
0: default; ~99% of GIFs
TransColor bit 0 1: got transparent color
0: frame is fully opaque
**/
uint16_t time; /** delay in GIF time units; 1 unit = 10 ms **/
uint8_t tran; /** transparent color index **/
} *egch = 0;
#pragma pack(pop)
struct GIF_WHDR wtmp, whdr;
long desc, blen;
uint8_t *buff;
memset(&wtmp,0,sizeof(struct GIF_WHDR));
memset(&whdr,0,sizeof(struct GIF_WHDR));
/** checking if the stream is not empty and has a 'GIF8[79]a' signature,
the data has sufficient size and frameskip value is non-negative **/
if (!ghdr || (size <= (long)sizeof(*ghdr)) || (*(buff = ghdr->head) != 71)
|| (buff[1] != 73) || (buff[2] != 70) || (buff[3] != 56) || (skip < 0)
|| ((buff[4] != 55) && (buff[4] != 57)) || (buff[5] != 97) || !gwfr)
return 0;
buff = (uint8_t*)(ghdr + 1) /** skipping the global header and palette **/
+ _GIF_LoadHeader(ghdr->flgs, 0, 0, 0, 0, 0L) * 3L;
if ((size -= buff - (uint8_t*)ghdr) <= 0)
return 0;
whdr.xdim = _GIF_SWAP(ghdr->xdim);
whdr.ydim = _GIF_SWAP(ghdr->ydim);
for (whdr.bptr = buff, whdr.bkgd = ghdr->bkgd, blen = --size;
(blen >= 0) && ((desc = *whdr.bptr++) != GIF_EOFM); /** sic: '>= 0' **/
blen = _GIF_SkipChunk(&whdr.bptr, blen) - 1) /** count all frames **/
if (desc == GIF_FHDM) {
fhdr = (struct GIF_FHDR*)whdr.bptr;
if (_GIF_LoadHeader(ghdr->flgs, &whdr.bptr, (void**)&whdr.cpal,
fhdr->flgs, &blen, sizeof(*fhdr)) <= 0)
break;
whdr.frxd = _GIF_SWAP(fhdr->frxd);
whdr.fryd = _GIF_SWAP(fhdr->fryd);
whdr.frxo = (whdr.frxd > whdr.frxo)? whdr.frxd : whdr.frxo;
whdr.fryo = (whdr.fryd > whdr.fryo)? whdr.fryd : whdr.fryo;
whdr.ifrm++;
}
blen = whdr.frxo * whdr.fryo * (long)sizeof(*whdr.bptr);
GIF_MGET(whdr.bptr, (unsigned long)(blen + GIF_BLEN + 2), anim, 1)
whdr.nfrm = (desc != GIF_EOFM)? -whdr.ifrm : whdr.ifrm;
for (whdr.bptr += GIF_BLEN, whdr.ifrm = -1; blen /** load all frames **/
&& (skip < ((whdr.nfrm < 0)? -whdr.nfrm : whdr.nfrm)) && (size >= 0);
size = (desc != GIF_EOFM)? ((desc != GIF_FHDM) || (skip > whdr.ifrm))?
_GIF_SkipChunk(&buff, size) - 1 : size - 1 : -1)
if ((desc = *buff++) == GIF_FHDM) { /** found a frame **/
whdr.intr = !!((fhdr = (struct GIF_FHDR*)buff)->flgs & 0x40);
*(void**)&whdr.cpal = (void*)(ghdr + 1); /** interlaced? -^ **/
whdr.clrs = _GIF_LoadHeader(ghdr->flgs, &buff, (void**)&whdr.cpal,
fhdr->flgs, &size, sizeof(*fhdr));
if ((skip <= ++whdr.ifrm) && ((whdr.clrs <= 0)
|| (_GIF_LoadFrame(&buff, &size,
whdr.bptr, whdr.bptr + blen) < 0)))
size = -(whdr.ifrm--) - 1; /** failed to load the frame **/
else if (skip <= whdr.ifrm) {
whdr.frxd = _GIF_SWAP(fhdr->frxd);
whdr.fryd = _GIF_SWAP(fhdr->fryd);
whdr.frxo = _GIF_SWAP(fhdr->frxo);
whdr.fryo = _GIF_SWAP(fhdr->fryo);
whdr.time = (egch)? _GIF_SWAP(egch->time) : 0;
whdr.tran = (egch && (egch->flgs & 0x01))? egch->tran : -1;
whdr.time = (egch && (egch->flgs & 0x02))? -whdr.time - 1
: whdr.time;
whdr.mode = (egch && !(egch->flgs & 0x10))?
(egch->flgs & 0x0C) >> 2 : GIF_NONE;
egch = 0;
wtmp = whdr;
gwfr(anim, &wtmp); /** passing the frame to the caller **/
}
}
else if (desc == GIF_EHDM) { /** found an extension **/
if (*buff == GIF_EGCM) /** graphics control ext. **/
egch = (struct GIF_EGCH*)(buff + 1 + 1);
else if ((*buff == GIF_EAMM) && eamf) { /** app metadata ext. **/
wtmp = whdr;
wtmp.bptr = buff + 1 + 1; /** just passing the raw chunk **/
eamf(anim, &wtmp);
}
}
whdr.bptr -= GIF_BLEN; /** for excess pixel codes ----v (here & above) **/
GIF_MGET(whdr.bptr, (unsigned long)(blen + GIF_BLEN + 2), anim, 0)
return (whdr.nfrm < 0)? (skip - whdr.ifrm - 1) : (whdr.ifrm + 1);
}
#undef _GIF_SWAP
#ifdef __cplusplus
}
#endif
#endif /** GIF_LOAD_H **/

View file

@ -1117,6 +1117,12 @@ void FurnaceGUI::play(int row) {
if (e->getStreamPlayer()) {
e->killStream();
}
if (shaderEditor) {
numTimesPlayed++;
e->setNumTimesPlayed(numTimesPlayed);
} else {
e->setNumTimesPlayed(-1);
}
memset(chanOscVol,0,DIV_MAX_CHANS*sizeof(float));
for (int i=0; i<DIV_MAX_CHANS; i++) {
chanOscChan[i].pitch=0.0f;
@ -1147,6 +1153,50 @@ void FurnaceGUI::setOrder(unsigned char order, bool forced) {
}
void FurnaceGUI::stop() {
if (shaderEditor) {
if (numTimesPlayed>=25) {
switch (numTimesPlayed) {
case 25:
showError("*bleep*\n\n\nAccess Denied");
break;
case 26:
showError("*bleep*\n\n\nAccess Is Denied");
break;
case 27:
showError("*bleep*\n\n\nUnauthorized Access");
break;
case 28:
showError("*bleep*\n\n\nIllegal Access");
break;
case 29:
showError("Please, move away from the stop button");
break;
case 30:
showError("You will not stop the song");
break;
case 31:
showError("Move on immediately");
break;
case 32:
showError("You will not stop the song!");
break;
case 33:
showError("No, no and no!");
break;
case 34:
showError("Will we do this all day?");
break;
case 35:
showError("");
break;
default:
showError("YOU HAVE NO CHOICE.");
break;
}
numTimesPlayed++;
return;
}
}
bool wasPlaying=e->isPlaying();
e->walkSong(loopOrder,loopRow,loopEnd);
e->stop();
@ -1194,6 +1244,11 @@ void FurnaceGUI::noteInput(int num, int key, int vol) {
DivPattern* pat=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][curOrder],true);
bool removeIns=false;
if (shaderEditor && num==84) {
showError("This note is reserved for the Master. You may not use it.");
return;
}
prepareUndo(GUI_UNDO_PATTERN_EDIT);
if (key==GUI_NOTE_OFF) { // note off
@ -1370,6 +1425,7 @@ void FurnaceGUI::keyDown(SDL_Event& ev) {
if (introPos<11.0 && !shortIntro) return;
if (ImGuiFileDialog::Instance()->IsOpened()) return;
if (aboutOpen) return;
if (cvOpen) return;
int mapped=ev.key.keysym.sym;
if (ev.key.keysym.mod&KMOD_CTRL) {
@ -2264,6 +2320,18 @@ int FurnaceGUI::load(String path) {
// warn the user
showWarning("you have loaded a backup!\nif you need to, please save it somewhere.\n\nDO NOT RELY ON THE BACKUP SYSTEM FOR AUTO-SAVE!\nFurnace will not save backups of backups.",GUI_WARN_GENERIC);
}
if (!cvOpen && shaderEditor) {
for (int i=0; i<e->song.systemLen; i++) {
if (e->song.system[i]==DIV_SYSTEM_YM2612 ||
e->song.system[i]==DIV_SYSTEM_YM2612_EXT ||
e->song.system[i]==DIV_SYSTEM_YM2612_CSM ||
e->song.system[i]==DIV_SYSTEM_YM2612_DUALPCM ||
e->song.system[i]==DIV_SYSTEM_YM2612_DUALPCM_EXT) {
showWarning("pure sine wave YM2612s are becoming expensive!\nwhy not try out the new Modified Sine Wave YM2612?\nequivalent quality, without the price!\ngo to file > manage chips for more details.",GUI_WARN_GENERIC);
break;
}
}
}
return 0;
}
@ -3095,6 +3163,7 @@ int FurnaceGUI::processEvent(SDL_Event* ev) {
e->saveConf();
}
#endif
if (cvOpen) return 1;
if (ev->type==SDL_KEYDOWN) {
if (!ev->key.repeat && latchTarget==0 && !wantCaptureKeyboard && !sampleMapWaitingInput && (ev->key.keysym.mod&(~(VALID_MODS)))==0) {
if (settings.notePreviewBehavior==0) return 1;
@ -4340,6 +4409,11 @@ bool FurnaceGUI::loop() {
if (ImGui::MenuItem("restore backup",BIND_FOR(GUI_ACTION_OPEN_BACKUP))) {
doAction(GUI_ACTION_OPEN_BACKUP);
}
if (numTimesPlayed>3) {
if (ImGui::MenuItem("Enable Serious Mode")) {
cvOpen=true;
}
}
ImGui::Separator();
if (ImGui::MenuItem("exit...",BIND_FOR(GUI_ACTION_QUIT))) {
requestQuit();
@ -4385,9 +4459,11 @@ bool FurnaceGUI::loop() {
toggleMobileUI(!mobileUI);
}
#endif
/*
if (ImGui::MenuItem("manage presets...",BIND_FOR(GUI_ACTION_WINDOW_USER_PRESETS))) {
userPresetsOpen=true;
}
*/
if (ImGui::MenuItem("settings...",BIND_FOR(GUI_ACTION_WINDOW_SETTINGS))) {
syncSettings();
settingsOpen=true;
@ -4715,32 +4791,6 @@ bool FurnaceGUI::loop() {
MEASURE(userPresets,drawUserPresets());
}
// NEW CODE - REMOVE WHEN DONE
if (shaderEditor) {
if (ImGui::Begin("Shader Editor 2024",&shaderEditor,ImGuiWindowFlags_NoScrollWithMouse|ImGuiWindowFlags_NoScrollbar)) {
ImGui::PushFont(patFont);
ImGui::InputTextMultiline("##SHFragment",&newOscFragment,ImVec2(ImGui::GetContentRegionAvail().x,ImGui::GetContentRegionAvail().y-ImGui::GetFrameHeightWithSpacing()),ImGuiInputTextFlags_UndoRedo);
ImGui::PopFont();
if (ImGui::Button("Save")) {
FILE* f=ps_fopen("/storage/emulated/0/osc.fsh","w");
if (f==NULL) {
showError("Something happened");
} else {
fwrite(newOscFragment.c_str(),1,newOscFragment.size(),f);
fclose(f);
showError("Saved!");
}
}
ImGui::SameLine();
if (ImGui::Button("Apply")) {
if (!rend->regenOscShader(newOscFragment.c_str())) {
showError("Of course you screwed it up, again!");
}
}
}
ImGui::End();
}
// release selection if mouse released
if (ImGui::IsMouseReleased(ImGuiMouseButton_Left) && selecting) {
if (!selectingFull) cursor=selEnd;
@ -4992,6 +5042,9 @@ bool FurnaceGUI::loop() {
case GUI_WARN_OPEN_BACKUP:
openFileDialog(GUI_FILE_OPEN_BACKUP);
break;
case GUI_WARN_CV:
cvOpen=true;
break;
default:
break;
}
@ -5641,6 +5694,30 @@ bool FurnaceGUI::loop() {
ImGui::CloseCurrentPopup();
}
break;
case GUI_WARN_CV:
if (ImGui::Button("Yes")) {
ImGui::CloseCurrentPopup();
if (curFileName=="" || curFileName.find(backupPath)==0 || e->song.version>=0xff00) {
openFileDialog(GUI_FILE_SAVE);
postWarnAction=GUI_WARN_CV;
} else {
if (save(curFileName,e->song.isDMF?e->song.version:0)>0) {
showError(fmt::sprintf("Error while saving file! (%s)",lastError));
} else {
cvOpen=true;
}
}
}
ImGui::SameLine();
if (ImGui::Button("No")) {
ImGui::CloseCurrentPopup();
cvOpen=true;
}
ImGui::SameLine();
if (ImGui::Button("Cancel") || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
ImGui::CloseCurrentPopup();
}
break;
case GUI_WARN_OPEN_BACKUP:
if (ImGui::Button("Yes")) {
ImGui::CloseCurrentPopup();
@ -6711,6 +6788,8 @@ bool FurnaceGUI::init() {
xyOscIntensity=e->getConfFloat("xyOscIntensity",2.0f);
xyOscThickness=e->getConfFloat("xyOscThickness",2.0f);
cvHiScore=e->getConfInt("cvHiScore",25000);
syncSettings();
syncTutorial();
@ -7051,6 +7130,20 @@ bool FurnaceGUI::init() {
firstFrame=true;
time_t timet=time(NULL);
struct tm* curtm=localtime(&timet);
if (curtm!=NULL) {
if (curtm->tm_mon==3 && curtm->tm_mday==1) {
if (cvHiScore<=25000) {
shaderEditor=true;
}
}
}
if (!shaderEditor) {
e->setNumTimesPlayed(-1);
}
userEvents=SDL_RegisterEvents(1);
e->setMidiCallback([this](const TAMidiMessage& msg) -> int {
@ -7278,6 +7371,8 @@ void FurnaceGUI::commitState() {
e->setConf(key,recentFile[i]);
}
}
e->setConf("cvHiScore",cvHiScore);
}
bool FurnaceGUI::finish(bool saveConfig) {
@ -7322,7 +7417,7 @@ bool FurnaceGUI::finish(bool saveConfig) {
}
bool FurnaceGUI::requestQuit() {
if (modified) {
if (modified && !cvOpen) {
showWarning("Unsaved changes! Save changes before quitting?",GUI_WARN_QUIT);
} else {
quit=true;
@ -7337,6 +7432,7 @@ FurnaceGUI::FurnaceGUI():
sdlWin(NULL),
vibrator(NULL),
vibratorAvailable(false),
cv(NULL),
sampleTex(NULL),
sampleTexW(0),
sampleTexH(0),
@ -7399,6 +7495,7 @@ FurnaceGUI::FurnaceGUI():
wheelCalmDown(0),
shallDetectScale(0),
cpuCores(0),
numTimesPlayed(0),
secondTimer(0.0f),
userEvents(0xffffffff),
mobileMenuPos(0.0f),
@ -7535,7 +7632,9 @@ FurnaceGUI::FurnaceGUI():
xyOscOpen(false),
memoryOpen(false),
csPlayerOpen(false),
cvOpen(false),
userPresetsOpen(false),
cvNotSerious(false),
shortIntro(false),
insListDir(false),
waveListDir(false),

View file

@ -579,6 +579,7 @@ enum FurnaceGUIWarnings {
GUI_WARN_SUBSONG_DEL,
GUI_WARN_SYSTEM_DEL,
GUI_WARN_CLEAR_HISTORY,
GUI_WARN_CV,
GUI_WARN_GENERIC
};
@ -1456,7 +1457,7 @@ class FurnaceGUIRender {
virtual bool lockTexture(FurnaceGUITexture* which, void** data, int* pitch);
virtual bool unlockTexture(FurnaceGUITexture* which);
virtual bool updateTexture(FurnaceGUITexture* which, void* data, int pitch);
virtual FurnaceGUITexture* createTexture(bool dynamic, int width, int height);
virtual FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true);
virtual bool destroyTexture(FurnaceGUITexture* which);
virtual void setTextureBlendMode(FurnaceGUITexture* which, FurnaceGUIBlendMode mode);
virtual void setBlendMode(FurnaceGUIBlendMode mode);
@ -1501,6 +1502,8 @@ struct PendingDrawOsc {
lineSize(0.0f) {}
};
struct FurnaceCV;
class FurnaceGUI {
DivEngine* e;
@ -1510,7 +1513,10 @@ class FurnaceGUI {
SDL_Window* sdlWin;
SDL_Haptic* vibrator;
bool vibratorAvailable;
FurnaceCV* cv;
FurnaceGUITexture* cvTex;
FurnaceGUITexture* sampleTex;
int sampleTexW, sampleTexH;
bool updateSampleTex;
@ -1550,6 +1556,7 @@ class FurnaceGUI {
bool willExport[DIV_MAX_CHIPS];
int vgmExportVersion;
int vgmExportTrailingTicks;
int cvHiScore;
int drawHalt;
int zsmExportTickRate;
int macroPointSize;
@ -1560,6 +1567,7 @@ class FurnaceGUI {
int wheelCalmDown;
int shallDetectScale;
int cpuCores;
int numTimesPlayed;
float secondTimer;
unsigned int userEvents;
float mobileMenuPos, autoButtonSize, mobileEditAnim;
@ -2083,7 +2091,9 @@ class FurnaceGUI {
bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen;
bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen, effectListOpen, chanOscOpen;
bool subSongsOpen, findOpen, spoilerOpen, patManagerOpen, sysManagerOpen, clockOpen, speedOpen;
bool groovesOpen, xyOscOpen, memoryOpen, csPlayerOpen, userPresetsOpen;
bool groovesOpen, xyOscOpen, memoryOpen, csPlayerOpen, cvOpen, userPresetsOpen;
bool cvNotSerious;
bool shortIntro;
bool insListDir, waveListDir, sampleListDir;
@ -2478,6 +2488,7 @@ class FurnaceGUI {
// user presets window
int selectedUserPreset;
std::vector<String> randomDemoSong;
void drawExportAudio(bool onWindow=false);
void drawExportVGM(bool onWindow=false);
@ -2725,6 +2736,9 @@ class FurnaceGUI {
void initTutorial();
void activateTutorial(FurnaceGUITutorials which);
void initRandomDemoSong();
bool loadRandomDemoSong();
bool loadUserPresets(bool redundancy=true);
bool saveUserPresets(bool redundancy=true);

View file

@ -35,7 +35,7 @@ bool FurnaceGUIRender::updateTexture(FurnaceGUITexture* which, void* data, int p
return false;
}
FurnaceGUITexture* FurnaceGUIRender::createTexture(bool dynamic, int width, int height) {
FurnaceGUITexture* FurnaceGUIRender::createTexture(bool dynamic, int width, int height, bool interpolate) {
return NULL;
}

View file

@ -199,7 +199,7 @@ bool FurnaceGUIRenderDX11::updateTexture(FurnaceGUITexture* which, void* data, i
return true;
}
FurnaceGUITexture* FurnaceGUIRenderDX11::createTexture(bool dynamic, int width, int height) {
FurnaceGUITexture* FurnaceGUIRenderDX11::createTexture(bool dynamic, int width, int height, bool interpolate) {
D3D11_TEXTURE2D_DESC texDesc;
D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
ID3D11Texture2D* tex=NULL;

View file

@ -64,7 +64,7 @@ class FurnaceGUIRenderDX11: public FurnaceGUIRender {
bool lockTexture(FurnaceGUITexture* which, void** data, int* pitch);
bool unlockTexture(FurnaceGUITexture* which);
bool updateTexture(FurnaceGUITexture* which, void* data, int pitch);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true);
bool destroyTexture(FurnaceGUITexture* which);
void setTextureBlendMode(FurnaceGUITexture* which, FurnaceGUIBlendMode mode);
void setBlendMode(FurnaceGUIBlendMode mode);

View file

@ -301,12 +301,17 @@ bool FurnaceGUIRenderGL::updateTexture(FurnaceGUITexture* which, void* data, int
return true;
}
FurnaceGUITexture* FurnaceGUIRenderGL::createTexture(bool dynamic, int width, int height) {
FurnaceGUITexture* FurnaceGUIRenderGL::createTexture(bool dynamic, int width, int height, bool interpolate) {
FurnaceGLTexture* t=new FurnaceGLTexture;
C(glGenTextures(1,&t->id));
C(glBindTexture(GL_TEXTURE_2D,t->id));
C(glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR));
C(glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR));
if (interpolate) {
C(glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR));
C(glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR));
} else {
C(glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST));
C(glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST));
}
C(glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,PIXEL_FORMAT,NULL));
C(furActiveTexture(GL_TEXTURE0));
t->width=width;

View file

@ -53,7 +53,7 @@ class FurnaceGUIRenderGL: public FurnaceGUIRender {
bool lockTexture(FurnaceGUITexture* which, void** data, int* pitch);
bool unlockTexture(FurnaceGUITexture* which);
bool updateTexture(FurnaceGUITexture* which, void* data, int pitch);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true);
bool destroyTexture(FurnaceGUITexture* which);
void setTextureBlendMode(FurnaceGUITexture* which, FurnaceGUIBlendMode mode);
void setBlendMode(FurnaceGUIBlendMode mode);

View file

@ -49,8 +49,10 @@ bool FurnaceGUIRenderSDL::updateTexture(FurnaceGUITexture* which, void* data, in
return SDL_UpdateTexture(t->tex,NULL,data,pitch)==0;
}
FurnaceGUITexture* FurnaceGUIRenderSDL::createTexture(bool dynamic, int width, int height) {
FurnaceGUITexture* FurnaceGUIRenderSDL::createTexture(bool dynamic, int width, int height, bool interpolate) {
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,interpolate?"1":"0");
SDL_Texture* t=SDL_CreateTexture(sdlRend,SDL_PIXELFORMAT_ABGR8888,dynamic?SDL_TEXTUREACCESS_STREAMING:SDL_TEXTUREACCESS_STATIC,width,height);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,"1");
if (t==NULL) return NULL;
FurnaceSDLTexture* ret=new FurnaceSDLTexture;

View file

@ -26,7 +26,7 @@ class FurnaceGUIRenderSDL: public FurnaceGUIRender {
bool lockTexture(FurnaceGUITexture* which, void** data, int* pitch);
bool unlockTexture(FurnaceGUITexture* which);
bool updateTexture(FurnaceGUITexture* which, void* data, int pitch);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height);
FurnaceGUITexture* createTexture(bool dynamic, int width, int height, bool interpolate=true);
bool destroyTexture(FurnaceGUITexture* which);
void setTextureBlendMode(FurnaceGUITexture* which, FurnaceGUIBlendMode mode);
void setBlendMode(FurnaceGUIBlendMode mode);
@ -46,4 +46,4 @@ class FurnaceGUIRenderSDL: public FurnaceGUIRender {
bool quit();
FurnaceGUIRenderSDL():
sdlRend(NULL) {}
};
};

View file

@ -44,6 +44,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
}
bool noExtMacros=flags.getBool("noExtMacros",false);
bool fbAllOps=flags.getBool("fbAllOps",false);
bool msw=flags.getBool("msw",false);
ImGui::Text("Clock rate:");
ImGui::Indent();
@ -93,6 +94,15 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
altered=true;
}
}
if (msw || shaderEditor) {
if (ImGui::Checkbox("Modified sine wave",&msw)) {
altered=true;
}
if (msw && shaderEditor) {
ImGui::Text("Oopsie...");
}
}
if (altered) {
e->lockSave([&]() {
@ -100,6 +110,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
flags.set("chipType",chipType);
flags.set("noExtMacros",noExtMacros);
flags.set("fbAllOps",fbAllOps);
flags.set("msw",msw);
});
}
break;

1501
src/gui/tileData.h Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -645,6 +645,7 @@ int main(int argc, char** argv) {
if (benchMode) {
logI("starting benchmark!");
e.setNumTimesPlayed(-1);
if (benchMode==2) {
e.benchmarkSeek();
} else {
@ -655,6 +656,7 @@ int main(int argc, char** argv) {
}
if (outName!="" || vgmOutName!="" || cmdOutName!="") {
e.setNumTimesPlayed(-1);
if (cmdOutName!="") {
SafeWriter* w=e.saveCommand();
if (w!=NULL) {
@ -698,6 +700,7 @@ int main(int argc, char** argv) {
if (consoleMode) {
bool cliSuccess=false;
e.setNumTimesPlayed(-1);
cli.bindEngine(&e);
if (!cli.init()) {
reportError("error while starting CLI!");