Permalink
Cannot retrieve contributors at this time
/*----------------------------------------------------------------------------------------------- | |
The MIT License (MIT) | |
Copyright (c) 2015-2018 J.Hubert | |
Permission is hereby granted, free of charge, to any person obtaining a copy of this software | |
and associated documentation files (the "Software"), | |
to deal in the Software without restriction, including without limitation the rights to use, | |
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, | |
and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in all copies | |
or substantial portions of the Software. | |
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 OR COPYRIGHT HOLDERS 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. | |
-------------------------------------------------------------------------------------------------*/ | |
#ifndef _CRT_SECURE_NO_WARNINGS | |
# define _CRT_SECURE_NO_WARNINGS | |
#endif | |
#include <windows.h> | |
#include <string.h> | |
#include <mmsystem.h> | |
#include <dsound.h> | |
#include <math.h> | |
#include <malloc.h> | |
#undef ARRAY_SIZE // collision... | |
#undef MEM_FREE // collision... | |
extern "C" | |
{ | |
#include "DEMOSDK\BASTYPES.H" | |
#include "DEMOSDK\STANDARD.H" | |
#include "DEMOSDK\HARDWARE.H" | |
#include "DEMOSDK\SYSTEM.H" | |
#include "DEMOSDK\TRACE.H" | |
#include "DEMOSDK\PC\WINDOW.H" | |
#include "DEMOSDK\PC\EMUL.H" | |
#include "DEMOSDK\PC\BITCONVR.H" | |
} | |
#define emul_WIDTH 1024 | |
#define emul_HEIGHT (313*2) | |
STRUCT(FBext) | |
{ | |
bool enable; | |
s16 width; | |
s16 height; | |
s16 pitch; | |
u32 currentindex; | |
u32 commands [1024*1024]; | |
}; | |
ENUM(FBextCommand) | |
{ | |
FBEXT_SETCOLOR, | |
FBEXT_SETWIDTH, | |
FBEXT_SETADR, | |
FBEXT_SETVIDEOMODE | |
}; | |
STRUCT(MiniEmul) | |
{ | |
WINdow* w; | |
u16 width; | |
u16 height; | |
u16 width_ext; | |
FBext fbext; | |
size_t buffermask; | |
IDirectSound8* directSound; | |
IDirectSoundBuffer* primaryBuffer; | |
IDirectSoundBuffer8* secondaryBuffer; | |
u32 lastExtraKey; | |
bool captureSound; | |
u32 imagelut [256]; | |
u8 image [emul_WIDTH*emul_HEIGHT*sizeof(u32)]; | |
}; | |
MiniEmul g_miniEmul; | |
extern "C" void EMULfbExStart (u8 _videomode, u16 _startcyclex, u16 _starty, u16 _endcyclex, u16 _endy, u16 _pitch) | |
{ | |
g_miniEmul.fbext.currentindex = 0; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _videomode; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _startcyclex; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _starty; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _endcyclex; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _endy; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _pitch; | |
} | |
extern "C" void EMULfbExSetVideoMode (u32 _startcycle, u8 _videomode) | |
{ | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _startcycle; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = FBEXT_SETVIDEOMODE; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _videomode; | |
} | |
extern "C" void EMULfbExSetColor (u32 _startcycle, u16 _index, u16 _value) | |
{ | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _startcycle; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = FBEXT_SETCOLOR; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _index; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _value; | |
} | |
extern "C" void EMULfbExSetAdr (u32 _startcycle, u32 _adr) | |
{ | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _startcycle; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = FBEXT_SETADR; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _adr; | |
} | |
extern "C" void EMULfbExSetWidth (u32 _startcycle, u16 _startx, u16 _endx, u16 _pitch) | |
{ | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _startcycle; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = FBEXT_SETWIDTH; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _startx; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _endx; | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = _pitch; | |
} | |
extern "C" void EMULfbExEnd (void) | |
{ | |
g_miniEmul.fbext.commands[g_miniEmul.fbext.currentindex++] = 0xFFFFFFFF; | |
g_miniEmul.fbext.enable = true; | |
} | |
extern "C" void EMULfbExDisable (void) | |
{ | |
g_miniEmul.fbext.enable = false; | |
} | |
extern "C" u32 EMULfbExComputeCycle (u8 _videosync, u16 _x, u16 _y) | |
{ | |
u32 cyclesperline = 0; | |
switch (_videosync) | |
{ | |
case HW_VIDEO_SYNC_50HZ: | |
cyclesperline = 512; | |
break; | |
case HW_VIDEO_SYNC_60HZ: | |
cyclesperline = 508; | |
break; | |
case HW_VIDEO_SYNC_EXTERN: | |
cyclesperline = 256; /* ? */ | |
break; | |
default: ASSERT(0); | |
} | |
return ((u32)_y * cyclesperline) + (u32)_x; | |
} | |
extern "C" WINdow* EMULgetWindow (void) | |
{ | |
return g_miniEmul.w; | |
} | |
static bool InitializeDirectSound(MiniEmul* _emul) | |
{ | |
HRESULT result; | |
DSBUFFERDESC bufferDesc; | |
WAVEFORMATEX waveFormat; | |
// Initialize the direct sound interface pointer for the default sound device. | |
result = DirectSoundCreate8(NULL, &(_emul->directSound), NULL); | |
if(FAILED(result)) | |
{ | |
return false; | |
} | |
// Set the cooperative level to priority so the format of the primary sound buffer can be modified. | |
result = _emul->directSound->SetCooperativeLevel((HWND)WINgetWindowHandle(_emul->w), DSSCL_PRIORITY); | |
if(FAILED(result)) | |
{ | |
return false; | |
} | |
// Setup the primary buffer description. | |
bufferDesc.dwSize = sizeof(DSBUFFERDESC); | |
bufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME; | |
bufferDesc.dwBufferBytes = 0; | |
bufferDesc.dwReserved = 0; | |
bufferDesc.lpwfxFormat = NULL; | |
bufferDesc.guid3DAlgorithm = GUID_NULL; | |
// Get control of the primary sound buffer on the default sound device. | |
result = _emul->directSound->CreateSoundBuffer(&bufferDesc, &(_emul->primaryBuffer), NULL); | |
if(FAILED(result)) | |
{ | |
return false; | |
} | |
// Setup the format of the primary sound bufffer. | |
// In this case it is a .WAV file recorded at 44,100 samples per second in 16-bit stereo (cd audio format). | |
waveFormat.wFormatTag = WAVE_FORMAT_PCM; | |
waveFormat.nSamplesPerSec = 44100; | |
waveFormat.wBitsPerSample = 16; | |
waveFormat.nChannels = 2; | |
waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels; | |
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; | |
waveFormat.cbSize = 0; | |
// Set the primary buffer to be the wave format specified. | |
result = _emul->primaryBuffer->SetFormat(&waveFormat); | |
if(FAILED(result)) | |
{ | |
return false; | |
} | |
return true; | |
} | |
static s32 g_EMULleftChannelAmp = 64; | |
extern "C" void EMULleftChannel(void) | |
{ | |
const float dbleft = -2.0f * (float)(20 - (*HW_MICROWIRE_DATA & 0x3F)); | |
g_EMULleftChannelAmp = (s32) (powf(10.0f, dbleft / 10.0f) * 64.0f); | |
} | |
static s32 g_EMULrightChannelAmp = 64; | |
extern "C" void EMULrightChannel(void) | |
{ | |
const float dbright = -2.0f * float(20 - (*HW_MICROWIRE_DATA & 0x3F)); | |
g_EMULrightChannelAmp = (s32) (powf(10.0f, dbright / 10.0f) * 64.0f); | |
} | |
extern "C" void EMULplaysound (void* _data, u32 _byteslength, u32 _offset) | |
{ | |
void* bufferPtr = NULL; | |
DWORD bufferSize = 0; | |
void* bufferPtr2 = NULL; | |
DWORD bufferSize2 = 0; | |
HRESULT result = g_miniEmul.secondaryBuffer->Lock(_offset, _byteslength, (void**)&bufferPtr, (DWORD*)&bufferSize, (void**)&bufferPtr2, (DWORD*)&bufferSize2, 0); | |
ASSERT (result == DS_OK); | |
ASSERT (bufferPtr2 == NULL); | |
u32 t; | |
u8* d = (u8*)bufferPtr; | |
s8* s = (s8*)_data; | |
for (t = 0 ; t < _byteslength ; t += 2) | |
{ | |
*d++ = (s8) ( (((*s++) * g_EMULleftChannelAmp) >> 6) + 128); | |
*d++ = (s8) ( (((*s++) * g_EMULrightChannelAmp) >> 6) + 128); | |
} | |
result = g_miniEmul.secondaryBuffer->Unlock((void*)bufferPtr, bufferSize, bufferPtr2, bufferSize2); | |
ASSERT (result == DS_OK); | |
if (g_miniEmul.captureSound) | |
{ | |
static FILE* file = NULL; | |
if (file == NULL) | |
{ | |
file = fopen (".\\_logs\\dmadump.raw", "wb"); | |
} | |
fwrite (_data, 1, _byteslength, file); | |
WINsetColor (g_miniEmul.w, 255, 0, 0); | |
WINfilledRectangle(g_miniEmul.w, 5, 5, 30, 30); | |
} | |
} | |
extern "C" void EMULgetSound (void* _data, u32 _byteslength) | |
{ | |
void* bufferPtr = NULL; | |
DWORD bufferSize = 0; | |
HRESULT result = g_miniEmul.secondaryBuffer->Lock(0, _byteslength, (void**)&bufferPtr, (DWORD*)&bufferSize, NULL, 0, DSBLOCK_ENTIREBUFFER); | |
ASSERT (result == DS_OK); | |
{ | |
u32 t; | |
u8* d = (u8*)bufferPtr; | |
s8* s = (s8*)_data; | |
for (t = 0 ; t < _byteslength ; t++) | |
{ | |
*s++ = (*d++) - 128; | |
} | |
} | |
// Unlock the secondary buffer after the data has been written to it. | |
result = g_miniEmul.secondaryBuffer->Unlock((void*)bufferPtr, bufferSize, NULL, 0); | |
ASSERT (result == DS_OK); | |
} | |
extern "C" u32 EMULgetPlayOffset (void) | |
{ | |
DWORD playCursor = 0, writeCursor = 0; | |
g_miniEmul.secondaryBuffer->GetCurrentPosition(&playCursor, &writeCursor); | |
return writeCursor; | |
} | |
extern "C" void EMULcreateSoundBuffer (u32 _length, bool _stereo, u32 _dmafreq) | |
{ | |
WAVEFORMATEX waveFormat; | |
DSBUFFERDESC bufferDesc; | |
HRESULT result; | |
IDirectSoundBuffer* tempBuffer; | |
unsigned nbChannels = _stereo ? 2 : 1; | |
if ( g_miniEmul.secondaryBuffer != NULL ) | |
{ | |
g_miniEmul.secondaryBuffer->Release(); | |
g_miniEmul.secondaryBuffer = NULL; | |
} | |
// Set the wave format of secondary buffer that this wave file will be loaded onto. | |
waveFormat.wFormatTag = WAVE_FORMAT_PCM; | |
waveFormat.nSamplesPerSec = _dmafreq; | |
waveFormat.wBitsPerSample = 8; | |
waveFormat.nChannels = nbChannels; | |
waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels; | |
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; | |
waveFormat.cbSize = 0; | |
// Set the buffer description of the secondary sound buffer that the wave file will be loaded onto. | |
bufferDesc.dwSize = sizeof(DSBUFFERDESC); | |
bufferDesc.dwFlags = DSBCAPS_CTRLVOLUME; | |
bufferDesc.dwBufferBytes = _length * 2; // double buffer | |
bufferDesc.dwReserved = 0; | |
bufferDesc.lpwfxFormat = &waveFormat; | |
bufferDesc.guid3DAlgorithm = GUID_NULL; | |
// Create a temporary sound buffer with the specific buffer settings. | |
result = g_miniEmul.directSound->CreateSoundBuffer(&bufferDesc, &tempBuffer, NULL); | |
ASSERT ( result == DS_OK ); | |
// Test the buffer format against the direct sound 8 interface and create the secondary buffer. | |
result = tempBuffer->QueryInterface(IID_IDirectSoundBuffer8, (void**)&g_miniEmul.secondaryBuffer); | |
ASSERT ( result == DS_OK ); | |
// Release the temporary buffer. | |
tempBuffer->Release(); | |
tempBuffer = 0; | |
// Create a temporary buffer to hold the wave file data. | |
// Lock the secondary buffer to write wave data into it. | |
void* bufferPtr = NULL; | |
DWORD bufferSize = 0; | |
result = g_miniEmul.secondaryBuffer->Lock(0, _length * 2, (void**)&bufferPtr, (DWORD*)&bufferSize, NULL, 0, DSBLOCK_ENTIREBUFFER); | |
ASSERT ( result == DS_OK ); | |
STDmset (bufferPtr, 0, bufferSize); | |
// Unlock the secondary buffer after the data has been written to it. | |
result = g_miniEmul.secondaryBuffer->Unlock((void*)bufferPtr, bufferSize, NULL, 0); | |
ASSERT ( result == DS_OK ); | |
// Set position at the beginning of the sound buffer. | |
result = g_miniEmul.secondaryBuffer->SetCurrentPosition(0); | |
ASSERT ( result == DS_OK ); | |
// Set volume of the buffer to 100%. | |
result = g_miniEmul.secondaryBuffer->SetVolume(DSBVOLUME_MAX); | |
ASSERT ( result == DS_OK ); | |
// Play the contents of the secondary sound buffer. | |
result = g_miniEmul.secondaryBuffer->Play(0, 0, DSBPLAY_LOOPING); | |
ASSERT ( result == DS_OK ); | |
} | |
static void ShutdownDirectSound(MiniEmul* _emul) | |
{ | |
// Release the secondary sound buffer. | |
if (_emul->secondaryBuffer) | |
{ | |
_emul->secondaryBuffer->Release(); | |
_emul->secondaryBuffer = NULL; | |
} | |
// Release the primary sound buffer pointer. | |
if (_emul->primaryBuffer) | |
{ | |
_emul->primaryBuffer->Release(); | |
_emul->primaryBuffer = NULL; | |
} | |
// Release the direct sound interface pointer. | |
if(_emul->directSound) | |
{ | |
_emul->directSound->Release(); | |
_emul->directSound = NULL; | |
} | |
} | |
extern "C" void EMULinit (void* _buffer, s16 _width, s16 _height, s16 _width_ext) | |
{ | |
WINinitParam param; | |
bool result; | |
DEFAULT_CONSTRUCT(&g_miniEmul); | |
param.x = param.y = WINDOW_CENTER; | |
param.w = _width == -1 ? EMUL_WINDOW_WIDTH : _width; | |
param.h = _height == -1 ? EMUL_WINDOW_HEIGHT : _height; | |
param.title = NULL; | |
param.hInstance = NULL; | |
g_miniEmul.width = (u16) param.w; | |
g_miniEmul.height = (u16) param.h; | |
memset (g_miniEmul.image, 0, sizeof(g_miniEmul.image)); | |
param.w += _width_ext; | |
g_miniEmul.w = WINconstruct (¶m); | |
result = InitializeDirectSound(&g_miniEmul); | |
ASSERT (result); | |
} | |
static u32 ST2RVBcolor (u16 _color) | |
{ | |
u16 color = PCENDIANSWAP16(_color); | |
u8 R = (u8)(color >> 8); | |
u8 G = (u8)(color >> 4); | |
u8 B = (u8)(color); | |
R <<= 1; | |
G <<= 1; | |
B <<= 1; | |
R |= (R & 0x10) != 0; | |
G |= (G & 0x10) != 0; | |
B |= (B & 0x10) != 0; | |
R &= 0xF; | |
G &= 0xF; | |
B &= 0xF; | |
R <<= 4; | |
G <<= 4; | |
B <<= 4; | |
return ((u32)R << 16) | ((u32)G << 8) | (u32)B; | |
} | |
static void ST2PCLut(u16* _STlut, u32* _PClut) | |
{ | |
u8 i; | |
for (i = 0 ; i < 16 ; i++) | |
{ | |
_PClut[i] = ST2RVBcolor(_STlut[i]); | |
} | |
} | |
static u8 emulVideoMode2NBP(u8 _videomode) | |
{ | |
switch (_videomode) | |
{ | |
case HW_VIDEO_MODE_1P: return 1; | |
case HW_VIDEO_MODE_2P: return 2; | |
case HW_VIDEO_MODE_4P: return 4; | |
default: ASSERT(0); return 0; | |
} | |
} | |
static void emulfromChunkToRVB (void* _base, u8 _videomode) | |
{ | |
u8* source = (u8*) _base; | |
u32* dest = (u32*) g_miniEmul.image; | |
u32* commands = g_miniEmul.fbext.commands; | |
u8 videomode = (u8) *commands++; | |
u16 startcyclex = (u16) *commands++; | |
u16 starty = (u16) *commands++; | |
u16 endcyclex = (u16) *commands++; | |
u16 endy = (u16) *commands++; | |
u16 pitch = (u16) *commands++; | |
u32 currentcycley = 0; | |
u16 y; | |
u8 nbP = emulVideoMode2NBP(videomode); | |
ASSERT(g_miniEmul.fbext.enable); | |
ASSERT(nbP <= 4); | |
for (y = 0 ; y < emul_HEIGHT ; y++) | |
{ | |
u16 currentcyclex = 0; | |
u16 planes[4]; | |
u16 x, shifterx = 0; | |
u16* s = (u16*) source; | |
u32* d = dest; | |
if (nbP != 1) | |
{ | |
if (y == (emul_HEIGHT / 2)) | |
{ | |
break; | |
} | |
} | |
for (x = 0 ; x < emul_WIDTH ; x++) | |
{ | |
u32 currentcycle = currentcycley + currentcyclex; | |
u16 p; | |
while (currentcycle == *commands) | |
{ | |
commands++; | |
switch (*commands++) | |
{ | |
case FBEXT_SETCOLOR: | |
{ | |
u16 index = (u16) *commands++; | |
u16 value = (u16) *commands++; | |
HW_COLOR_LUT[index] = value; | |
} | |
break; | |
case FBEXT_SETVIDEOMODE: | |
videomode = (u8) *commands++; | |
nbP = emulVideoMode2NBP(videomode); | |
break; | |
case FBEXT_SETWIDTH: | |
startcyclex = (u16) *commands++; | |
endcyclex = (u16) *commands++; | |
pitch = (u16) *commands++; | |
break; | |
case FBEXT_SETADR: | |
source = (u8*) *commands++; | |
break; | |
default: | |
ASSERT(0); | |
} | |
} | |
if ((currentcyclex >= startcyclex) && (currentcyclex <= endcyclex) && (y >= starty) && (y <= endy)) | |
{ | |
u8 pix = 0; | |
u8 val = 1 << nbP; | |
if ((shifterx++ & 15) == 0) | |
{ | |
for (p = 0 ; p < nbP ; p++) | |
{ | |
planes[p] = PCENDIANSWAP16( *s ); | |
s++; | |
} | |
} | |
for (p = 0 ; p < nbP ; p++) | |
{ | |
pix |= (planes[p] & 0x8000) != 0 ? val : 0; | |
pix >>= 1; | |
planes[p] <<= 1; | |
} | |
{ | |
u32 v = ST2RVBcolor( HW_COLOR_LUT[pix] ); | |
*d++ = v; | |
if (nbP == 4) | |
{ | |
*d++ = v; | |
} | |
} | |
} | |
else | |
{ | |
u32 v = ST2RVBcolor( HW_COLOR_LUT[0] ); | |
*d++ = v; | |
if (nbP == 4) | |
{ | |
*d++ = v; | |
} | |
} | |
switch (nbP) | |
{ | |
case 4: | |
currentcyclex++; | |
x++; | |
break; | |
case 2: | |
currentcyclex += x & 1; | |
break; | |
case 1: | |
currentcyclex += (x & 3) == 3; | |
break; | |
} | |
} | |
switch (nbP) | |
{ | |
case 4: | |
case 2: | |
currentcycley += 512; | |
break; | |
case 1: | |
currentcycley += 256; | |
break; | |
} | |
if ((y >= starty) && (y <= endy)) | |
{ | |
source += pitch; | |
} | |
if (nbP != 1) | |
{ | |
memset(dest + emul_WIDTH, 0, emul_WIDTH * sizeof(u32)); | |
dest += emul_WIDTH; | |
} | |
dest += emul_WIDTH; | |
} | |
} | |
extern "C" void EMULwait (u32 _ms) | |
{ | |
Sleep(_ms); | |
} | |
extern "C" void EMULcls (void) | |
{ | |
WINsetColor (g_miniEmul.w, 0,0,0); | |
WINclear (g_miniEmul.w); | |
} | |
extern "C" void EMULrender (void) | |
{ | |
void* adr = (void*) SYSreadVideoBase(); | |
u8 videomode = *HW_VIDEO_MODE; | |
u16 steaddpixels = 0; | |
ST2PCLut(HW_COLOR_LUT, g_miniEmul.imagelut); | |
if ((*HW_VIDEO_PIXOFFSET != 0) && (*HW_VIDEO_PIXOFFSET_HIDDEN == 0)) | |
{ | |
steaddpixels = 16; | |
} | |
if (g_miniEmul.fbext.enable) | |
{ | |
emulfromChunkToRVB (adr, videomode); | |
WINdrawImage (g_miniEmul.w, g_miniEmul.image, emul_WIDTH, emul_HEIGHT, 32, NULL, 0, 0); | |
} | |
else | |
{ | |
u16 width = 0; | |
u16 height = 0; | |
u16 pitch = 0; | |
switch (videomode) | |
{ | |
case HW_VIDEO_MODE_1P: | |
width = 640 + steaddpixels; | |
height = 400; | |
pitch = width / 8; | |
BITfromChunk1PTo8b (adr, pitch, NULL, g_miniEmul.image, width, height, width); | |
break; | |
case HW_VIDEO_MODE_2P: | |
width = 640 + steaddpixels; | |
height = 200; | |
pitch = width / 4; | |
BITfromChunk2PTo8b (adr, pitch, NULL, g_miniEmul.image, width, height, width); | |
break; | |
case HW_VIDEO_MODE_4P: | |
width = 320 + steaddpixels; | |
height = 200; | |
pitch = width / 2; | |
BITfromChunk4PTo8b (adr, pitch, NULL, g_miniEmul.image, width, height, width); | |
break; | |
} | |
WINdrawImage (g_miniEmul.w, g_miniEmul.image, width, height, 8, (u8*) g_miniEmul.imagelut, (g_miniEmul.width - width) / 2, (g_miniEmul.height - height) / 2); | |
} | |
WINrender (g_miniEmul.w); | |
{ | |
u32 extrakey = WINgetKeyExtraState (g_miniEmul.w); | |
if ( extrakey != g_miniEmul.lastExtraKey ) | |
{ | |
g_miniEmul.lastExtraKey = extrakey; | |
switch ( extrakey ) | |
{ | |
case VK_PAUSE: | |
g_miniEmul.captureSound ^= 1; | |
break; | |
case VK_END: | |
TRACsaveLog("logPC.txt"); | |
break; | |
} | |
} | |
} | |
*HW_KEYBOARD_DATA = (u8) WINgetKeyState(g_miniEmul.w); | |
} | |
extern "C" void EMULblit (void) | |
{ | |
u8 rshift = *HW_BLITTER_CTRL2 & 15; | |
bool fxsr = (*HW_BLITTER_CTRL2 & HW_BLITTER_CTRL2_FORCE_XTRA_SRC ) != 0; | |
bool nfsr = (*HW_BLITTER_CTRL2 & HW_BLITTER_CTRL2_NO_FINAL_SRC_READ) != 0; | |
u16 htone = (*HW_BLITTER_CTRL1) & 15; | |
u16* s = (u16*) *HW_BLITTER_ADDR_SOURCE; | |
u16* d = (u16*) *HW_BLITTER_ADDR_DEST; | |
s16 incSx = *HW_BLITTER_XINC_SOURCE; | |
s16 incSy = *HW_BLITTER_YINC_SOURCE; | |
s16 incDx = *HW_BLITTER_XINC_DEST; | |
s16 incDy = *HW_BLITTER_YINC_DEST; | |
incSx >>= 1; | |
incSy >>= 1; | |
incDx >>= 1; | |
incDy >>= 1; | |
do | |
{ | |
u16 x; | |
u16 w1 = 0; | |
u16 endmask = *HW_BLITTER_ENDMASK1; | |
endmask = PCENDIANSWAP16 (endmask); | |
if (fxsr) | |
{ | |
w1 = *s; | |
w1 = PCENDIANSWAP16(w1); | |
s += incSx; | |
} | |
for (x = *HW_BLITTER_XSIZE ; x > 0 ; x--) | |
{ | |
u16 w2 = 0; | |
u16 sw = -1; | |
u16 dw; | |
if ((x != 1) || (nfsr == 0)) | |
{ | |
if (((*HW_BLITTER_HOP) & HW_BLITTER_HOP_SOURCE) != 0) | |
{ | |
w2 = *s; | |
w2 = PCENDIANSWAP16(w2); | |
} | |
} | |
switch (*HW_BLITTER_HOP) | |
{ | |
case HW_BLITTER_HOP_BIT1: | |
sw = 0xFFFF; | |
break; | |
case HW_BLITTER_HOP_HTONE: | |
sw = HW_BLITTER_HTONE[htone & 15]; | |
sw = PCENDIANSWAP16(sw); | |
break; | |
case HW_BLITTER_HOP_SOURCE: | |
case HW_BLITTER_HOP_SOURCE_AND_HTONE: | |
sw = (w1 << (16 - rshift)) | (w2 >> rshift); | |
if ((*HW_BLITTER_HOP) == HW_BLITTER_HOP_SOURCE_AND_HTONE) | |
{ | |
u16 ht = HW_BLITTER_HTONE[htone & 15]; | |
ht = PCENDIANSWAP16(ht); | |
sw &= ht; | |
} | |
break; | |
} | |
w1 = w2; | |
/* apply logical operation */ | |
dw = *d; | |
dw = PCENDIANSWAP16(dw); | |
switch (*HW_BLITTER_OP) | |
{ | |
case HW_BLITTER_OP_BIT0: dw = 0; break; | |
case HW_BLITTER_OP_S_AND_D: dw = sw & dw; break; | |
case HW_BLITTER_OP_S_AND_NOT_D: dw = sw & ~dw; break; | |
case HW_BLITTER_OP_S: dw = sw; break; | |
case HW_BLITTER_OP_NOT_S_AND_D: dw = ~sw & dw; break; | |
case HW_BLITTER_OP_D: dw = *d; break; | |
case HW_BLITTER_OP_S_XOR_D: dw = sw ^ dw; break; | |
case HW_BLITTER_OP_S_OR_D: dw = sw | dw; break; | |
case HW_BLITTER_OP_NOT_S_AND_NOT_D: dw = ~sw & ~dw; break; | |
case HW_BLITTER_OP_NOT_S_XOR_D: dw = ~sw ^ dw; break; | |
case HW_BLITTER_OP_NOT_D: dw = ~dw; break; | |
case HW_BLITTER_OP_NOT_S: dw = ~sw; break; | |
case HW_BLITTER_OP_S_OR_NOT_D: dw = sw | ~dw; break; | |
case HW_BLITTER_OP_NOT_S_OR_D: dw = ~sw | dw; break; | |
case HW_BLITTER_OP_NOT_S_OR_NOT_D: dw = ~sw | ~dw; break; | |
case HW_BLITTER_OP_BIT1: dw = -1; break; | |
} | |
/* end mask and destination write */ | |
{ | |
u16 dm = PCENDIANSWAP16(*d); | |
u16 dbak = dm & ~endmask; | |
dw = dbak | (dw & endmask); | |
dw = PCENDIANSWAP16(dw); | |
*d = dw; | |
} | |
if (x != 1) | |
{ | |
s += incSx; | |
d += incDx; | |
} | |
if (x == 2) | |
{ | |
if ( nfsr ) | |
{ | |
s -= incSx; | |
} | |
endmask = *HW_BLITTER_ENDMASK3; | |
endmask = PCENDIANSWAP16 (endmask); | |
} | |
else | |
{ | |
endmask = *HW_BLITTER_ENDMASK2; | |
endmask = PCENDIANSWAP16 (endmask); | |
} | |
} | |
s += incSy; | |
d += incDy; | |
htone++; | |
(*HW_BLITTER_YSIZE)--; | |
} | |
while (*HW_BLITTER_YSIZE); | |
*HW_BLITTER_ADDR_SOURCE = (u32) s; | |
*HW_BLITTER_ADDR_DEST = (u32) d; | |
} | |
// 68k port helpers | |
extern "C" u8* EMUL_B_I (EMULregister* _reg) | |
{ | |
u8* adr = (u8*) _reg->l; | |
_reg->l++; | |
return adr; | |
} | |
extern "C" u16* EMUL_W_I (EMULregister* _reg) | |
{ | |
u16* adr = (u16*) _reg->l; | |
_reg->l += 2; | |
return adr; | |
} | |
extern "C" u32* EMUL_L_I (EMULregister* _reg) | |
{ | |
u32* adr = (u32*) _reg->l; | |
_reg->l += 4; | |
return adr; | |
} | |
extern "C" void EMUL_ROR_W (EMULregister* _reg, u8 _shift) | |
{ | |
if (_shift > 0) | |
{ | |
u16 bits = _reg->w; | |
_shift &= 15; | |
bits <<= 16 - _shift; | |
_reg->w >>= _shift; | |
_reg->w |= bits; | |
} | |
} | |
extern "C" void EMUL_ROL_L (EMULregister* _reg, u8 _shift) | |
{ | |
if (_shift > 0) | |
{ | |
u32 bits = _reg->l; | |
_shift &= 31; | |
bits >>= 32 - _shift; | |
_reg->l <<= _shift; | |
_reg->l |= bits; | |
} | |
} | |
extern "C" void EMUL_LSL_L (EMULregister* _reg, u8 _shift) | |
{ | |
if (_shift >= 32) | |
{ | |
_reg->l = 0; | |
} | |
else | |
{ | |
_reg->l <<= _shift; | |
} | |
} | |
extern "C" void EMUL_SUB_B (EMULregister* _source, EMULregister* _dest, EMUL68k* _p) | |
{ | |
u16 source = _source->b; | |
u16 dest = _dest->b; | |
dest -= source; | |
_dest->b = (u8) dest; | |
_p->carry = (dest & 0x100) != 0; | |
} | |
extern "C" bool EMUL_BTST (u32 _data, u8 _bit) | |
{ | |
return (_data & (1 << _bit)) != 0; | |
} | |
extern "C" void EMULlog(char* str) | |
{ | |
OutputDebugStringA(str); | |
} |