mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 15:27:46 -04:00
the old-new win32 port
git-svn-id: file:///home/notaz/opt/svn/PicoDrive@804 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
parent
ae87bffa06
commit
823b9004c4
21 changed files with 2072 additions and 6 deletions
|
@ -21,7 +21,12 @@ static char *mystrip(char *str);
|
||||||
#include "emu.h"
|
#include "emu.h"
|
||||||
#include <pico/pico.h>
|
#include <pico/pico.h>
|
||||||
|
|
||||||
|
// always output DOS endlines
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define NL "\n"
|
||||||
|
#else
|
||||||
#define NL "\r\n"
|
#define NL "\r\n"
|
||||||
|
#endif
|
||||||
|
|
||||||
static int seek_sect(FILE *f, const char *section)
|
static int seek_sect(FILE *f, const char *section)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "plat.h"
|
#include "plat.h"
|
||||||
#include "../linux/in_evdev.h"
|
#include "../linux/in_evdev.h"
|
||||||
#include "../gp2x/in_gp2x.h"
|
#include "../gp2x/in_gp2x.h"
|
||||||
|
#include "../win32/in_vk.h"
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -237,6 +238,7 @@ int in_update(int *result)
|
||||||
for (i = 0; i < in_dev_count; i++) {
|
for (i = 0; i < in_dev_count; i++) {
|
||||||
in_dev_t *dev = &in_devices[i];
|
in_dev_t *dev = &in_devices[i];
|
||||||
if (dev->probed && dev->binds != NULL) {
|
if (dev->probed && dev->binds != NULL) {
|
||||||
|
// FIXME: this is stupid, make it indirect
|
||||||
switch (dev->drv_id) {
|
switch (dev->drv_id) {
|
||||||
#ifdef IN_EVDEV
|
#ifdef IN_EVDEV
|
||||||
case IN_DRVID_EVDEV:
|
case IN_DRVID_EVDEV:
|
||||||
|
@ -248,6 +250,9 @@ int in_update(int *result)
|
||||||
ret |= in_gp2x_update(dev->drv_data, dev->binds, result);
|
ret |= in_gp2x_update(dev->drv_data, dev->binds, result);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case IN_DRVID_VK:
|
||||||
|
ret |= in_vk_update(dev->drv_data, dev->binds, result);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -808,6 +813,7 @@ void in_init(void)
|
||||||
#ifdef IN_EVDEV
|
#ifdef IN_EVDEV
|
||||||
in_evdev_init(&in_drivers[IN_DRVID_EVDEV]);
|
in_evdev_init(&in_drivers[IN_DRVID_EVDEV]);
|
||||||
#endif
|
#endif
|
||||||
|
in_vk_init(&in_drivers[IN_DRVID_VK]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
|
@ -50,6 +50,7 @@ enum {
|
||||||
IN_DRVID_UNKNOWN = 0,
|
IN_DRVID_UNKNOWN = 0,
|
||||||
IN_DRVID_GP2X,
|
IN_DRVID_GP2X,
|
||||||
IN_DRVID_EVDEV,
|
IN_DRVID_EVDEV,
|
||||||
|
IN_DRVID_VK,
|
||||||
IN_DRVID_COUNT,
|
IN_DRVID_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,10 @@
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
extern void lprintf(const char *fmt, ...);
|
extern void lprintf(const char *fmt, ...);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include <pico/patch.h>
|
#include <pico/patch.h>
|
||||||
|
|
||||||
static char static_buff[64];
|
static char static_buff[64];
|
||||||
static char menu_error_msg[64] = { 0, };
|
char menu_error_msg[64] = { 0, };
|
||||||
static int menu_error_time = 0;
|
static int menu_error_time = 0;
|
||||||
|
|
||||||
#ifndef UIQ3
|
#ifndef UIQ3
|
||||||
|
|
|
@ -159,6 +159,9 @@ void menu_plat_setup(int is_wiz);
|
||||||
void text_out16(int x, int y, const char *texto, ...);
|
void text_out16(int x, int y, const char *texto, ...);
|
||||||
void me_update_msg(const char *msg);
|
void me_update_msg(const char *msg);
|
||||||
|
|
||||||
|
void menu_romload_prepare(const char *rom_name);
|
||||||
|
void menu_romload_end(void);
|
||||||
|
|
||||||
void menu_loop(void);
|
void menu_loop(void);
|
||||||
int menu_loop_tray(void);
|
int menu_loop_tray(void);
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,6 @@ void pemu_sound_start(void);
|
||||||
void pemu_sound_stop(void);
|
void pemu_sound_stop(void);
|
||||||
void pemu_sound_wait(void);
|
void pemu_sound_wait(void);
|
||||||
|
|
||||||
void menu_romload_prepare(const char *rom_name);
|
|
||||||
void menu_romload_end(void);
|
|
||||||
|
|
||||||
void plat_early_init(void);
|
void plat_early_init(void);
|
||||||
void plat_init(void);
|
void plat_init(void);
|
||||||
void plat_finish(void);
|
void plat_finish(void);
|
||||||
|
@ -44,7 +41,7 @@ int plat_is_dir(const char *path);
|
||||||
int plat_wait_event(int *fds_hnds, int count, int timeout_ms);
|
int plat_wait_event(int *fds_hnds, int count, int timeout_ms);
|
||||||
void plat_sleep_ms(int ms);
|
void plat_sleep_ms(int ms);
|
||||||
|
|
||||||
/* timers, to be used for time diff and must refet to the same clock */
|
/* timers, to be used for time diff and must refer to the same clock */
|
||||||
unsigned int plat_get_ticks_ms(void);
|
unsigned int plat_get_ticks_ms(void);
|
||||||
unsigned int plat_get_ticks_us(void);
|
unsigned int plat_get_ticks_us(void);
|
||||||
void plat_wait_till_us(unsigned int us);
|
void plat_wait_till_us(unsigned int us);
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
/* define POSIX stuff: dirent, scandir, getcwd, mkdir */
|
/* define POSIX stuff: dirent, scandir, getcwd, mkdir */
|
||||||
#if defined(__linux__)
|
#if defined(__linux__) || defined(__MINGW32__)
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
#warning hacks!
|
||||||
|
#define mkdir(pathname,mode) mkdir(pathname)
|
||||||
|
#define d_type d_ino
|
||||||
|
#define DT_REG 0
|
||||||
|
#define DT_DIR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#error "must provide posix"
|
#error "must provide posix"
|
||||||
|
|
129
platform/win32/Makefile
Normal file
129
platform/win32/Makefile
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
# settings
|
||||||
|
CROSS=i586-mingw32msvc-
|
||||||
|
|
||||||
|
#use_musashi = 1
|
||||||
|
use_fame = 1
|
||||||
|
#use_mz80 = 1
|
||||||
|
|
||||||
|
-include Makefile.local
|
||||||
|
|
||||||
|
CC = $(CROSS)gcc
|
||||||
|
CXX = $(CROSS)g++
|
||||||
|
LD = $(CROSS)ld
|
||||||
|
STRIP = $(CROSS)strip
|
||||||
|
|
||||||
|
DEFINES = _UNZIP_SUPPORT IN_VK
|
||||||
|
CFLAGS += -O2 -Wall -falign-functions=2 -ffast-math
|
||||||
|
CFLAGS += -I../.. -I. -I../../zlib/ -Idirectx/include/
|
||||||
|
LDFLAGS += -L. -Ldirectx/lib/ -lgdi32 -lcomdlg32 -lddraw -ldsound -ldxguid
|
||||||
|
|
||||||
|
# frontend
|
||||||
|
OBJS += main.o plat.o direct.o dsnd.o in_vk.o
|
||||||
|
|
||||||
|
# common
|
||||||
|
OBJS += platform/common/emu.o platform/common/menu.o \
|
||||||
|
platform/common/config.o platform/common/fonts.o platform/common/readpng.o \
|
||||||
|
platform/common/input.o
|
||||||
|
|
||||||
|
# Pico
|
||||||
|
OBJS += pico/area.o pico/cart.o pico/memory.o pico/pico.o pico/sek.o \
|
||||||
|
pico/videoport.o pico/draw2.o pico/draw.o pico/z80if.o pico/patch.o \
|
||||||
|
pico/mode4.o pico/sms.o pico/misc.o pico/eeprom.o pico/debug.o
|
||||||
|
# Pico - CD
|
||||||
|
OBJS += pico/cd/pico.o pico/cd/memory.o pico/cd/sek.o pico/cd/LC89510.o \
|
||||||
|
pico/cd/cd_sys.o pico/cd/cd_file.o pico/cd/cue.o pico/cd/gfx_cd.o \
|
||||||
|
pico/cd/area.o pico/cd/misc.o pico/cd/pcm.o pico/cd/buffering.o
|
||||||
|
# Pico - 32X
|
||||||
|
OBJS += pico/32x/32x.o pico/32x/memory.o pico/32x/draw.o pico/32x/pwm.o
|
||||||
|
# Pico - Pico
|
||||||
|
OBJS += pico/pico/pico.o pico/pico/memory.o pico/pico/xpcm.o
|
||||||
|
# Pico - sound
|
||||||
|
OBJS += pico/sound/sound.o pico/sound/sn76496.o pico/sound/ym2612.o pico/sound/mix.o
|
||||||
|
# Pico - carthw
|
||||||
|
OBJS += pico/carthw/carthw.o pico/carthw/svp/svp.o pico/carthw/svp/memory.o \
|
||||||
|
pico/carthw/svp/ssp16.o pico/carthw/svp/compiler.o
|
||||||
|
# zlib
|
||||||
|
OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \
|
||||||
|
zlib/deflate.o zlib/crc32.o zlib/adler32.o zlib/zutil.o zlib/compress.o zlib/uncompr.o
|
||||||
|
# unzip
|
||||||
|
OBJS += unzip/unzip.o unzip/unzip_stream.o
|
||||||
|
# CPU cores
|
||||||
|
ifeq "$(use_musashi)" "1"
|
||||||
|
DEFINES += EMU_M68K
|
||||||
|
OBJS += cpu/musashi/m68kops.o cpu/musashi/m68kcpu.o
|
||||||
|
#OBJS += cpu/musashi/m68kdasm.o
|
||||||
|
endif
|
||||||
|
ifeq "$(use_fame)" "1"
|
||||||
|
DEFINES += EMU_F68K
|
||||||
|
OBJS += cpu/fame/famec.o
|
||||||
|
endif
|
||||||
|
# z80
|
||||||
|
ifeq "$(use_mz80)" "1"
|
||||||
|
DEFINES += _USE_MZ80
|
||||||
|
OBJS += cpu/mz80/mz80.o
|
||||||
|
else
|
||||||
|
DEFINES += _USE_CZ80
|
||||||
|
OBJS += cpu/cz80/cz80.o
|
||||||
|
endif
|
||||||
|
# sh2
|
||||||
|
OBJS += cpu/sh2mame/sh2pico.o
|
||||||
|
# misc
|
||||||
|
ifeq "$(use_fame)" "1"
|
||||||
|
ifeq "$(use_musashi)" "1"
|
||||||
|
OBJS += pico/debugCPU.o
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
CFLAGS += $(addprefix -D,$(DEFINES))
|
||||||
|
CXXFLAGS = $(CFLAGS)
|
||||||
|
|
||||||
|
vpath %.c = ../..
|
||||||
|
|
||||||
|
DIRS = platform platform/gp2x platform/common pico pico/cd pico/pico pico/sound pico/carthw/svp \
|
||||||
|
pico/32x zlib unzip cpu cpu/musashi cpu/fame cpu/mz80 cpu/cz80 cpu/sh2mame
|
||||||
|
|
||||||
|
TARGET = PicoDrive.exe
|
||||||
|
|
||||||
|
all: mkdirs $(TARGET)
|
||||||
|
clean: tidy
|
||||||
|
@$(RM) $(TARGET)
|
||||||
|
tidy:
|
||||||
|
$(RM) $(OBJS) $(TARGET).map
|
||||||
|
rm -rf $(DIRS)
|
||||||
|
|
||||||
|
$(TARGET) : $(OBJS)
|
||||||
|
@echo ">>>" $@
|
||||||
|
$(CC) $(CFLAGS) $^ $(LDFLAGS) -lm -lpng -Wl,-Map=$(TARGET).map -o $@
|
||||||
|
$(STRIP) $@
|
||||||
|
|
||||||
|
mkdirs:
|
||||||
|
@mkdir -p $(DIRS)
|
||||||
|
|
||||||
|
include ../common/revision.mak
|
||||||
|
|
||||||
|
pico/carthw/svp/compiler.o : ../../pico/carthw/svp/gen_arm.c
|
||||||
|
pico/pico.o pico/cd/pico.o : ../../pico/pico_cmn.c ../../pico/pico_int.h
|
||||||
|
pico/memory.o pico/cd/memory.o : ../../pico/pico_int.h ../../pico/memory.h
|
||||||
|
|
||||||
|
../../cpu/musashi/m68kops.c :
|
||||||
|
@make -C ../../cpu/musashi
|
||||||
|
|
||||||
|
cpu/mz80/mz80.o : ../../cpu/mz80/mz80.asm
|
||||||
|
@echo $@
|
||||||
|
@nasm -f elf $< -o $@
|
||||||
|
|
||||||
|
../../cpu/mz80/mz80.asm :
|
||||||
|
@make -C ../../cpu/mz80/
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
@echo ">>>" $<
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
.s.o:
|
||||||
|
@echo ">>>" $<
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
cpu/fame/famec.o : ../../cpu/fame/famec.c ../../cpu/fame/famec_opcodes.h
|
||||||
|
@echo ">>>" $<
|
||||||
|
$(CC) $(CFLAGS) -Wno-unused -c $< -o $@
|
||||||
|
|
410
platform/win32/direct.cpp
Normal file
410
platform/win32/direct.cpp
Normal file
|
@ -0,0 +1,410 @@
|
||||||
|
// ddraw
|
||||||
|
#include <ddraw.h>
|
||||||
|
#include "../common/lprintf.h"
|
||||||
|
#include "direct.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
#define EmuWidth 320
|
||||||
|
#define EmuHeight 240
|
||||||
|
|
||||||
|
#define RELEASE(x) if (x) x->Release(); x=NULL;
|
||||||
|
#define LOGFAIL() lprintf("fail: %s %s:%i\n", __FUNCTION__, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
static LPDIRECTDRAW7 m_pDD = NULL;
|
||||||
|
static LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer = NULL;
|
||||||
|
static LPDIRECTDRAWSURFACE7 m_pddsBackBuffer = NULL;
|
||||||
|
|
||||||
|
// quick and dirty stuff..
|
||||||
|
void DirectExit(void)
|
||||||
|
{
|
||||||
|
RELEASE(m_pddsBackBuffer);
|
||||||
|
RELEASE(m_pddsFrontBuffer);
|
||||||
|
RELEASE(m_pDD);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DirectInit(void)
|
||||||
|
{
|
||||||
|
HRESULT ret;
|
||||||
|
LPDIRECTDRAWCLIPPER pcClipper = NULL;
|
||||||
|
DDSURFACEDESC2 ddsd;
|
||||||
|
|
||||||
|
ret = DirectDrawCreateEx(NULL, (VOID**)&m_pDD, IID_IDirectDraw7, NULL);
|
||||||
|
if (ret) { LOGFAIL(); return 1; }
|
||||||
|
|
||||||
|
// Set cooperative level
|
||||||
|
ret = m_pDD->SetCooperativeLevel( FrameWnd, DDSCL_NORMAL );
|
||||||
|
if (ret) { LOGFAIL(); goto fail; }
|
||||||
|
|
||||||
|
// Create the primary surface
|
||||||
|
ZeroMemory( &ddsd, sizeof( ddsd ) );
|
||||||
|
ddsd.dwSize = sizeof( ddsd );
|
||||||
|
ddsd.dwFlags = DDSD_CAPS;
|
||||||
|
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
||||||
|
|
||||||
|
ret = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL );
|
||||||
|
if (ret) { LOGFAIL(); goto fail; }
|
||||||
|
|
||||||
|
// Create the backbuffer surface
|
||||||
|
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
|
||||||
|
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
||||||
|
ddsd.dwWidth = EmuWidth;
|
||||||
|
ddsd.dwHeight = EmuHeight;
|
||||||
|
|
||||||
|
ret = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL );
|
||||||
|
if (ret) { LOGFAIL(); goto fail; }
|
||||||
|
|
||||||
|
// clipper
|
||||||
|
ret = m_pDD->CreateClipper( 0, &pcClipper, NULL );
|
||||||
|
if (ret) { LOGFAIL(); goto fail; }
|
||||||
|
|
||||||
|
ret = pcClipper->SetHWnd( 0, FrameWnd );
|
||||||
|
if (ret) { LOGFAIL(); goto fail; }
|
||||||
|
|
||||||
|
ret = m_pddsFrontBuffer->SetClipper( pcClipper );
|
||||||
|
if (ret) { LOGFAIL(); goto fail; }
|
||||||
|
|
||||||
|
RELEASE(pcClipper);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
RELEASE(pcClipper);
|
||||||
|
DirectExit();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DirectScreen(const void *emu_screen)
|
||||||
|
{
|
||||||
|
const unsigned short *ps = (const unsigned short *)emu_screen;
|
||||||
|
DDSURFACEDESC2 sd;
|
||||||
|
int ret, x, y;
|
||||||
|
|
||||||
|
memset(&sd, 0, sizeof(sd));
|
||||||
|
sd.dwSize = sizeof(sd);
|
||||||
|
ret = m_pddsBackBuffer->Lock(NULL, &sd, DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_WRITEONLY, NULL);
|
||||||
|
if (ret) { LOGFAIL(); return 1; }
|
||||||
|
|
||||||
|
//lprintf("w: %i h: %i pi: %i pf: %i\n", sd.dwWidth, sd.dwHeight, sd.lPitch, sd.ddpfPixelFormat.dwRGBBitCount);
|
||||||
|
|
||||||
|
if (sd.ddpfPixelFormat.dwRGBBitCount == 32)
|
||||||
|
{
|
||||||
|
int *dst = (int *)sd.lpSurface;
|
||||||
|
for (y = 0; y < EmuHeight; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < EmuWidth; x++)
|
||||||
|
{
|
||||||
|
int s = *ps++;
|
||||||
|
dst[x] = ((s&0xf800)<<8) | ((s&0x07e0)<<5) | ((s&0x001f)<<3);
|
||||||
|
}
|
||||||
|
dst = (int *)((char *)dst + sd.lPitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sd.ddpfPixelFormat.dwRGBBitCount == 24) /* wine uses this for me */
|
||||||
|
{
|
||||||
|
void *dst = sd.lpSurface;
|
||||||
|
for (y = 0; y < EmuHeight; y++)
|
||||||
|
{
|
||||||
|
unsigned char *dst1 = (unsigned char *) dst;
|
||||||
|
for (x = 0; x < EmuWidth; x++, dst1 += 3)
|
||||||
|
{
|
||||||
|
int s = *ps++;
|
||||||
|
dst1[2] = (s&0xf800)>>8; dst1[1] = (s&0x07e0)>>3; dst1[0] = s<<3; // BGR
|
||||||
|
}
|
||||||
|
dst = (void *)((char *)dst + sd.lPitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sd.ddpfPixelFormat.dwRGBBitCount == 16)
|
||||||
|
{
|
||||||
|
unsigned short *dst = (unsigned short *)sd.lpSurface;
|
||||||
|
for (y = 0; y < EmuHeight; y++)
|
||||||
|
{
|
||||||
|
memcpy(dst, ps, EmuWidth*2);
|
||||||
|
ps += EmuWidth;
|
||||||
|
dst = (unsigned short *)((char *)dst + sd.lPitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGFAIL();
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = m_pddsBackBuffer->Unlock(NULL);
|
||||||
|
if (ret) { LOGFAIL(); return 1; }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DirectClear(unsigned int colour)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
DDBLTFX ddbltfx;
|
||||||
|
ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
|
||||||
|
ddbltfx.dwSize = sizeof(ddbltfx);
|
||||||
|
ddbltfx.dwFillColor = colour;
|
||||||
|
|
||||||
|
if (m_pddsBackBuffer != NULL)
|
||||||
|
ret = m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
|
||||||
|
if (ret) { LOGFAIL(); return 1; }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DirectPresent(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
if (FrameRectMy.right - FrameRectMy.left > 0 && FrameRectMy.bottom - FrameRectMy.top > 0)
|
||||||
|
ret = m_pddsFrontBuffer->Blt(&FrameRectMy, m_pddsBackBuffer, &EmuScreenRect, DDBLT_WAIT, NULL);
|
||||||
|
if (ret) { LOGFAIL(); return 1; }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* D3D */
|
||||||
|
#ifdef USE_D3D
|
||||||
|
static IDirect3D8 *Direct3D=NULL;
|
||||||
|
IDirect3DDevice8 *Device=NULL;
|
||||||
|
IDirect3DSurface8 *DirectBack=NULL; // Back Buffer
|
||||||
|
|
||||||
|
static IDirect3DVertexBuffer8 *VertexBuffer=NULL;
|
||||||
|
|
||||||
|
struct CustomVertex
|
||||||
|
{
|
||||||
|
float x,y,z; // Vertex cordinates
|
||||||
|
unsigned int colour;
|
||||||
|
float u,v; // Texture coordinates
|
||||||
|
};
|
||||||
|
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
|
||||||
|
|
||||||
|
static CustomVertex VertexList[4];
|
||||||
|
|
||||||
|
int DirectInit()
|
||||||
|
{
|
||||||
|
D3DPRESENT_PARAMETERS d3dpp;
|
||||||
|
D3DDISPLAYMODE mode;
|
||||||
|
int i,u,ret=0;
|
||||||
|
|
||||||
|
memset(&d3dpp,0,sizeof(d3dpp));
|
||||||
|
memset(&mode,0,sizeof(mode));
|
||||||
|
|
||||||
|
Direct3D=Direct3DCreate8(D3D_SDK_VERSION); if (Direct3D==NULL) return 1;
|
||||||
|
|
||||||
|
// Set up the structure used to create the D3D device:
|
||||||
|
d3dpp.BackBufferWidth =MainWidth;
|
||||||
|
d3dpp.BackBufferHeight=MainHeight;
|
||||||
|
d3dpp.BackBufferCount =1;
|
||||||
|
d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
|
||||||
|
d3dpp.MultiSampleType =D3DMULTISAMPLE_NONE;
|
||||||
|
|
||||||
|
#ifdef _XBOX
|
||||||
|
d3dpp.BackBufferFormat=D3DFMT_X8R8G8B8;
|
||||||
|
d3dpp.FullScreen_RefreshRateInHz=60;
|
||||||
|
#else
|
||||||
|
Direct3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&mode);
|
||||||
|
d3dpp.BackBufferFormat=mode.Format;
|
||||||
|
d3dpp.Windowed=1;
|
||||||
|
d3dpp.hDeviceWindow=FrameWnd;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Try to create a device with hardware vertex processing:
|
||||||
|
for (i=0;i<3;i++)
|
||||||
|
{
|
||||||
|
int behave=D3DCREATE_HARDWARE_VERTEXPROCESSING;
|
||||||
|
|
||||||
|
// Try software vertex processing:
|
||||||
|
if (i==1) behave=D3DCREATE_MIXED_VERTEXPROCESSING;
|
||||||
|
if (i==2) behave=D3DCREATE_SOFTWARE_VERTEXPROCESSING;
|
||||||
|
|
||||||
|
Direct3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,FrameWnd,
|
||||||
|
behave|D3DCREATE_MULTITHREADED,&d3dpp,&Device);
|
||||||
|
if (Device) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Device==NULL)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
// try ref
|
||||||
|
Direct3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_REF,FrameWnd,
|
||||||
|
D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED,&d3dpp,&Device);
|
||||||
|
if (Device==NULL) goto fail0;
|
||||||
|
HMODULE test = LoadLibrary("d3d8d.dll");
|
||||||
|
if (test != NULL) FreeLibrary(test);
|
||||||
|
else {
|
||||||
|
error("Sorry, but this program requires Direct3D with hardware acceleration.\n\n"
|
||||||
|
"You can try using Direct3D software emulation, but you have to install "
|
||||||
|
"DirectX SDK for it to work\n(it seems to be missing now).");
|
||||||
|
goto fail1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
goto fail1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Device->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&DirectBack);
|
||||||
|
if (DirectBack==NULL) goto fail1;
|
||||||
|
|
||||||
|
Device->CreateVertexBuffer(sizeof(VertexList),0,D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT,&VertexBuffer);
|
||||||
|
if (VertexBuffer==NULL) goto fail2;
|
||||||
|
|
||||||
|
ret=TexScreenInit(); if (ret) goto fail3;
|
||||||
|
|
||||||
|
//FontInit();
|
||||||
|
|
||||||
|
Device->SetRenderState(D3DRS_LIGHTING,0); // Turn off lighting
|
||||||
|
|
||||||
|
// Set up texture modes:
|
||||||
|
Device->SetTextureStageState(0,D3DTSS_ADDRESSU,D3DTADDRESS_CLAMP);
|
||||||
|
Device->SetTextureStageState(0,D3DTSS_ADDRESSV,D3DTADDRESS_CLAMP);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail3:
|
||||||
|
RELEASE(VertexBuffer)
|
||||||
|
fail2:
|
||||||
|
RELEASE(DirectBack)
|
||||||
|
fail1:
|
||||||
|
RELEASE(Device)
|
||||||
|
fail0:
|
||||||
|
RELEASE(Direct3D)
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectExit()
|
||||||
|
{
|
||||||
|
TexScreenExit();
|
||||||
|
|
||||||
|
// d3d
|
||||||
|
RELEASE(VertexBuffer)
|
||||||
|
RELEASE(DirectBack)
|
||||||
|
RELEASE(Device)
|
||||||
|
RELEASE(Direct3D)
|
||||||
|
}
|
||||||
|
|
||||||
|
int DirectClear(unsigned int colour)
|
||||||
|
{
|
||||||
|
if (Device != NULL) {
|
||||||
|
Device->Clear(0,NULL,D3DCLEAR_TARGET,colour,1.0f,0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DirectPresent()
|
||||||
|
{
|
||||||
|
if (Device != NULL) {
|
||||||
|
Device->Present(NULL,NULL,NULL,NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PI 3.14159265f
|
||||||
|
|
||||||
|
static int MakeVertexList()
|
||||||
|
{
|
||||||
|
struct CustomVertex *vert=NULL,*pv=NULL;
|
||||||
|
float dist=0.0f;
|
||||||
|
float scalex=0.0f,scaley=0.0f;
|
||||||
|
unsigned int colour=0xffffff;
|
||||||
|
float right=0.0f,bottom=0.0f;
|
||||||
|
|
||||||
|
if (LoopMode!=8) colour=0x102040;
|
||||||
|
|
||||||
|
dist=10.0f; scalex=dist*1.3333f; scaley=dist;
|
||||||
|
|
||||||
|
scalex*=640.0f/(float)MainWidth;
|
||||||
|
scaley*=448.0f/(float)MainHeight;
|
||||||
|
|
||||||
|
vert=VertexList;
|
||||||
|
|
||||||
|
// Put the vertices for the corners of the screen:
|
||||||
|
pv=vert;
|
||||||
|
pv->z=dist;
|
||||||
|
pv->x=-scalex; pv->y=scaley;
|
||||||
|
pv->colour=colour; pv++;
|
||||||
|
|
||||||
|
*pv=vert[0]; pv->x= scalex; pv->y= scaley; pv++;
|
||||||
|
*pv=vert[0]; pv->x=-scalex; pv->y=-scaley; pv++;
|
||||||
|
*pv=vert[0]; pv->x= scalex; pv->y=-scaley; pv++;
|
||||||
|
|
||||||
|
// Find where the screen images ends on the texture
|
||||||
|
right =(float)EmuWidth /(float)TexWidth;
|
||||||
|
bottom=(float)EmuHeight/(float)TexHeight;
|
||||||
|
|
||||||
|
// Write texture coordinates:
|
||||||
|
pv=vert;
|
||||||
|
pv->u=0.0f; pv->v=0.00f; pv++;
|
||||||
|
pv->u=right; pv->v=0.00f; pv++;
|
||||||
|
pv->u=0.0f; pv->v=bottom; pv++;
|
||||||
|
pv->u=right; pv->v=bottom; pv++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SetupMatrices()
|
||||||
|
{
|
||||||
|
D3DXVECTOR3 eye ( 0.0f, 0.0f, 0.0f );
|
||||||
|
D3DXVECTOR3 look( 0.0f, 0.0f, 0.0f );
|
||||||
|
D3DXVECTOR3 up ( 0.0f, 1.0f, 0.0f );
|
||||||
|
D3DXMATRIX mat;
|
||||||
|
float nudgex=0.0f,nudgey=0.0f;
|
||||||
|
|
||||||
|
memset(&mat,0,sizeof(mat));
|
||||||
|
|
||||||
|
mat.m[0][0]=mat.m[1][1]=mat.m[2][2]=mat.m[3][3]=1.0f;
|
||||||
|
Device->SetTransform(D3DTS_WORLD,&mat);
|
||||||
|
|
||||||
|
look.x=(float)Inp.axis[2]/2457.6f;
|
||||||
|
look.y=(float)Inp.axis[3]/2457.6f;
|
||||||
|
look.z=10.0f;
|
||||||
|
|
||||||
|
// Nudge pixels to the centre of each screen pixel:
|
||||||
|
nudgex=13.3333f/(float)(MainWidth <<1);
|
||||||
|
nudgey=10.0000f/(float)(MainHeight<<1);
|
||||||
|
eye.x +=nudgex; eye.y +=nudgey;
|
||||||
|
look.x+=nudgex; look.y+=nudgey;
|
||||||
|
|
||||||
|
D3DXMatrixLookAtLH(&mat,&eye,&look,&up);
|
||||||
|
Device->SetTransform(D3DTS_VIEW,&mat);
|
||||||
|
|
||||||
|
D3DXMatrixPerspectiveFovLH(&mat, 0.5f*PI, 1.3333f, 0.2f, 1000.0f);
|
||||||
|
Device->SetTransform(D3DTS_PROJECTION,&mat);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DirectScreen()
|
||||||
|
{
|
||||||
|
unsigned char *lock=NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (Device == NULL)
|
||||||
|
return DirectScreenDDraw();
|
||||||
|
|
||||||
|
// Copy the screen to the screen texture:
|
||||||
|
#ifdef _XBOX
|
||||||
|
TexScreenSwizzle();
|
||||||
|
#else
|
||||||
|
ret=TexScreenLinear();
|
||||||
|
if (ret) lprintf("TexScreenLinear failed\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SetupMatrices();
|
||||||
|
|
||||||
|
MakeVertexList();
|
||||||
|
|
||||||
|
// Copy vertices in:
|
||||||
|
VertexBuffer->Lock(0,sizeof(VertexList),&lock,0);
|
||||||
|
if (lock==NULL) { lprintf("VertexBuffer->Lock failed\n"); return 1; }
|
||||||
|
memcpy(lock,VertexList,sizeof(VertexList));
|
||||||
|
VertexBuffer->Unlock();
|
||||||
|
|
||||||
|
Device->BeginScene();
|
||||||
|
Device->SetTexture(0,TexScreen);
|
||||||
|
Device->SetStreamSource(0,VertexBuffer,sizeof(CustomVertex));
|
||||||
|
Device->SetVertexShader(D3DFVF_CUSTOMVERTEX);
|
||||||
|
Device->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2);
|
||||||
|
Device->EndScene();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
15
platform/win32/direct.h
Normal file
15
platform/win32/direct.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int DirectInit(void);
|
||||||
|
void DirectExit(void);
|
||||||
|
|
||||||
|
int DirectScreen(const void *emu_screen);
|
||||||
|
int DirectClear(unsigned int colour);
|
||||||
|
int DirectPresent(void);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
165
platform/win32/dsnd.cpp
Normal file
165
platform/win32/dsnd.cpp
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
//#pragma warning (disable:4201)
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <mmsystem.h>
|
||||||
|
#include <dsound.h>
|
||||||
|
|
||||||
|
#include "dsnd.h"
|
||||||
|
#include "../common/lprintf.h"
|
||||||
|
|
||||||
|
#define NSEGS 4
|
||||||
|
#define RELEASE(x) if (x) x->Release(); x=NULL;
|
||||||
|
|
||||||
|
static LPDIRECTSOUND DSound;
|
||||||
|
static LPDIRECTSOUNDBUFFER LoopBuffer;
|
||||||
|
static LPDIRECTSOUNDNOTIFY DSoundNotify;
|
||||||
|
static HANDLE seg_played_event;
|
||||||
|
static int LoopLen, LoopWrite, LoopSeg; // bytes
|
||||||
|
|
||||||
|
static int LoopBlank(void)
|
||||||
|
{
|
||||||
|
void *mema=NULL,*memb=NULL;
|
||||||
|
DWORD sizea=0,sizeb=0;
|
||||||
|
|
||||||
|
LoopBuffer->Lock(0, LoopLen, &mema,&sizea, &memb,&sizeb, 0);
|
||||||
|
|
||||||
|
if (mema) memset(mema,0,sizea);
|
||||||
|
|
||||||
|
LoopBuffer->Unlock(mema,sizea, memb,sizeb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DSoundInit(HWND wnd_coop, int rate, int stereo, int seg_samples)
|
||||||
|
{
|
||||||
|
DSBUFFERDESC dsbd;
|
||||||
|
WAVEFORMATEX wfx;
|
||||||
|
DSBPOSITIONNOTIFY notifies[NSEGS];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(&dsbd,0,sizeof(dsbd));
|
||||||
|
memset(&wfx,0,sizeof(wfx));
|
||||||
|
|
||||||
|
// Make wave format:
|
||||||
|
wfx.wFormatTag=WAVE_FORMAT_PCM;
|
||||||
|
wfx.nChannels=stereo ? 2 : 1;
|
||||||
|
wfx.nSamplesPerSec=rate;
|
||||||
|
wfx.wBitsPerSample=16;
|
||||||
|
|
||||||
|
wfx.nBlockAlign=(WORD)((wfx.nChannels*wfx.wBitsPerSample)>>3);
|
||||||
|
wfx.nAvgBytesPerSec=wfx.nBlockAlign*wfx.nSamplesPerSec;
|
||||||
|
|
||||||
|
// Create the DirectSound interface:
|
||||||
|
DirectSoundCreate(NULL,&DSound,NULL);
|
||||||
|
if (DSound==NULL) return 1;
|
||||||
|
|
||||||
|
LoopSeg = seg_samples * 2;
|
||||||
|
if (stereo)
|
||||||
|
LoopSeg *= 2;
|
||||||
|
|
||||||
|
LoopLen = LoopSeg * NSEGS;
|
||||||
|
|
||||||
|
DSound->SetCooperativeLevel(wnd_coop, DSSCL_PRIORITY);
|
||||||
|
dsbd.dwFlags=DSBCAPS_GLOBALFOCUS; // Play in background
|
||||||
|
dsbd.dwFlags|=DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_CTRLPOSITIONNOTIFY;
|
||||||
|
|
||||||
|
// Create the looping buffer:
|
||||||
|
dsbd.dwSize=sizeof(dsbd);
|
||||||
|
dsbd.dwBufferBytes=LoopLen;
|
||||||
|
dsbd.lpwfxFormat=&wfx;
|
||||||
|
|
||||||
|
DSound->CreateSoundBuffer(&dsbd,&LoopBuffer,NULL);
|
||||||
|
if (LoopBuffer==NULL) return 1;
|
||||||
|
|
||||||
|
LoopBuffer->QueryInterface(IID_IDirectSoundNotify, (LPVOID*)&DSoundNotify);
|
||||||
|
if (DSoundNotify == NULL) {
|
||||||
|
lprintf("QueryInterface(IID_IDirectSoundNotify) failed\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg_played_event = CreateEvent(NULL, 0, 0, NULL);
|
||||||
|
if (seg_played_event == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
for (i = 0; i < NSEGS; i++) {
|
||||||
|
notifies[i].dwOffset = i * LoopSeg;
|
||||||
|
notifies[i].hEventNotify = seg_played_event;
|
||||||
|
}
|
||||||
|
i = DSoundNotify->SetNotificationPositions(NSEGS, notifies);
|
||||||
|
if (i != DS_OK) {
|
||||||
|
lprintf("SetNotificationPositions failed\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
LoopBlank();
|
||||||
|
LoopBuffer->Play(0, 0, DSBPLAY_LOOPING);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSoundExit(void)
|
||||||
|
{
|
||||||
|
if (LoopBuffer)
|
||||||
|
LoopBuffer->Stop();
|
||||||
|
RELEASE(DSoundNotify);
|
||||||
|
RELEASE(LoopBuffer)
|
||||||
|
RELEASE(DSound)
|
||||||
|
CloseHandle(seg_played_event);
|
||||||
|
seg_played_event = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int WriteSeg(const void *buff)
|
||||||
|
{
|
||||||
|
void *mema=NULL,*memb=NULL;
|
||||||
|
DWORD sizea=0,sizeb=0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
// Lock the segment at 'LoopWrite' and copy the next segment in
|
||||||
|
ret = LoopBuffer->Lock(LoopWrite, LoopSeg, &mema, &sizea, &memb, &sizeb, 0);
|
||||||
|
if (ret != DS_OK)
|
||||||
|
lprintf("LoopBuffer->Lock() failed: %i\n", ret);
|
||||||
|
|
||||||
|
if (mema) memcpy(mema,buff,sizea);
|
||||||
|
// if (memb) memcpy(memb,DSoundNext+sizea,sizeb);
|
||||||
|
if (sizeb != 0) lprintf("sizeb is not 0! (%i)\n", sizeb);
|
||||||
|
|
||||||
|
ret = LoopBuffer->Unlock(mema,sizea, memb, sizeb);
|
||||||
|
if (ret != DS_OK)
|
||||||
|
lprintf("LoopBuffer->Unlock() failed: %i\n", ret);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DSoundUpdate(const void *buff, int blocking)
|
||||||
|
{
|
||||||
|
DWORD play = 0;
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
LoopBuffer->GetCurrentPosition(&play, NULL);
|
||||||
|
pos = play;
|
||||||
|
|
||||||
|
// 'LoopWrite' is the next seg in the loop that we want to write
|
||||||
|
// First check that the sound 'play' pointer has moved out of it:
|
||||||
|
if (blocking) {
|
||||||
|
while (LoopWrite <= pos && pos < LoopWrite + LoopSeg) {
|
||||||
|
WaitForSingleObject(seg_played_event, 5000);
|
||||||
|
LoopBuffer->GetCurrentPosition(&play, NULL);
|
||||||
|
pos = play;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (LoopWrite <= pos && pos < LoopWrite + LoopSeg)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteSeg(buff);
|
||||||
|
|
||||||
|
// Advance LoopWrite to next seg:
|
||||||
|
LoopWrite += LoopSeg;
|
||||||
|
if (LoopWrite + LoopSeg > LoopLen)
|
||||||
|
LoopWrite = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
14
platform/win32/dsnd.h
Normal file
14
platform/win32/dsnd.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int DSoundInit(HWND wnd_coop, int rate, int stereo, int seg_samples);
|
||||||
|
void DSoundExit(void);
|
||||||
|
int DSoundUpdate(const void *buff, int blocking);
|
||||||
|
|
||||||
|
extern short *DSoundNext;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
273
platform/win32/in_vk.c
Normal file
273
platform/win32/in_vk.c
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
#define RC_INVOKED // we only need defines
|
||||||
|
#include <winuser.h>
|
||||||
|
#undef RC_INVOKED
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../common/input.h"
|
||||||
|
#include "../common/emu.h" // array_size
|
||||||
|
#include "in_vk.h"
|
||||||
|
|
||||||
|
#define IN_VK_PREFIX "vk:"
|
||||||
|
#define IN_VK_NKEYS 0x100
|
||||||
|
|
||||||
|
static const char * const in_vk_prefix = IN_VK_PREFIX;
|
||||||
|
static const char * const in_vk_keys[IN_VK_NKEYS] = {
|
||||||
|
[0 ... (IN_VK_NKEYS - 1)] = NULL,
|
||||||
|
[VK_LBUTTON] = "LBUTTON", [VK_RBUTTON] = "RBUTTON",
|
||||||
|
[VK_TAB] = "TAB", [VK_RETURN] = "RETURN",
|
||||||
|
[VK_SHIFT] = "SHIFT", [VK_CONTROL] = "CONTROL",
|
||||||
|
[VK_LEFT] = "LEFT", [VK_UP] = "UP",
|
||||||
|
[VK_RIGHT] = "RIGHT", [VK_DOWN] = "DOWN",
|
||||||
|
[VK_SPACE] = "SPACE",
|
||||||
|
};
|
||||||
|
|
||||||
|
// additional player12 keys
|
||||||
|
int in_vk_add_pl12;
|
||||||
|
|
||||||
|
// up to 4, keyboards rarely allow more
|
||||||
|
static int in_vk_keys_down[4];
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define VK_END 35
|
||||||
|
#define VK_HOME 36
|
||||||
|
#define VK_INSERT 45
|
||||||
|
#define VK_DELETE 46
|
||||||
|
#define VK_NUMPAD0 0x60
|
||||||
|
#define VK_NUMPAD1 0x61
|
||||||
|
#define VK_NUMPAD2 0x62
|
||||||
|
#define VK_NUMPAD3 0x63
|
||||||
|
#define VK_NUMPAD4 0x64
|
||||||
|
#define VK_NUMPAD5 0x65
|
||||||
|
#define VK_NUMPAD6 0x66
|
||||||
|
#define VK_NUMPAD7 0x67
|
||||||
|
#define VK_NUMPAD8 0x68
|
||||||
|
#define VK_NUMPAD9 0x69
|
||||||
|
#define VK_MULTIPLY 0x6A
|
||||||
|
#define VK_ADD 0x6B
|
||||||
|
#define VK_SEPARATOR 0x6C
|
||||||
|
#define VK_SUBTRACT 0x6D
|
||||||
|
#define VK_DECIMAL 0x6E
|
||||||
|
#define VK_DIVIDE 0x6F
|
||||||
|
#define VK_F1 0x70
|
||||||
|
#define VK_F2 0x71
|
||||||
|
#define VK_F3 0x72
|
||||||
|
#define VK_F4 0x73
|
||||||
|
#define VK_F5 0x74
|
||||||
|
#define VK_F6 0x75
|
||||||
|
#define VK_F7 0x76
|
||||||
|
#define VK_F8 0x77
|
||||||
|
#define VK_F9 0x78
|
||||||
|
#define VK_F10 0x79
|
||||||
|
#define VK_F11 0x7A
|
||||||
|
#define VK_F12 0x7B
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void in_vk_probe(void)
|
||||||
|
{
|
||||||
|
memset(in_vk_keys_down, 0, sizeof(in_vk_keys_down));
|
||||||
|
in_register(IN_VK_PREFIX "vk", IN_DRVID_VK, -1, (void *)1, IN_VK_NKEYS, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int in_vk_get_bind_count(void)
|
||||||
|
{
|
||||||
|
return IN_VK_NKEYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ORs result with pressed buttons */
|
||||||
|
int in_vk_update(void *drv_data, const int *binds, int *result)
|
||||||
|
{
|
||||||
|
int i, t, k;
|
||||||
|
|
||||||
|
for (i = 0; i < array_size(in_vk_keys_down); i++) {
|
||||||
|
k = in_vk_keys_down[i];
|
||||||
|
if (!k)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (t = 0; t < IN_BINDTYPE_COUNT; t++)
|
||||||
|
result[t] |= binds[IN_BIND_OFFS(k, t)];
|
||||||
|
}
|
||||||
|
|
||||||
|
result[IN_BINDTYPE_PLAYER12] |= in_vk_add_pl12;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void in_vk_keydown(int kc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// search
|
||||||
|
for (i = 0; i < array_size(in_vk_keys_down); i++)
|
||||||
|
if (in_vk_keys_down[i] == kc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// do
|
||||||
|
for (i = 0; i < array_size(in_vk_keys_down); i++) {
|
||||||
|
if (in_vk_keys_down[i] == 0) {
|
||||||
|
in_vk_keys_down[i] = kc;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void in_vk_keyup(int kc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < array_size(in_vk_keys_down); i++)
|
||||||
|
if (in_vk_keys_down[i] == kc)
|
||||||
|
in_vk_keys_down[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int in_vk_update_keycode(void *data, int *is_down)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
short key;
|
||||||
|
short pbtn;
|
||||||
|
} key_pbtn_map[] =
|
||||||
|
{
|
||||||
|
{ VK_UP, PBTN_UP },
|
||||||
|
{ VK_DOWN, PBTN_DOWN },
|
||||||
|
{ VK_LEFT, PBTN_LEFT },
|
||||||
|
{ VK_RIGHT, PBTN_RIGHT },
|
||||||
|
{ VK_RETURN, PBTN_MOK },
|
||||||
|
/*
|
||||||
|
{ BTN_X, PBTN_MBACK },
|
||||||
|
{ BTN_A, PBTN_MA2 },
|
||||||
|
{ BTN_Y, PBTN_MA3 },
|
||||||
|
{ BTN_L, PBTN_L },
|
||||||
|
{ BTN_R, PBTN_R },
|
||||||
|
{ BTN_SELECT, PBTN_MENU },
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
#define KEY_PBTN_MAP_SIZE (sizeof(key_pbtn_map) / sizeof(key_pbtn_map[0]))
|
||||||
|
|
||||||
|
static int in_vk_menu_translate(int keycode)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (keycode < 0)
|
||||||
|
{
|
||||||
|
/* menu -> kc */
|
||||||
|
keycode = -keycode;
|
||||||
|
for (i = 0; i < KEY_PBTN_MAP_SIZE; i++)
|
||||||
|
if (key_pbtn_map[i].pbtn == keycode)
|
||||||
|
return key_pbtn_map[i].key;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < KEY_PBTN_MAP_SIZE; i++)
|
||||||
|
if (key_pbtn_map[i].key == keycode)
|
||||||
|
return key_pbtn_map[i].pbtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int in_vk_get_key_code(const char *key_name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (key_name[1] == 0 && 'A' <= key_name[0] && key_name[0] <= 'Z')
|
||||||
|
return key_name[0];
|
||||||
|
|
||||||
|
for (i = 0; i < IN_VK_NKEYS; i++) {
|
||||||
|
const char *k = in_vk_keys[i];
|
||||||
|
if (k != NULL && strcasecmp(k, key_name) == 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *in_vk_get_key_name(int keycode)
|
||||||
|
{
|
||||||
|
const char *name = NULL;
|
||||||
|
static char buff[4];
|
||||||
|
|
||||||
|
if ('A' <= keycode && keycode < 'Z') {
|
||||||
|
buff[0] = keycode;
|
||||||
|
buff[1] = 0;
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 <= keycode && keycode < IN_VK_NKEYS)
|
||||||
|
name = in_vk_keys[keycode];
|
||||||
|
if (name == NULL)
|
||||||
|
name = "Unkn";
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
short code;
|
||||||
|
char btype;
|
||||||
|
char bit;
|
||||||
|
} in_vk_def_binds[] =
|
||||||
|
{
|
||||||
|
/* MXYZ SACB RLDU */
|
||||||
|
{ VK_UP, IN_BINDTYPE_PLAYER12, 0 },
|
||||||
|
{ VK_DOWN, IN_BINDTYPE_PLAYER12, 1 },
|
||||||
|
{ VK_LEFT, IN_BINDTYPE_PLAYER12, 2 },
|
||||||
|
{ VK_RIGHT, IN_BINDTYPE_PLAYER12, 3 },
|
||||||
|
{ 'S', IN_BINDTYPE_PLAYER12, 4 }, /* B */
|
||||||
|
{ 'D', IN_BINDTYPE_PLAYER12, 5 }, /* C */
|
||||||
|
{ 'A', IN_BINDTYPE_PLAYER12, 6 }, /* A */
|
||||||
|
{ VK_RETURN, IN_BINDTYPE_PLAYER12, 7 },
|
||||||
|
/*
|
||||||
|
{ BTN_SELECT, IN_BINDTYPE_EMU, PEVB_MENU },
|
||||||
|
// { BTN_Y, IN_BINDTYPE_EMU, PEVB_SWITCH_RND },
|
||||||
|
{ BTN_L, IN_BINDTYPE_EMU, PEVB_STATE_SAVE },
|
||||||
|
{ BTN_R, IN_BINDTYPE_EMU, PEVB_STATE_LOAD },
|
||||||
|
{ BTN_VOL_UP, IN_BINDTYPE_EMU, PEVB_VOL_UP },
|
||||||
|
{ BTN_VOL_DOWN, IN_BINDTYPE_EMU, PEVB_VOL_DOWN },
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEF_BIND_COUNT (sizeof(in_vk_def_binds) / sizeof(in_vk_def_binds[0]))
|
||||||
|
|
||||||
|
static void in_vk_get_def_binds(int *binds)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < DEF_BIND_COUNT; i++)
|
||||||
|
binds[IN_BIND_OFFS(in_vk_def_binds[i].code, in_vk_def_binds[i].btype)] =
|
||||||
|
1 << in_vk_def_binds[i].bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove binds of missing keys, count remaining ones */
|
||||||
|
static int in_vk_clean_binds(void *drv_data, int *binds, int *def_binds)
|
||||||
|
{
|
||||||
|
int i, count = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < IN_VK_NKEYS; i++) {
|
||||||
|
int t, offs;
|
||||||
|
for (t = 0; t < IN_BINDTYPE_COUNT; t++) {
|
||||||
|
offs = IN_BIND_OFFS(i, t);
|
||||||
|
if (strcmp(in_vk_get_key_name(i), "Unkn") == 0)
|
||||||
|
binds[offs] = def_binds[offs] = 0;
|
||||||
|
if (binds[offs])
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void in_vk_init(void *vdrv)
|
||||||
|
{
|
||||||
|
in_drv_t *drv = vdrv;
|
||||||
|
|
||||||
|
drv->prefix = in_vk_prefix;
|
||||||
|
drv->probe = in_vk_probe;
|
||||||
|
drv->get_bind_count = in_vk_get_bind_count;
|
||||||
|
drv->get_def_binds = in_vk_get_def_binds;
|
||||||
|
drv->clean_binds = in_vk_clean_binds;
|
||||||
|
drv->menu_translate = in_vk_menu_translate;
|
||||||
|
drv->get_key_code = in_vk_get_key_code;
|
||||||
|
drv->get_key_name = in_vk_get_key_name;
|
||||||
|
drv->update_keycode = in_vk_update_keycode;
|
||||||
|
}
|
||||||
|
|
16
platform/win32/in_vk.h
Normal file
16
platform/win32/in_vk.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifdef IN_VK
|
||||||
|
|
||||||
|
void in_vk_init(void *vdrv);
|
||||||
|
int in_vk_update(void *drv_data, const int *binds, int *result);
|
||||||
|
|
||||||
|
void in_vk_keydown(int kc);
|
||||||
|
void in_vk_keyup(int kc);
|
||||||
|
|
||||||
|
extern int in_vk_add_pl12;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define in_vk_init(x)
|
||||||
|
#define in_vk_update(a,b,c) 0
|
||||||
|
|
||||||
|
#endif
|
635
platform/win32/main.c
Normal file
635
platform/win32/main.c
Normal file
|
@ -0,0 +1,635 @@
|
||||||
|
#include <windows.h>
|
||||||
|
#include <commdlg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "../../pico/pico.h"
|
||||||
|
#include "../common/readpng.h"
|
||||||
|
#include "../common/config.h"
|
||||||
|
#include "../common/lprintf.h"
|
||||||
|
#include "../common/emu.h"
|
||||||
|
#include "../common/menu.h"
|
||||||
|
#include "../common/input.h"
|
||||||
|
#include "../common/plat.h"
|
||||||
|
#include "version.h"
|
||||||
|
#include "direct.h"
|
||||||
|
#include "in_vk.h"
|
||||||
|
|
||||||
|
char *romname=NULL;
|
||||||
|
HWND FrameWnd=NULL;
|
||||||
|
RECT FrameRectMy;
|
||||||
|
RECT EmuScreenRect = { 0, 0, 320, 224 };
|
||||||
|
int lock_to_1_1 = 1;
|
||||||
|
static HWND PicoSwWnd=NULL, PicoPadWnd=NULL;
|
||||||
|
|
||||||
|
static HMENU mmain = 0, mdisplay = 0, mpicohw = 0;
|
||||||
|
static HBITMAP ppad_bmp = 0;
|
||||||
|
static HBITMAP ppage_bmps[7] = { 0, };
|
||||||
|
static char rom_name[0x20*3+1];
|
||||||
|
static int main_wnd_as_pad = 0;
|
||||||
|
|
||||||
|
static HANDLE loop_enter_event, loop_end_event;
|
||||||
|
|
||||||
|
void error(char *text)
|
||||||
|
{
|
||||||
|
MessageBox(FrameWnd, text, "Error", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void UpdateRect(void)
|
||||||
|
{
|
||||||
|
WINDOWINFO wi;
|
||||||
|
memset(&wi, 0, sizeof(wi));
|
||||||
|
wi.cbSize = sizeof(wi);
|
||||||
|
GetWindowInfo(FrameWnd, &wi);
|
||||||
|
FrameRectMy = wi.rcClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int extract_rom_name(char *dest, const unsigned char *src, int len)
|
||||||
|
{
|
||||||
|
char *p = dest, s_old = 0x20;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = len - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (src[i^1] != ' ') break;
|
||||||
|
}
|
||||||
|
len = i + 1;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
unsigned char s = src[i^1];
|
||||||
|
if (s == 0x20 && s_old == 0x20) continue;
|
||||||
|
else if (s >= 0x20 && s < 0x7f && s != '%')
|
||||||
|
{
|
||||||
|
*p++ = s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprintf(p, "%%%02x", s);
|
||||||
|
p += 3;
|
||||||
|
}
|
||||||
|
s_old = s;
|
||||||
|
}
|
||||||
|
*p = 0;
|
||||||
|
|
||||||
|
return p - dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_name_alias(const char *afname)
|
||||||
|
{
|
||||||
|
char buff[256], *var, *val;
|
||||||
|
FILE *f;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
f = fopen(afname, "r");
|
||||||
|
if (f == NULL) return;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
ret = config_get_var_val(f, buff, sizeof(buff), &var, &val);
|
||||||
|
if (ret == 0) break;
|
||||||
|
if (ret == -1) continue;
|
||||||
|
|
||||||
|
if (strcmp(rom_name, var) == 0) {
|
||||||
|
lprintf("rom aliased: \"%s\" -> \"%s\"\n", rom_name, val);
|
||||||
|
strncpy(rom_name, val, sizeof(rom_name));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HBITMAP png2hb(const char *fname, int is_480)
|
||||||
|
{
|
||||||
|
BITMAPINFOHEADER bih;
|
||||||
|
HBITMAP bmp;
|
||||||
|
void *bmem;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
bmem = calloc(1, is_480 ? 480*240*3 : 320*240*3);
|
||||||
|
if (bmem == NULL) return NULL;
|
||||||
|
ret = readpng(bmem, fname, is_480 ? READPNG_480_24 : READPNG_320_24);
|
||||||
|
if (ret != 0) {
|
||||||
|
free(bmem);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&bih, 0, sizeof(bih));
|
||||||
|
bih.biSize = sizeof(bih);
|
||||||
|
bih.biWidth = is_480 ? 480 : 320;
|
||||||
|
bih.biHeight = -240;
|
||||||
|
bih.biPlanes = 1;
|
||||||
|
bih.biBitCount = 24;
|
||||||
|
bih.biCompression = BI_RGB;
|
||||||
|
bmp = CreateDIBitmap(GetDC(FrameWnd), &bih, CBM_INIT, bmem, (BITMAPINFO *)&bih, 0);
|
||||||
|
if (bmp == NULL)
|
||||||
|
lprintf("CreateDIBitmap failed with %i", GetLastError());
|
||||||
|
|
||||||
|
free(bmem);
|
||||||
|
return bmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PrepareForROM(void)
|
||||||
|
{
|
||||||
|
unsigned char *rom_data = NULL;
|
||||||
|
int i, ret, show = PicoAHW & PAHW_PICO;
|
||||||
|
|
||||||
|
PicoGetInternal(PI_ROM, (pint_ret_t *) &rom_data);
|
||||||
|
EnableMenuItem(mmain, 2, MF_BYPOSITION|(show ? MF_ENABLED : MF_GRAYED));
|
||||||
|
ShowWindow(PicoPadWnd, show ? SW_SHOWNA : SW_HIDE);
|
||||||
|
ShowWindow(PicoSwWnd, show ? SW_SHOWNA : SW_HIDE);
|
||||||
|
CheckMenuItem(mpicohw, 1210, show ? MF_CHECKED : MF_UNCHECKED);
|
||||||
|
CheckMenuItem(mpicohw, 1211, show ? MF_CHECKED : MF_UNCHECKED);
|
||||||
|
PostMessage(FrameWnd, WM_COMMAND, 1220 + PicoPicohw.page, 0);
|
||||||
|
DrawMenuBar(FrameWnd);
|
||||||
|
InvalidateRect(PicoSwWnd, NULL, 1);
|
||||||
|
|
||||||
|
PicoPicohw.pen_pos[0] =
|
||||||
|
PicoPicohw.pen_pos[1] = 0x8000;
|
||||||
|
in_vk_add_pl12 = 0;
|
||||||
|
|
||||||
|
ret = extract_rom_name(rom_name, rom_data + 0x150, 0x20);
|
||||||
|
if (ret == 0)
|
||||||
|
extract_rom_name(rom_name, rom_data + 0x130, 0x20);
|
||||||
|
|
||||||
|
if (show)
|
||||||
|
{
|
||||||
|
char path[MAX_PATH], *p;
|
||||||
|
GetModuleFileName(NULL, path, sizeof(path) - 32);
|
||||||
|
p = strrchr(path, '\\');
|
||||||
|
if (p == NULL) p = path;
|
||||||
|
else p++;
|
||||||
|
if (ppad_bmp == NULL) {
|
||||||
|
strcpy(p, "pico\\pad.png");
|
||||||
|
ppad_bmp = png2hb(path, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(p, "pico\\alias.txt");
|
||||||
|
check_name_alias(path);
|
||||||
|
|
||||||
|
for (i = 0; i < 7; i++) {
|
||||||
|
if (ppage_bmps[i] != NULL) DeleteObject(ppage_bmps[i]);
|
||||||
|
sprintf(p, "pico\\%s_%i.png", rom_name, i);
|
||||||
|
ppage_bmps[i] = png2hb(path, 1);
|
||||||
|
}
|
||||||
|
// games usually don't have page 6, so just duplicate page 5.
|
||||||
|
if (ppage_bmps[6] == NULL && ppage_bmps[5] != NULL) {
|
||||||
|
sprintf(p, "pico\\%s_5.png", rom_name);
|
||||||
|
ppage_bmps[6] = png2hb(path, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LoadROM(const char *cmdpath)
|
||||||
|
{
|
||||||
|
char rompath[MAX_PATH];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (cmdpath != NULL && strlen(cmdpath)) {
|
||||||
|
strcpy(rompath, cmdpath + (cmdpath[0] == '\"' ? 1 : 0));
|
||||||
|
if (rompath[strlen(rompath)-1] == '\"')
|
||||||
|
rompath[strlen(rompath)-1] = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
OPENFILENAME of; ZeroMemory(&of, sizeof(of));
|
||||||
|
rompath[sizeof(rompath) - 1] = 0;
|
||||||
|
strncpy(rompath, rom_fname_loaded, sizeof(rompath) - 1);
|
||||||
|
of.lStructSize = sizeof(of);
|
||||||
|
of.lpstrFilter = "ROMs, CD images\0*.smd;*.bin;*.gen;*.zip;*.32x;*.sms;*.iso;*.cso;*.cue\0"
|
||||||
|
"whatever\0*.*\0";
|
||||||
|
of.lpstrFile = rompath;
|
||||||
|
of.nMaxFile = MAX_PATH;
|
||||||
|
of.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
|
||||||
|
of.hwndOwner = FrameWnd;
|
||||||
|
if (!GetOpenFileName(&of))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (engineState == PGS_Running) {
|
||||||
|
engineState = PGS_Paused;
|
||||||
|
WaitForSingleObject(loop_end_event, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = emu_reload_rom(rompath);
|
||||||
|
if (ret == 0) {
|
||||||
|
extern char menu_error_msg[]; // HACK..
|
||||||
|
error(menu_error_msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrepareForROM();
|
||||||
|
engineState = PGS_Running;
|
||||||
|
SetEvent(loop_enter_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int rect_widths[4] = { 320, 256, 640, 512 };
|
||||||
|
static const int rect_heights[4] = { 224, 224, 448, 448 };
|
||||||
|
|
||||||
|
// Window proc for the frame window:
|
||||||
|
static LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
|
||||||
|
{
|
||||||
|
POINT pt;
|
||||||
|
RECT rc;
|
||||||
|
int i;
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_CLOSE:
|
||||||
|
PostQuitMessage(0);
|
||||||
|
return 0;
|
||||||
|
case WM_DESTROY:
|
||||||
|
FrameWnd = NULL; // Blank the handle
|
||||||
|
break;
|
||||||
|
case WM_SIZE:
|
||||||
|
case WM_MOVE:
|
||||||
|
case WM_SIZING:
|
||||||
|
UpdateRect();
|
||||||
|
if (lock_to_1_1 && FrameRectMy.right - FrameRectMy.left != 0 &&
|
||||||
|
(FrameRectMy.right - FrameRectMy.left != EmuScreenRect.right - EmuScreenRect.left ||
|
||||||
|
FrameRectMy.bottom - FrameRectMy.top != EmuScreenRect.bottom - EmuScreenRect.top)) {
|
||||||
|
lock_to_1_1 = 0;
|
||||||
|
CheckMenuItem(mdisplay, 1104, MF_UNCHECKED);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_COMMAND:
|
||||||
|
switch (LOWORD(wparam))
|
||||||
|
{
|
||||||
|
case 1000:
|
||||||
|
LoadROM(NULL);
|
||||||
|
break;
|
||||||
|
case 1001:
|
||||||
|
emu_reset_game();
|
||||||
|
return 0;
|
||||||
|
case 1002:
|
||||||
|
PostQuitMessage(0);
|
||||||
|
return 0;
|
||||||
|
case 1100:
|
||||||
|
case 1101:
|
||||||
|
case 1102:
|
||||||
|
case 1103:
|
||||||
|
// LoopWait=1; // another sync hack
|
||||||
|
// for (i = 0; !LoopWaiting && i < 10; i++) Sleep(10);
|
||||||
|
FrameRectMy.right = FrameRectMy.left + rect_widths[wparam&3];
|
||||||
|
FrameRectMy.bottom = FrameRectMy.top + rect_heights[wparam&3];
|
||||||
|
AdjustWindowRect(&FrameRectMy, WS_OVERLAPPEDWINDOW, 1);
|
||||||
|
MoveWindow(hwnd, FrameRectMy.left, FrameRectMy.top,
|
||||||
|
FrameRectMy.right-FrameRectMy.left, FrameRectMy.bottom-FrameRectMy.top, 1);
|
||||||
|
UpdateRect();
|
||||||
|
lock_to_1_1 = 0;
|
||||||
|
CheckMenuItem(mdisplay, 1104, MF_UNCHECKED);
|
||||||
|
// if (rom_loaded) LoopWait=0;
|
||||||
|
return 0;
|
||||||
|
case 1104:
|
||||||
|
lock_to_1_1 = !lock_to_1_1;
|
||||||
|
CheckMenuItem(mdisplay, 1104, lock_to_1_1 ? MF_CHECKED : MF_UNCHECKED);
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 2000: // EmuScreenRect/FrameRectMy sync request
|
||||||
|
if (!lock_to_1_1)
|
||||||
|
return 0;
|
||||||
|
FrameRectMy.right = FrameRectMy.left + (EmuScreenRect.right - EmuScreenRect.left);
|
||||||
|
FrameRectMy.bottom = FrameRectMy.top + (EmuScreenRect.bottom - EmuScreenRect.top);
|
||||||
|
AdjustWindowRect(&FrameRectMy, WS_OVERLAPPEDWINDOW, 1);
|
||||||
|
MoveWindow(hwnd, FrameRectMy.left, FrameRectMy.top,
|
||||||
|
FrameRectMy.right-FrameRectMy.left, FrameRectMy.bottom-FrameRectMy.top, 1);
|
||||||
|
UpdateRect();
|
||||||
|
return 0;
|
||||||
|
case 1210:
|
||||||
|
case 1211:
|
||||||
|
i = IsWindowVisible((LOWORD(wparam)&1) ? PicoPadWnd : PicoSwWnd);
|
||||||
|
i = !i;
|
||||||
|
ShowWindow((LOWORD(wparam)&1) ? PicoPadWnd : PicoSwWnd, i ? SW_SHOWNA : SW_HIDE);
|
||||||
|
CheckMenuItem(mpicohw, LOWORD(wparam), i ? MF_CHECKED : MF_UNCHECKED);
|
||||||
|
return 0;
|
||||||
|
case 1212:
|
||||||
|
main_wnd_as_pad = !main_wnd_as_pad;
|
||||||
|
CheckMenuItem(mpicohw, 1212, main_wnd_as_pad ? MF_CHECKED : MF_UNCHECKED);
|
||||||
|
return 0;
|
||||||
|
case 1220:
|
||||||
|
case 1221:
|
||||||
|
case 1222:
|
||||||
|
case 1223:
|
||||||
|
case 1224:
|
||||||
|
case 1225:
|
||||||
|
case 1226:
|
||||||
|
PicoPicohw.page = LOWORD(wparam) % 10;
|
||||||
|
for (i = 0; i < 7; i++)
|
||||||
|
CheckMenuItem(mpicohw, 1220 + i, MF_UNCHECKED);
|
||||||
|
CheckMenuItem(mpicohw, 1220 + PicoPicohw.page, MF_CHECKED);
|
||||||
|
InvalidateRect(PicoSwWnd, NULL, 1);
|
||||||
|
return 0;
|
||||||
|
case 1300:
|
||||||
|
MessageBox(FrameWnd, plat_get_credits(), "About", 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_TIMER:
|
||||||
|
GetCursorPos(&pt);
|
||||||
|
GetWindowRect(PicoSwWnd, &rc);
|
||||||
|
if (PtInRect(&rc, pt)) break;
|
||||||
|
GetWindowRect(PicoPadWnd, &rc);
|
||||||
|
if (PtInRect(&rc, pt)) break;
|
||||||
|
PicoPicohw.pen_pos[0] |= 0x8000;
|
||||||
|
PicoPicohw.pen_pos[1] |= 0x8000;
|
||||||
|
in_vk_add_pl12 = 0;
|
||||||
|
break;
|
||||||
|
case WM_LBUTTONDOWN: in_vk_add_pl12 |= 0x20; return 0;
|
||||||
|
case WM_LBUTTONUP: in_vk_add_pl12 &= ~0x20; return 0;
|
||||||
|
case WM_MOUSEMOVE:
|
||||||
|
if (!main_wnd_as_pad) break;
|
||||||
|
PicoPicohw.pen_pos[0] = 0x03c + (320 * LOWORD(lparam) / (FrameRectMy.right - FrameRectMy.left));
|
||||||
|
PicoPicohw.pen_pos[1] = 0x1fc + (232 * HIWORD(lparam) / (FrameRectMy.bottom - FrameRectMy.top));
|
||||||
|
SetTimer(FrameWnd, 100, 1000, NULL);
|
||||||
|
break;
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
if (wparam == VK_TAB) {
|
||||||
|
emu_reset_game();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (wparam == VK_ESCAPE) {
|
||||||
|
LoadROM(NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
in_vk_keydown(wparam);
|
||||||
|
break;
|
||||||
|
case WM_KEYUP:
|
||||||
|
in_vk_keyup(wparam);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DefWindowProc(hwnd,msg,wparam,lparam);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LRESULT CALLBACK PicoSwWndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
|
||||||
|
{
|
||||||
|
PAINTSTRUCT ps;
|
||||||
|
HDC hdc, hdc2;
|
||||||
|
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_DESTROY: PicoSwWnd=NULL; break;
|
||||||
|
case WM_LBUTTONDOWN: in_vk_add_pl12 |= 0x20; return 0;
|
||||||
|
case WM_LBUTTONUP: in_vk_add_pl12 &= ~0x20; return 0;
|
||||||
|
case WM_MOUSEMOVE:
|
||||||
|
if (HIWORD(lparam) < 0x20) break;
|
||||||
|
PicoPicohw.pen_pos[0] = 0x03c + LOWORD(lparam) * 2/3;
|
||||||
|
PicoPicohw.pen_pos[1] = 0x2f8 + HIWORD(lparam) - 0x20;
|
||||||
|
SetTimer(FrameWnd, 100, 1000, NULL);
|
||||||
|
break;
|
||||||
|
case WM_KEYDOWN: in_vk_keydown(wparam); break;
|
||||||
|
case WM_KEYUP: in_vk_keyup(wparam); break;
|
||||||
|
case WM_PAINT:
|
||||||
|
hdc = BeginPaint(hwnd, &ps);
|
||||||
|
if (ppage_bmps[PicoPicohw.page] == NULL)
|
||||||
|
{
|
||||||
|
SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
|
||||||
|
SetTextColor(hdc, RGB(255, 255, 255));
|
||||||
|
SetBkColor(hdc, RGB(0, 0, 0));
|
||||||
|
TextOut(hdc, 2, 2, "missing PNGs for", 16);
|
||||||
|
TextOut(hdc, 2, 18, rom_name, strlen(rom_name));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hdc2 = CreateCompatibleDC(GetDC(FrameWnd));
|
||||||
|
SelectObject(hdc2, ppage_bmps[PicoPicohw.page]);
|
||||||
|
BitBlt(hdc, 0, 0, 480, 240, hdc2, 0, 0, SRCCOPY);
|
||||||
|
DeleteDC(hdc2);
|
||||||
|
}
|
||||||
|
EndPaint(hwnd, &ps);
|
||||||
|
return 0;
|
||||||
|
case WM_CLOSE:
|
||||||
|
ShowWindow(hwnd, SW_HIDE);
|
||||||
|
CheckMenuItem(mpicohw, 1210, MF_UNCHECKED);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DefWindowProc(hwnd,msg,wparam,lparam);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LRESULT CALLBACK PicoPadWndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
|
||||||
|
{
|
||||||
|
PAINTSTRUCT ps;
|
||||||
|
HDC hdc, hdc2;
|
||||||
|
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_DESTROY: PicoPadWnd=NULL; break;
|
||||||
|
case WM_LBUTTONDOWN: in_vk_add_pl12 |= 0x20; return 0;
|
||||||
|
case WM_LBUTTONUP: in_vk_add_pl12 &= ~0x20; return 0;
|
||||||
|
case WM_MOUSEMOVE:
|
||||||
|
PicoPicohw.pen_pos[0] = 0x03c + LOWORD(lparam);
|
||||||
|
PicoPicohw.pen_pos[1] = 0x1fc + HIWORD(lparam);
|
||||||
|
SetTimer(FrameWnd, 100, 1000, NULL);
|
||||||
|
break;
|
||||||
|
case WM_KEYDOWN: in_vk_keydown(wparam); break;
|
||||||
|
case WM_KEYUP: in_vk_keyup(wparam); break;
|
||||||
|
case WM_PAINT:
|
||||||
|
if (ppad_bmp == NULL) break;
|
||||||
|
hdc = BeginPaint(hwnd, &ps);
|
||||||
|
hdc2 = CreateCompatibleDC(GetDC(FrameWnd));
|
||||||
|
SelectObject(hdc2, ppad_bmp);
|
||||||
|
BitBlt(hdc, 0, 0, 320, 240, hdc2, 0, 0, SRCCOPY);
|
||||||
|
EndPaint(hwnd, &ps);
|
||||||
|
DeleteDC(hdc2);
|
||||||
|
return 0;
|
||||||
|
case WM_CLOSE:
|
||||||
|
ShowWindow(hwnd, SW_HIDE);
|
||||||
|
CheckMenuItem(mpicohw, 1211, MF_UNCHECKED);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DefWindowProc(hwnd,msg,wparam,lparam);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int FrameInit()
|
||||||
|
{
|
||||||
|
WNDCLASS wc;
|
||||||
|
RECT rect={0,0,0,0};
|
||||||
|
HMENU mfile;
|
||||||
|
int style=0;
|
||||||
|
int left=0,top=0,width=0,height=0;
|
||||||
|
|
||||||
|
memset(&wc,0,sizeof(wc));
|
||||||
|
|
||||||
|
// Register the window class:
|
||||||
|
wc.lpfnWndProc=WndProc;
|
||||||
|
wc.hInstance=GetModuleHandle(NULL);
|
||||||
|
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
|
||||||
|
wc.hbrBackground=CreateSolidBrush(0);
|
||||||
|
wc.lpszClassName="PicoMainFrame";
|
||||||
|
RegisterClass(&wc);
|
||||||
|
|
||||||
|
wc.lpszClassName="PicoSwWnd";
|
||||||
|
wc.lpfnWndProc=PicoSwWndProc;
|
||||||
|
RegisterClass(&wc);
|
||||||
|
|
||||||
|
wc.lpszClassName="PicoPadWnd";
|
||||||
|
wc.lpfnWndProc=PicoPadWndProc;
|
||||||
|
RegisterClass(&wc);
|
||||||
|
|
||||||
|
rect.right =320;
|
||||||
|
rect.bottom=224;
|
||||||
|
|
||||||
|
// Adjust size of windows based on borders:
|
||||||
|
style=WS_OVERLAPPEDWINDOW;
|
||||||
|
AdjustWindowRect(&rect,style,1);
|
||||||
|
width =rect.right-rect.left;
|
||||||
|
height=rect.bottom-rect.top;
|
||||||
|
|
||||||
|
// Place window in the centre of the screen:
|
||||||
|
SystemParametersInfo(SPI_GETWORKAREA,0,&rect,0);
|
||||||
|
left=rect.left+rect.right;
|
||||||
|
top=rect.top+rect.bottom;
|
||||||
|
|
||||||
|
left-=width; left>>=1;
|
||||||
|
top-=height; top>>=1;
|
||||||
|
|
||||||
|
// Create menu:
|
||||||
|
mfile = CreateMenu();
|
||||||
|
InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1000, "&Load ROM");
|
||||||
|
InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1001, "&Reset");
|
||||||
|
InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1002, "E&xit");
|
||||||
|
mdisplay = CreateMenu();
|
||||||
|
InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1100, "320x224");
|
||||||
|
InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1101, "256x224");
|
||||||
|
InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1102, "640x448");
|
||||||
|
InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1103, "512x448");
|
||||||
|
InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1104, "Lock to 1:1");
|
||||||
|
mpicohw = CreateMenu();
|
||||||
|
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1210, "Show &Storyware");
|
||||||
|
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1211, "Show &Drawing pad");
|
||||||
|
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1212, "&Main window as pad");
|
||||||
|
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL);
|
||||||
|
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1220, "Title page (&0)");
|
||||||
|
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1221, "Page &1");
|
||||||
|
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1222, "Page &2");
|
||||||
|
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1223, "Page &3");
|
||||||
|
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1224, "Page &4");
|
||||||
|
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1225, "Page &5");
|
||||||
|
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1226, "Page &6");
|
||||||
|
mmain = CreateMenu();
|
||||||
|
InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mfile, "&File");
|
||||||
|
InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mdisplay, "&Display");
|
||||||
|
InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mpicohw, "&Pico");
|
||||||
|
EnableMenuItem(mmain, 2, MF_BYPOSITION|MF_GRAYED);
|
||||||
|
// InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, 1200, "&Config");
|
||||||
|
InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING, 1300, "&About");
|
||||||
|
|
||||||
|
// Create the window:
|
||||||
|
FrameWnd=CreateWindow("PicoMainFrame","PicoDrive " VERSION,style|WS_VISIBLE,
|
||||||
|
left,top,width,height,NULL,mmain,NULL,NULL);
|
||||||
|
|
||||||
|
CheckMenuItem(mdisplay, 1104, lock_to_1_1 ? MF_CHECKED : MF_UNCHECKED);
|
||||||
|
ShowWindow(FrameWnd, SW_NORMAL);
|
||||||
|
UpdateWindow(FrameWnd);
|
||||||
|
UpdateRect();
|
||||||
|
|
||||||
|
// create Pico windows
|
||||||
|
style = WS_OVERLAPPED|WS_CAPTION|WS_BORDER|WS_SYSMENU;
|
||||||
|
rect.left=rect.top=0;
|
||||||
|
rect.right =320;
|
||||||
|
rect.bottom=224;
|
||||||
|
|
||||||
|
AdjustWindowRect(&rect,style,1);
|
||||||
|
width =rect.right-rect.left;
|
||||||
|
height=rect.bottom-rect.top;
|
||||||
|
|
||||||
|
left += 326;
|
||||||
|
PicoSwWnd=CreateWindow("PicoSwWnd","Storyware",style,
|
||||||
|
left,top,width+160,height,FrameWnd,NULL,NULL,NULL);
|
||||||
|
|
||||||
|
top += 266;
|
||||||
|
PicoPadWnd=CreateWindow("PicoPadWnd","Drawing Pad",style,
|
||||||
|
left,top,width,height,FrameWnd,NULL,NULL,NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------
|
||||||
|
|
||||||
|
static DWORD WINAPI work_thread(void *x)
|
||||||
|
{
|
||||||
|
while (engineState != PGS_Quit) {
|
||||||
|
WaitForSingleObject(loop_enter_event, INFINITE);
|
||||||
|
if (engineState != PGS_Running)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
printf("loop..\n");
|
||||||
|
emu_loop();
|
||||||
|
SetEvent(loop_end_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: use main.c
|
||||||
|
void xxinit(void)
|
||||||
|
{
|
||||||
|
/* in_init() must go before config, config accesses in_ fwk */
|
||||||
|
in_init();
|
||||||
|
pemu_prep_defconfig();
|
||||||
|
emu_read_config(0, 0);
|
||||||
|
config_readlrom(PicoConfigFile);
|
||||||
|
|
||||||
|
plat_init();
|
||||||
|
in_probe();
|
||||||
|
|
||||||
|
emu_init();
|
||||||
|
menu_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int WINAPI WinMain(HINSTANCE p1, HINSTANCE p2, LPSTR cmdline, int p4)
|
||||||
|
{
|
||||||
|
MSG msg;
|
||||||
|
DWORD tid = 0;
|
||||||
|
HANDLE thread;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
xxinit();
|
||||||
|
FrameInit();
|
||||||
|
ret = DirectInit();
|
||||||
|
if (ret)
|
||||||
|
goto end0;
|
||||||
|
|
||||||
|
loop_enter_event = CreateEvent(NULL, 0, 0, NULL);
|
||||||
|
if (loop_enter_event == NULL)
|
||||||
|
goto end0;
|
||||||
|
|
||||||
|
loop_end_event = CreateEvent(NULL, 0, 0, NULL);
|
||||||
|
if (loop_end_event == NULL)
|
||||||
|
goto end0;
|
||||||
|
|
||||||
|
thread = CreateThread(NULL, 0, work_thread, NULL, 0, &tid);
|
||||||
|
if (thread == NULL)
|
||||||
|
goto end0;
|
||||||
|
|
||||||
|
LoadROM(cmdline);
|
||||||
|
|
||||||
|
// Main window loop:
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
GetMessage(&msg,NULL,0,0);
|
||||||
|
if (msg.message==WM_QUIT) break;
|
||||||
|
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal thread to quit and wait for it to exit:
|
||||||
|
if (engineState == PGS_Running) {
|
||||||
|
engineState = PGS_Quit;
|
||||||
|
WaitForSingleObject(loop_end_event, 5000);
|
||||||
|
}
|
||||||
|
CloseHandle(thread); thread=NULL;
|
||||||
|
|
||||||
|
emu_write_config(0);
|
||||||
|
emu_finish();
|
||||||
|
//plat_finish();
|
||||||
|
|
||||||
|
end0:
|
||||||
|
DirectExit();
|
||||||
|
DestroyWindow(FrameWnd);
|
||||||
|
|
||||||
|
// _CrtDumpMemoryLeaks();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
11
platform/win32/main.h
Normal file
11
platform/win32/main.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern HWND FrameWnd;
|
||||||
|
extern RECT FrameRectMy;
|
||||||
|
extern RECT EmuScreenRect;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
259
platform/win32/plat.c
Normal file
259
platform/win32/plat.c
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "../common/lprintf.h"
|
||||||
|
#include "../common/plat.h"
|
||||||
|
#include "../common/emu.h"
|
||||||
|
#include "../../pico/pico.h"
|
||||||
|
#include "version.h"
|
||||||
|
#include "direct.h"
|
||||||
|
#include "dsnd.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
static unsigned short screen_buff[320 * 240];
|
||||||
|
static unsigned char PicoDraw2FB_[(8+320) * (8+240+8)];
|
||||||
|
unsigned char *PicoDraw2FB = PicoDraw2FB_;
|
||||||
|
|
||||||
|
char cpu_clk_name[] = "unused";
|
||||||
|
|
||||||
|
void plat_init(void)
|
||||||
|
{
|
||||||
|
g_screen_ptr = (void *)screen_buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
int plat_is_dir(const char *path)
|
||||||
|
{
|
||||||
|
return (GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int plat_get_ticks_ms(void)
|
||||||
|
{
|
||||||
|
return GetTickCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int plat_get_ticks_us(void)
|
||||||
|
{
|
||||||
|
// XXX: maybe performance counters?
|
||||||
|
return GetTickCount() * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void plat_wait_till_us(unsigned int us)
|
||||||
|
{
|
||||||
|
int msdiff = (int)(us - plat_get_ticks_us()) / 1000;
|
||||||
|
if (msdiff > 6)
|
||||||
|
;// Sleep(msdiff - 6);
|
||||||
|
while (plat_get_ticks_us() < us)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void plat_sleep_ms(int ms)
|
||||||
|
{
|
||||||
|
Sleep(ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
int plat_wait_event(int *fds_hnds, int count, int timeout_ms)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pemu_prep_defconfig(void)
|
||||||
|
{
|
||||||
|
memset(&defaultConfig, 0, sizeof(defaultConfig));
|
||||||
|
defaultConfig.EmuOpt = 0x9d | EOPT_RAM_TIMINGS|EOPT_CONFIRM_SAVE|EOPT_EN_CD_LEDS;
|
||||||
|
defaultConfig.s_PicoOpt = POPT_EN_STEREO|POPT_EN_FM|POPT_EN_PSG|POPT_EN_Z80 |
|
||||||
|
POPT_EN_MCD_PCM|POPT_EN_MCD_CDDA|POPT_ACC_SPRITES |
|
||||||
|
POPT_EN_32X|POPT_EN_PWM;
|
||||||
|
defaultConfig.s_PicoOpt|= POPT_6BTN_PAD; // for xmen proto
|
||||||
|
defaultConfig.s_PsndRate = 44100;
|
||||||
|
defaultConfig.s_PicoRegion = 0; // auto
|
||||||
|
defaultConfig.s_PicoAutoRgnOrder = 0x184; // US, EU, JP
|
||||||
|
defaultConfig.s_PicoCDBuffers = 0;
|
||||||
|
defaultConfig.Frameskip = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int EmuScanBegin16(unsigned int num)
|
||||||
|
{
|
||||||
|
DrawLineDest = (unsigned short *) g_screen_ptr + g_screen_width * num;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pemu_loop_prep(void)
|
||||||
|
{
|
||||||
|
PicoDrawSetColorFormat(1);
|
||||||
|
PicoScanBegin = EmuScanBegin16;
|
||||||
|
pemu_sound_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pemu_loop_end(void)
|
||||||
|
{
|
||||||
|
pemu_sound_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pemu_forced_frame(int opts)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void pemu_update_display(const char *fps, const char *notice_msg)
|
||||||
|
{
|
||||||
|
DirectScreen(g_screen_ptr);
|
||||||
|
DirectPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void plat_video_wait_vsync(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void plat_video_toggle_renderer(int is_next, int force_16bpp, int is_menu)
|
||||||
|
{
|
||||||
|
// this will auto-select SMS/32X renderers
|
||||||
|
PicoDrawSetColorFormat(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emu_video_mode_change(int start_line, int line_count, int is_32cols)
|
||||||
|
{
|
||||||
|
EmuScreenRect.left = is_32cols ? 32 : 0;
|
||||||
|
EmuScreenRect.right = is_32cols ? 256+32 : 320;
|
||||||
|
EmuScreenRect.top = start_line;
|
||||||
|
EmuScreenRect.bottom = start_line + line_count;
|
||||||
|
|
||||||
|
PostMessage(FrameWnd, WM_COMMAND, 0x20000 | 2000, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sndbuff[2*44100/50/2 + 4];
|
||||||
|
|
||||||
|
static void update_sound(int len)
|
||||||
|
{
|
||||||
|
/* avoid writing audio when lagging behind to prevent audio lag */
|
||||||
|
if (PicoSkipFrame != 2)
|
||||||
|
DSoundUpdate(sndbuff, (currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pemu_sound_start(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
PsndOut = NULL;
|
||||||
|
currentConfig.EmuOpt &= ~EOPT_EXT_FRMLIMIT;
|
||||||
|
|
||||||
|
// prepare sound stuff
|
||||||
|
if (currentConfig.EmuOpt & EOPT_EN_SOUND)
|
||||||
|
{
|
||||||
|
PsndRerate(0);
|
||||||
|
|
||||||
|
ret = DSoundInit(FrameWnd, PsndRate, (PicoOpt & POPT_EN_STEREO) ? 1 : 0, PsndLen);
|
||||||
|
if (ret != 0) {
|
||||||
|
lprintf("dsound init failed\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PsndOut = (void *)sndbuff;
|
||||||
|
PicoWriteSound = update_sound;
|
||||||
|
currentConfig.EmuOpt |= EOPT_EXT_FRMLIMIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pemu_sound_stop(void)
|
||||||
|
{
|
||||||
|
DSoundExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pemu_sound_wait(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int plat_get_root_dir(char *dst, int len)
|
||||||
|
{
|
||||||
|
int ml;
|
||||||
|
|
||||||
|
ml = GetModuleFileName(NULL, dst, len);
|
||||||
|
while (ml > 0 && dst[ml] != '\\')
|
||||||
|
ml--;
|
||||||
|
if (ml != 0)
|
||||||
|
ml++;
|
||||||
|
|
||||||
|
dst[ml] = 0;
|
||||||
|
return ml;
|
||||||
|
}
|
||||||
|
|
||||||
|
void plat_status_msg_busy_first(const char *msg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void plat_status_msg_busy_next(const char *msg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void plat_status_msg_clear(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void plat_video_menu_enter(int is_rom_loaded)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void plat_video_menu_begin(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void plat_video_menu_end(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void plat_validate_config(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void plat_update_volume(int has_changed, int is_up)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *plat_get_credits(void)
|
||||||
|
{
|
||||||
|
return "PicoDrive v" VERSION " minibeta (c) notaz, 2006-2009\n\n"
|
||||||
|
"Credits:\n"
|
||||||
|
"fDave: base code of PicoDrive\n"
|
||||||
|
"Chui: Fame/C\n"
|
||||||
|
"NJ: CZ80\n"
|
||||||
|
"MAME devs: YM2612, SN76496 and SH2 cores\n"
|
||||||
|
"Stéphane Dallongeville: base of Fame/C (C68K), CZ80\n\n"
|
||||||
|
"Special thanks (ideas, valuable information and stuff):\n"
|
||||||
|
"Charles MacDonald, Eke, Exophase, Haze, Lordus, Nemesis,\n"
|
||||||
|
"Pierpaolo Prazzoli, Rokas, Steve Snake, Tasco Deluxe.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void plat_debug_cat(char *str)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// required by pico
|
||||||
|
int mp3_get_bitrate(FILE *f, int size)
|
||||||
|
{
|
||||||
|
return 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mp3_start_play(FILE *f, int pos)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void mp3_update(int *buffer, int length, int stereo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// other
|
||||||
|
void lprintf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char buf[512];
|
||||||
|
va_list val;
|
||||||
|
|
||||||
|
va_start(val, fmt);
|
||||||
|
vsnprintf(buf, sizeof(buf), fmt, val);
|
||||||
|
va_end(val);
|
||||||
|
OutputDebugString(buf);
|
||||||
|
printf("%s", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fake
|
||||||
|
int alphasort() { return 0; }
|
||||||
|
int scandir() { return 0; }
|
||||||
|
|
40
platform/win32/port_config.h
Normal file
40
platform/win32/port_config.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// port specific settings
|
||||||
|
|
||||||
|
#ifndef PORT_CONFIG_H
|
||||||
|
#define PORT_CONFIG_H
|
||||||
|
|
||||||
|
#define NO_SYNC
|
||||||
|
|
||||||
|
#define CASE_SENSITIVE_FS 0 // CS filesystem
|
||||||
|
#define DONT_OPEN_MANY_FILES 0
|
||||||
|
#define REDUCE_IO_CALLS 0
|
||||||
|
|
||||||
|
#define SCREEN_SIZE_FIXED 0
|
||||||
|
#define SCREEN_WIDTH 320
|
||||||
|
#define SCREEN_HEIGHT 240
|
||||||
|
|
||||||
|
// draw.c
|
||||||
|
#define OVERRIDE_HIGHCOL 0
|
||||||
|
|
||||||
|
// draw2.c
|
||||||
|
#define START_ROW 0 // which row of tiles to start rendering at?
|
||||||
|
#define END_ROW 28 // ..end
|
||||||
|
|
||||||
|
// pico.c
|
||||||
|
#define CAN_HANDLE_240_LINES 1
|
||||||
|
|
||||||
|
#define SIMPLE_WRITE_SOUND 1
|
||||||
|
#define mix_32_to_16l_stereo_lvl mix_32_to_16l_stereo
|
||||||
|
|
||||||
|
#define EL_LOGMASK (EL_STATUS)
|
||||||
|
|
||||||
|
//#define dprintf(f,...) printf("%05i:%03i: " f "\n",Pico.m.frame_count,Pico.m.scanline,##__VA_ARGS__)
|
||||||
|
#define dprintf(x...)
|
||||||
|
|
||||||
|
// platform
|
||||||
|
#define PATH_SEP "\\"
|
||||||
|
#define PATH_SEP_C '\\'
|
||||||
|
#define MENU_X2 0
|
||||||
|
|
||||||
|
#endif //PORT_CONFIG_H
|
||||||
|
|
69
platform/win32/readme.txt
Normal file
69
platform/win32/readme.txt
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
|
||||||
|
About
|
||||||
|
-----
|
||||||
|
|
||||||
|
This is a quick windows port of PicoDrive, a Megadrive / Genesis emulator for
|
||||||
|
handheld devices. It was originally coded having ARM CPU based devices in mind
|
||||||
|
(most work was done on GP2X version), but there is also a PSP port.
|
||||||
|
|
||||||
|
The reason I'm sometimes doing windows versions is to show certain emulation
|
||||||
|
possibilities, first release was to demonstrate SVP emulation (Virtua Racing),
|
||||||
|
later Pico toy and X-Men 32X prototype. It is not to compete with other
|
||||||
|
emulators like Kega Fusion and the likes.
|
||||||
|
|
||||||
|
For more info, visit http://notaz.gp2x.de/svp.php
|
||||||
|
|
||||||
|
|
||||||
|
Releases
|
||||||
|
--------
|
||||||
|
|
||||||
|
1.70 - preliminary 32X emulation, runs X-Men proto.
|
||||||
|
1.45a - Few bugfixes and additions.
|
||||||
|
1.45 - Added preliminary Sega Pico emulation.
|
||||||
|
1.40b - Perspective fix thanks to Pierpaolo Prazzoli's info.
|
||||||
|
1.40a - Tasco Deluxe's dithering fix.
|
||||||
|
1.40 - first release.
|
||||||
|
|
||||||
|
|
||||||
|
Controls
|
||||||
|
--------
|
||||||
|
|
||||||
|
These are currently hardcoded, keyboard only:
|
||||||
|
|
||||||
|
PC Gen/MD Sega Pico
|
||||||
|
-------+-----------+---------
|
||||||
|
Enter: Start
|
||||||
|
A: A
|
||||||
|
S: B red button
|
||||||
|
D: C pen push
|
||||||
|
TAB: (reset)
|
||||||
|
Esc: (load ROM)
|
||||||
|
Arrows: D-pad
|
||||||
|
|
||||||
|
It is possible to change some things in config.cfg (it is created on exit),
|
||||||
|
but possibilities are limited.
|
||||||
|
|
||||||
|
|
||||||
|
Credits
|
||||||
|
-------
|
||||||
|
|
||||||
|
Vast majority of code written by notaz (notasasatgmailcom).
|
||||||
|
|
||||||
|
A lot of work on making SVP emulation happen was done by Tasco Deluxe, my
|
||||||
|
stuff is a continuation of his. Pierpaolo Prazzoli's information and his
|
||||||
|
SSP1610 disassembler in MAME code helped a lot too.
|
||||||
|
|
||||||
|
The original PicoDrive was written by fDave from finalburn.com
|
||||||
|
|
||||||
|
This PicoDrive version uses bits and pieces of from other projects:
|
||||||
|
|
||||||
|
68k: FAME/C core, by Chui and Stéphane Dallongeville (as C68K).
|
||||||
|
z80: CZ80 by Stéphane Dallongeville and modified by NJ.
|
||||||
|
YM2612, SN76496 and SH2 cores: MAME devs.
|
||||||
|
|
||||||
|
Special thanks (ideas, valuable information and stuff):
|
||||||
|
Charles MacDonald, Eke, Exophase, Haze, Lordus, Nemesis,
|
||||||
|
Pierpaolo Prazzoli, Rokas, Steve Snake, Tasco Deluxe.
|
||||||
|
|
||||||
|
Greets to all the sceners and emu authors out there!
|
||||||
|
|
2
platform/win32/version.h
Normal file
2
platform/win32/version.h
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#define VERSION "1.70"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue