diff --git a/src/oplsynth/mlopl.cpp b/src/oplsynth/mlopl.cpp index 285d4a6be..0fe171597 100644 --- a/src/oplsynth/mlopl.cpp +++ b/src/oplsynth/mlopl.cpp @@ -82,9 +82,9 @@ void musicBlock::writeModulation(uint slot, struct OPL2instrument *instr, int st instr->trem_vibr_2 | state); } -uint musicBlock::calcVolume(uint channelVolume, uint MUSvolume, uint noteVolume) +uint musicBlock::calcVolume(uint channelVolume, uint channelExpression, uint noteVolume) { - noteVolume = ((ulong)channelVolume * MUSvolume * noteVolume) / (256*127); + noteVolume = ((ulong)channelVolume * channelExpression * noteVolume) / (127*127); if (noteVolume > 127) return 127; else @@ -107,7 +107,8 @@ int musicBlock::occupyChannel(uint slot, uint channel, volume = driverdata.channelLastVolume[channel]; else driverdata.channelLastVolume[channel] = volume; - ch->realvolume = calcVolume(driverdata.channelVolume[channel], 256, ch->volume = volume); + ch->realvolume = calcVolume(driverdata.channelVolume[channel], + driverdata.channelExpression[channel], ch->volume = volume); if (instrument->flags & FL_FIXED_PITCH) note = instrument->note; else if (channel == PERCUSSION) @@ -273,7 +274,9 @@ void musicBlock::OPLpitchWheel(uint channel, int pitch) uint i; uint id = channel; - pitch >>= 7; + // Convert pitch from 14-bit to 7-bit, then scale it, since the player + // code only understands sensitivities of 2 semitones. + pitch = (pitch - 8192) * driverdata.channelPitchSens[channel] / (200 * 128) + 64; driverdata.channelPitch[channel] = pitch; for(i = 0; i < io->OPLchannels; i++) { @@ -298,6 +301,7 @@ void musicBlock::OPLchangeControl(uint channel, uchar controller, int value) case ctrlPatch: /* change instrument */ OPLprogramChange(channel, value); break; + case ctrlModulation: driverdata.channelModulation[channel] = value; for(i = 0; i < io->OPLchannels; i++) @@ -320,19 +324,28 @@ void musicBlock::OPLchangeControl(uint channel, uchar controller, int value) } } break; + case ctrlVolume: /* change volume */ driverdata.channelVolume[channel] = value; + /* fall-through */ + case ctrlExpression: /* change expression */ + if (controller == ctrlExpression) + { + driverdata.channelExpression[channel] = value; + } for(i = 0; i < io->OPLchannels; i++) { struct channelEntry *ch = &channels[i]; if (ch->channel == id) { ch->time = MLtime; - ch->realvolume = calcVolume(value, 256, ch->volume); + ch->realvolume = calcVolume(driverdata.channelVolume[channel], + driverdata.channelExpression[channel], ch->volume); io->OPLwriteVolume(i, ch->instr, ch->realvolume); } } break; + case ctrlPan: /* change pan (balance) */ driverdata.channelPan[channel] = value -= 64; for(i = 0; i < io->OPLchannels; i++) @@ -345,14 +358,76 @@ void musicBlock::OPLchangeControl(uint channel, uchar controller, int value) } } break; + case ctrlSustainPedal: /* change sustain pedal (hold) */ driverdata.channelSustain[channel] = value; if (value < 0x40) releaseSustain(channel); break; + + case ctrlNotesOff: /* turn off all notes that are not sustained */ + for (i = 0; i < io->OPLchannels; ++i) + { + if (channels[i].channel == id) + { + if (driverdata.channelSustain[id] < 0x40) + releaseChannel(i, 0); + else + channels[i].flags |= CH_SUSTAIN; + } + } + break; + + case ctrlSoundsOff: /* release all notes for this channel */ + for (i = 0; i < io->OPLchannels; ++i) + { + if (channels[i].channel == id) + { + releaseChannel(i, 0); + } + } + break; + + case ctrlRPNHi: + driverdata.channelRPN[id] = (driverdata.channelRPN[id] & 0x007F) | (value << 7); + break; + + case ctrlRPNLo: + driverdata.channelRPN[id] = (driverdata.channelRPN[id] & 0x3F80) | value; + break; + + case ctrlNRPNLo: + case ctrlNRPNHi: + driverdata.channelRPN[id] = 0x3FFF; + break; + + case ctrlDataEntryHi: + if (driverdata.channelRPN[id] == 0) + { + driverdata.channelPitchSens[id] = value * 100 + (driverdata.channelPitchSens[id] % 100); + } + break; + + case ctrlDataEntryLo: + if (driverdata.channelRPN[id] == 0) + { + driverdata.channelPitchSens[id] = value + (driverdata.channelPitchSens[id] / 100) * 100; + } + break; } } +void musicBlock::OPLresetControllers(uint chan, int vol) +{ + driverdata.channelVolume[chan] = vol; + driverdata.channelExpression[chan] = 127; + driverdata.channelSustain[chan] = 0; + driverdata.channelLastVolume[chan] = 64; + driverdata.channelPitch[chan] = 64; + driverdata.channelRPN[chan] = 0x3fff; + driverdata.channelPitchSens[chan] = 200; +} + void musicBlock::OPLprogramChange(uint channel, int value) { driverdata.channelInstr[channel] = value; @@ -364,10 +439,7 @@ void musicBlock::OPLplayMusic(int vol) for (i = 0; i < CHANNELS; i++) { - driverdata.channelVolume[i] = vol; /* default volume 127 for MUS (full volume) */ - driverdata.channelSustain[i] = 0; - driverdata.channelLastVolume[i] = 64; - driverdata.channelPitch[i] = 64; + OPLresetControllers(i, vol); } } @@ -379,18 +451,6 @@ void musicBlock::OPLstopMusic() releaseChannel(i, 1); } -void musicBlock::OPLchangeVolume(uint volume) -{ - uchar *channelVolume = driverdata.channelVolume; - uint i; - for(i = 0; i < io->OPLchannels; i++) - { - struct channelEntry *ch = &channels[i]; - ch->realvolume = calcVolume(channelVolume[ch->channel & 0xF], volume, ch->volume); - io->OPLwriteVolume(i, ch->instr, ch->realvolume); - } -} - int musicBlock::OPLloadBank (FileReader &data) { static const uchar masterhdr[8] = { '#','O','P','L','_','I','I','#' }; diff --git a/src/oplsynth/music_opl_mididevice.cpp b/src/oplsynth/music_opl_mididevice.cpp index d1f71cbe5..9413ae4bb 100644 --- a/src/oplsynth/music_opl_mididevice.cpp +++ b/src/oplsynth/music_opl_mididevice.cpp @@ -468,15 +468,21 @@ void OPLMIDIDevice::HandleEvent(int status, int parm1, int parm2) { case 0: OPLchangeControl(channel, ctrlBank, parm2); break; case 1: OPLchangeControl(channel, ctrlModulation, parm2); break; + case 6: OPLchangeControl(channel, ctrlDataEntryHi, parm2); break; case 7: OPLchangeControl(channel, ctrlVolume, parm2); break; case 10: OPLchangeControl(channel, ctrlPan, parm2); break; case 11: OPLchangeControl(channel, ctrlExpression, parm2); break; + case 38: OPLchangeControl(channel, ctrlDataEntryLo, parm2); break; case 64: OPLchangeControl(channel, ctrlSustainPedal, parm2); break; case 67: OPLchangeControl(channel, ctrlSoftPedal, parm2); break; case 91: OPLchangeControl(channel, ctrlReverb, parm2); break; case 93: OPLchangeControl(channel, ctrlChorus, parm2); break; + case 98: OPLchangeControl(channel, ctrlNRPNLo, parm2); break; + case 99: OPLchangeControl(channel, ctrlNRPNHi, parm2); break; + case 100: OPLchangeControl(channel, ctrlRPNLo, parm2); break; + case 101: OPLchangeControl(channel, ctrlRPNHi, parm2); break; case 120: OPLchangeControl(channel, ctrlSoundsOff, parm2); break; - case 121: OPLchangeControl(channel, ctrlResetCtrls, parm2); break; + case 121: OPLresetControllers(channel, 100); break; case 123: OPLchangeControl(channel, ctrlNotesOff, parm2); break; case 126: OPLchangeControl(channel, ctrlMono, parm2); break; case 127: OPLchangeControl(channel, ctrlPoly, parm2); break; diff --git a/src/oplsynth/muslib.h b/src/oplsynth/muslib.h index cf642ad73..f8576ec38 100644 --- a/src/oplsynth/muslib.h +++ b/src/oplsynth/muslib.h @@ -154,9 +154,12 @@ struct OPLdata { uchar channelVolume[CHANNELS]; // volume uchar channelLastVolume[CHANNELS]; // last volume schar channelPan[CHANNELS]; // pan, 0=normal - schar channelPitch[CHANNELS]; // pitch wheel, 0=normal + schar channelPitch[CHANNELS]; // pitch wheel, 64=normal uchar channelSustain[CHANNELS]; // sustain pedal value uchar channelModulation[CHANNELS]; // modulation pot value + ushort channelPitchSens[CHANNELS]; // pitch sensitivity, 2=default + ushort channelRPN[CHANNELS]; // RPN number for data entry + uchar channelExpression[CHANNELS]; // expression }; struct OPLio { @@ -227,9 +230,9 @@ struct musicBlock { void OPLpitchWheel(uint channel, int pitch); void OPLchangeControl(uint channel, uchar controller, int value); void OPLprogramChange(uint channel, int value); + void OPLresetControllers(uint channel, int vol); void OPLplayMusic(int vol); void OPLstopMusic(); - void OPLchangeVolume(uint volume); int OPLloadBank (FileReader &data); @@ -250,7 +253,7 @@ protected: void writeFrequency(uint slot, uint note, int pitch, uint keyOn); void writeModulation(uint slot, struct OPL2instrument *instr, int state); - uint calcVolume(uint channelVolume, uint MUSvolume, uint noteVolume); + uint calcVolume(uint channelVolume, uint channelExpression, uint noteVolume); int occupyChannel(uint slot, uint channel, int note, int volume, struct OP2instrEntry *instrument, uchar secondary); int releaseChannel(uint slot, uint killed); @@ -273,12 +276,17 @@ enum MUSctrl { ctrlChorus, ctrlSustainPedal, ctrlSoftPedal, - _ctrlCount_, - ctrlSoundsOff = _ctrlCount_, + ctrlRPNHi, + ctrlRPNLo, + ctrlNRPNHi, + ctrlNRPNLo, + ctrlDataEntryHi, + ctrlDataEntryLo, + + ctrlSoundsOff, ctrlNotesOff, ctrlMono, ctrlPoly, - ctrlResetCtrls }; #define OPL_SAMPLE_RATE 49716.0 diff --git a/src/v_pfx.cpp b/src/v_pfx.cpp index 852379da4..ce510d195 100644 --- a/src/v_pfx.cpp +++ b/src/v_pfx.cpp @@ -52,6 +52,9 @@ static void Palette32Generic (const PalEntry *pal); static void Palette32RGB (const PalEntry *pal); static void Palette32BGR (const PalEntry *pal); +static void Scale8 (BYTE *src, int srcpitch, + void *destin, int destpitch, int destwidth, int destheight, + fixed_t xstep, fixed_t ystep, fixed_t xfrac, fixed_t yfrac); static void Convert8 (BYTE *src, int srcpitch, void *destin, int destpitch, int destwidth, int destheight, fixed_t xstep, fixed_t ystep, fixed_t xfrac, fixed_t yfrac); @@ -69,6 +72,11 @@ void PfxState::SetFormat (int bits, uint32 redMask, uint32 greenMask, uint32 blu { switch (bits) { + case -8: + Convert = Scale8; + SetPalette = NULL; + break; + case 8: Convert = Convert8; SetPalette = NULL; @@ -132,7 +140,7 @@ void PfxState::SetFormat (int bits, uint32 redMask, uint32 greenMask, uint32 blu default: I_FatalError ("Can't draw to %d-bit displays", bits); } - if (bits != 8) + if (bits != 8 && bits != -8) { RedLeft = AnalyzeMask (redMask, &RedShift); GreenLeft = AnalyzeMask (greenMask, &GreenShift); @@ -260,7 +268,7 @@ static void Palette32BGR (const PalEntry *pal) // Bitmap converters ------------------------------------------------------- -static void Convert8 (BYTE *src, int srcpitch, +static void Scale8 (BYTE *src, int srcpitch, void *destin, int destpitch, int destwidth, int destheight, fixed_t xstep, fixed_t ystep, fixed_t xfrac, fixed_t yfrac) { @@ -273,8 +281,129 @@ static void Convert8 (BYTE *src, int srcpitch, BYTE *dest = (BYTE *)destin; if (xstep == FRACUNIT && ystep == FRACUNIT) + { + for (y = destheight; y != 0; y--) + { + memcpy(dest, src, destwidth); + dest += destpitch; + src += srcpitch; + } + } + else if (xstep == FRACUNIT/2 && ystep == FRACUNIT/2) + { + BYTE *dest2 = dest + destpitch; + destpitch = destpitch * 2 - destwidth; + srcpitch -= destwidth / 2; + for (y = destheight / 2; y != 0; --y) + { + for (x = destwidth / 2; x != 0; --x) + { + BYTE foo = src[0]; + dest[0] = foo; + dest[1] = foo; + dest2[0] = foo; + dest2[1] = foo; + dest += 2; + dest2 += 2; + src += 1; + } + dest += destpitch; + dest2 += destpitch; + src += srcpitch; + } + } + else if (xstep == FRACUNIT/4 && ystep == FRACUNIT/4) + { + int gap = destpitch * 4 - destwidth; + srcpitch -= destwidth / 4; + for (y = destheight / 4; y != 0; --y) + { + for (BYTE *end = dest + destpitch; dest != end; dest += 4) + { + BYTE foo = src[0]; + dest[0] = foo; + dest[1] = foo; + dest[2] = foo; + dest[3] = foo; + dest[0 + destpitch] = foo; + dest[1 + destpitch] = foo; + dest[2 + destpitch] = foo; + dest[3 + destpitch] = foo; + dest[0 + destpitch*2] = foo; + dest[1 + destpitch*2] = foo; + dest[2 + destpitch*2] = foo; + dest[3 + destpitch*2] = foo; + dest[0 + destpitch*3] = foo; + dest[1 + destpitch*3] = foo; + dest[2 + destpitch*3] = foo; + dest[3 + destpitch*3] = foo; + src += 1; + } + dest += gap; + src += srcpitch; + } + } + else { destpitch -= destwidth; + for (y = destheight; y != 0; y--) + { + fixed_t xf = xfrac; + x = destwidth; + while (((size_t)dest & 3) && x != 0) + { + *dest++ = src[xf >> FRACBITS]; + xf += xstep; + x--; + } + for (savedx = x, x >>= 2; x != 0; x--) + { + DWORD work; + +#ifdef WORDS_BIGENDIAN + work = src[xf >> FRACBITS] << 24; xf += xstep; + work |= src[xf >> FRACBITS] << 16; xf += xstep; + work |= src[xf >> FRACBITS] << 8; xf += xstep; + work |= src[xf >> FRACBITS]; xf += xstep; +#else + work = src[xf >> FRACBITS]; xf += xstep; + work |= src[xf >> FRACBITS] << 8; xf += xstep; + work |= src[xf >> FRACBITS] << 16; xf += xstep; + work |= src[xf >> FRACBITS] << 24; xf += xstep; +#endif + *(DWORD *)dest = work; + dest += 4; + } + for (savedx &= 3; savedx != 0; savedx--, xf += xstep) + { + *dest++ = src[xf >> FRACBITS]; + } + yfrac += ystep; + while (yfrac >= FRACUNIT) + { + yfrac -= FRACUNIT; + src += srcpitch; + } + dest += destpitch; + } + } +} + +static void Convert8 (BYTE *src, int srcpitch, + void *destin, int destpitch, int destwidth, int destheight, + fixed_t xstep, fixed_t ystep, fixed_t xfrac, fixed_t yfrac) +{ + if ((destwidth | destheight) == 0) + { + return; + } + + int x, y, savedx; + BYTE *dest = (BYTE *)destin; + + destpitch -= destwidth; + if (xstep == FRACUNIT && ystep == FRACUNIT) + { srcpitch -= destwidth; for (y = destheight; y != 0; y--) { @@ -311,7 +440,6 @@ static void Convert8 (BYTE *src, int srcpitch, } else { - destpitch -= destwidth; for (y = destheight; y != 0; y--) { fixed_t xf = xfrac; @@ -367,9 +495,9 @@ static void Convert16 (BYTE *src, int srcpitch, int x, y, savedx; WORD *dest = (WORD *)destin; + destpitch = (destpitch >> 1) - destwidth; if (xstep == FRACUNIT && ystep == FRACUNIT) { - destpitch = (destpitch >> 1) - destwidth; srcpitch -= destwidth; for (y = destheight; y != 0; y--) { @@ -402,7 +530,6 @@ static void Convert16 (BYTE *src, int srcpitch, } else { - destpitch = (destpitch >> 1) - destwidth; for (y = destheight; y != 0; y--) { fixed_t xf = xfrac; @@ -454,9 +581,9 @@ static void Convert24 (BYTE *src, int srcpitch, int x, y; BYTE *dest = (BYTE *)destin; + destpitch = destpitch - destwidth*3; if (xstep == FRACUNIT && ystep == FRACUNIT) { - destpitch = destpitch - destwidth*3; srcpitch -= destwidth; for (y = destheight; y != 0; y--) { @@ -475,7 +602,6 @@ static void Convert24 (BYTE *src, int srcpitch, } else { - destpitch = destpitch - destwidth*3; for (y = destheight; y != 0; y--) { fixed_t xf = xfrac; @@ -511,9 +637,9 @@ static void Convert32 (BYTE *src, int srcpitch, int x, y, savedx; DWORD *dest = (DWORD *)destin; + destpitch = (destpitch >> 2) - destwidth; if (xstep == FRACUNIT && ystep == FRACUNIT) { - destpitch = (destpitch >> 2) - destwidth; srcpitch -= destwidth; for (y = destheight; y != 0; y--) { @@ -540,7 +666,6 @@ static void Convert32 (BYTE *src, int srcpitch, } else { - destpitch -= destwidth; for (y = destheight; y != 0; y--) { fixed_t xf = xfrac; diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 77ff0ead5..fe61f07b9 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -460,6 +460,7 @@ bool D3DFB::CreateResources () } if (FAILED(D3DDevice->CreatePixelShader (GammaFixerDef, &GammaFixerShader))) { +// Cannot print during screen creation. // Printf ("Using Shader Model 1.4: Windowed mode gamma will not work.\n"); GammaFixerShader = NULL; } diff --git a/src/win32/fb_ddraw.cpp b/src/win32/fb_ddraw.cpp index 288000582..dfd12ba3c 100644 --- a/src/win32/fb_ddraw.cpp +++ b/src/win32/fb_ddraw.cpp @@ -3,7 +3,7 @@ ** Code to let ZDoom use DirectDraw 3 ** **--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit +** Copyright 1998-2008 Randy Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -132,12 +132,12 @@ DDrawFB::DDrawFB (int width, int height, bool fullscreen) BlitSurf = NULL; Clipper = NULL; GDIPalette = NULL; - ClipRegion = NULL; ClipSize = 0; BufferCount = 1; Gamma = 1.0; BufferPitch = Pitch; FlipFlags = vid_vsync ? DDFLIP_WAIT : DDFLIP_WAIT|DDFLIP_NOVSYNC; + PixelDoubling = 0; NeedGammaUpdate = false; NeedPalUpdate = false; @@ -239,20 +239,21 @@ bool DDrawFB::CreateResources () if (mode->width == Width && mode->height == Height) { TrueHeight = mode->realheight; + PixelDoubling = mode->doubling; break; } } - hr = DDraw->SetDisplayMode (Width, TrueHeight, bits = vid_displaybits, vid_refreshrate, 0); + hr = DDraw->SetDisplayMode (Width << PixelDoubling, TrueHeight << PixelDoubling, bits = vid_displaybits, vid_refreshrate, 0); if (FAILED(hr)) { - hr = DDraw->SetDisplayMode (Width, TrueHeight, bits = vid_displaybits, 0, 0); + hr = DDraw->SetDisplayMode (Width << PixelDoubling, TrueHeight << PixelDoubling, bits = vid_displaybits, 0, 0); bits = 32; while (FAILED(hr) && bits >= 8) { - hr = DDraw->SetDisplayMode (Width, Height, bits, vid_refreshrate, 0); + hr = DDraw->SetDisplayMode (Width << PixelDoubling, Height << PixelDoubling, bits, vid_refreshrate, 0); if (FAILED(hr)) { - hr = DDraw->SetDisplayMode (Width, Height, bits, 0, 0); + hr = DDraw->SetDisplayMode (Width << PixelDoubling, Height << PixelDoubling, bits, 0, 0); } bits -= 8; } @@ -290,6 +291,7 @@ bool DDrawFB::CreateResources () // Create the primary surface ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; +// PixelDoubling = 1; do { hr = DDraw->CreateSurface (&ddsd, &PrimarySurf, NULL); @@ -304,8 +306,8 @@ bool DDrawFB::CreateResources () MaybeCreatePalette (); // Resize the window to match desired dimensions - int sizew = Width + GetSystemMetrics (SM_CXSIZEFRAME)*2; - int sizeh = Height + GetSystemMetrics (SM_CYSIZEFRAME) * 2 + + int sizew = (Width << PixelDoubling) + GetSystemMetrics (SM_CXSIZEFRAME)*2; + int sizeh = (Height << PixelDoubling) + GetSystemMetrics (SM_CYSIZEFRAME) * 2 + GetSystemMetrics (SM_CYCAPTION); LOG2 ("Resize window to %dx%d\n", sizew, sizeh); VidResizing = true; @@ -334,8 +336,8 @@ bool DDrawFB::CreateResources () // Create the backbuffer ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; - ddsd.dwWidth = Width; - ddsd.dwHeight = Height; + ddsd.dwWidth = Width << PixelDoubling; + ddsd.dwHeight = Height << PixelDoubling; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | (UseBlitter ? DDSCAPS_SYSTEMMEMORY : 0); hr = DDraw->CreateSurface (&ddsd, &BackSurf, NULL); @@ -661,6 +663,11 @@ void DDrawFB::MaybeCreatePalette () NeedPalUpdate = true; } } + if (PixelDoubling) + { + UsePfx = true; + GPfx.SetFormat (-8, 0, 0, 0); + } } } else @@ -681,11 +688,6 @@ void DDrawFB::ReleaseResources () Unlock (); } - if (ClipRegion != NULL) - { - delete[] ClipRegion; - ClipRegion = NULL; - } SAFE_RELEASE( Clipper ); SAFE_RELEASE( PrimarySurf ); SAFE_RELEASE( BackSurf ); @@ -1110,8 +1112,8 @@ void DDrawFB::Update () if (UsePfx) { GPfx.Convert (MemBuffer, BufferPitch, - writept, Pitch, Width, Height, - FRACUNIT, FRACUNIT, 0, 0); + writept, Pitch, Width << PixelDoubling, Height << PixelDoubling, + FRACUNIT >> PixelDoubling, FRACUNIT >> PixelDoubling, 0, 0); } else { @@ -1207,8 +1209,8 @@ bool DDrawFB::PaintToWindow () if (LockSurf (NULL, NULL) != NoGood) { GPfx.Convert (MemBuffer, BufferPitch, - Buffer, Pitch, Width, Height, - FRACUNIT, FRACUNIT, 0, 0); + Buffer, Pitch, Width << PixelDoubling, Height << PixelDoubling, + FRACUNIT >> PixelDoubling, FRACUNIT >> PixelDoubling, 0, 0); LockingSurf->Unlock (NULL); if (FAILED (hr = PrimarySurf->Blt (&rect, BackSurf, NULL, DDBLT_WAIT|DDBLT_ASYNC, NULL))) { diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index 1114d5504..14cc3194b 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -108,6 +108,7 @@ class Win32Video : public IVideo void AddD3DModes (D3DFORMAT format); void AddLowResModes (); void AddLetterboxModes (); + void ScaleModes (int doubling); friend class DDrawFB; friend class D3DFB; @@ -193,13 +194,13 @@ private: LPDIRECTDRAWSURFACE LockingSurf; LPDIRECTDRAWCLIPPER Clipper; HPALETTE GDIPalette; - BYTE *ClipRegion; DWORD ClipSize; PalEntry Flash; int FlashAmount; int BufferCount; int BufferPitch; int TrueHeight; + int PixelDoubling; float Gamma; bool NeedGammaUpdate; diff --git a/src/win32/win32video.cpp b/src/win32/win32video.cpp index dbdc8990b..acbc5d8d6 100644 --- a/src/win32/win32video.cpp +++ b/src/win32/win32video.cpp @@ -185,7 +185,18 @@ bool Win32Video::InitD3D9 () FreeModes (); AddD3DModes (D3DFMT_X8R8G8B8); AddD3DModes (D3DFMT_R5G6B5); - AddLowResModes (); + if (Args->CheckParm ("-2")) + { // Force all modes to be pixel-doubled. + ScaleModes (1); + } + else if (Args->CheckParm ("-4")) + { // Force all modes to be pixel-quadrupled. + ScaleModes (2); + } + else + { + AddLowResModes (); + } AddLetterboxModes (); if (m_Modes == NULL) { // Too bad. We didn't find any modes for D3D9. We probably won't find any @@ -256,12 +267,24 @@ void Win32Video::InitDDraw () "If you started ZDoom from a fullscreen DOS box, run it from " "a DOS window instead. If that does not work, you may need to reboot."); } - if (OSPlatform == os_Win95) + if (Args->CheckParm ("-2")) + { // Force all modes to be pixel-doubled. + ScaleModes(1); + } + else if (Args->CheckParm ("-4")) + { // Force all modes to be pixel-quadrupled. + ScaleModes(2); + } + else { - // Windows 95 will let us use Mode X. If we didn't find any linear - // modes in the loop above, add the Mode X modes here. - AddMode (320, 200, 8, 200, 0); - AddMode (320, 240, 8, 240, 0); + if (OSPlatform == os_Win95) + { + // Windows 95 will let us use Mode X. If we didn't find any linear + // modes in the loop above, add the Mode X modes here. + AddMode (320, 200, 8, 200, 0); + AddMode (320, 240, 8, 240, 0); + } + AddLowResModes (); } AddLetterboxModes (); } @@ -358,7 +381,7 @@ void Win32Video::AddLowResModes() { nextmode = mode->next; if (mode->realheight == mode->height && - mode->doubling == 0&& + mode->doubling == 0 && mode->height >= 200*2 && mode->height <= 480*2 && mode->width >= 320*2 && @@ -371,7 +394,7 @@ void Win32Video::AddLowResModes() { nextmode = mode->next; if (mode->realheight == mode->height && - mode->doubling == 0&& + mode->doubling == 0 && mode->height >= 200*4 && mode->height <= 480*4 && mode->width >= 320*4 && @@ -455,6 +478,36 @@ void Win32Video::FreeModes () m_Modes = NULL; } +// For every mode, set its scaling factor. Modes that end up with too +// small a display area are discarded. + +void Win32Video::ScaleModes (int doubling) +{ + ModeInfo *mode, **prev; + + prev = &m_Modes; + mode = m_Modes; + + while (mode != NULL) + { + assert(mode->doubling == 0); + mode->width >>= doubling; + mode->height >>= doubling; + mode->realheight >>= doubling; + mode->doubling = doubling; + if ((mode->width & 7) != 0 || mode->width < 320 || mode->height < 200) + { // Mode became too small. Delete it. + *prev = mode->next; + delete mode; + } + else + { + prev = &mode->next; + } + mode = *prev; + } +} + void Win32Video::StartModeIterator (int bits, bool fs) { m_IteratorMode = m_Modes;