mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-01 02:22:39 +00:00
prepare for 0.6.2
This commit is contained in:
parent
90859be901
commit
90c628612e
28 changed files with 4946 additions and 46 deletions
Binary file not shown.
|
@ -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
44
extern/opn/ym3438.c
vendored
|
@ -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
2
extern/opn/ym3438.h
vendored
|
@ -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
2
res/make-tile.sh
Executable 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
BIN
res/tile.data.pal
Normal file
Binary file not shown.
BIN
res/tile.gif
Normal file
BIN
res/tile.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
302
src/gui/gif_load.h
Normal 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 **/
|
153
src/gui/gui.cpp
153
src/gui/gui.cpp
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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
1501
src/gui/tileData.h
Normal file
File diff suppressed because it is too large
Load diff
2858
src/gui/tutorial.cpp
2858
src/gui/tutorial.cpp
File diff suppressed because it is too large
Load diff
|
@ -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!");
|
||||
|
|
Loading…
Reference in a new issue