e5f2131fe4c31c402d22d8c2e4b320a916fd9f96
[cyclone68000.git] / PicoDrive / Emulate.cpp
1 \r
2 // This file is part of the PicoDrive Megadrive Emulator\r
3 \r
4 // This code is licensed under the GNU General Public License version 2.0 and the MAME License.\r
5 // You can choose the license that has the most advantages for you.\r
6 \r
7 // SVN repository can be found at http://code.google.com/p/cyclone68000/\r
8 \r
9 #include "stdafx.h"\r
10 \r
11 TCHAR RomName[260]={0};\r
12 static unsigned char *RomData=NULL;\r
13 static unsigned int RomSize=0;\r
14 \r
15 static unsigned int LastSecond=0;\r
16 static int FramesDone=0;\r
17 static int FramesPerSecond=60;\r
18 \r
19 struct Target Targ;\r
20 \r
21 static int TargetInit()\r
22 {\r
23   RECT rect={0,0,0,0};\r
24   int height=0;\r
25 \r
26   memset(&Targ,0,sizeof(Targ));\r
27 \r
28   height=168;\r
29 \r
30   ClientToScreen(FrameWnd,&Targ.point);\r
31 \r
32   GetClientRect(FrameWnd,&rect);\r
33   // Find out where the top of the screen should go:\r
34   rect.top=(rect.bottom-height)>>1;\r
35   if (rect.top<0) rect.top=0;\r
36   rect.bottom=rect.top+height;\r
37 \r
38   Targ.view=rect; // Save the view rectangle (client coordinates)\r
39 \r
40   Targ.offset=Targ.view.top+Targ.point.y;\r
41 \r
42   return 0;\r
43 }\r
44 \r
45 static int TargetUpdate()\r
46 {\r
47   // Need to repaint the view rectangle:\r
48   GetUpdateRect(FrameWnd,&Targ.update,0);\r
49 \r
50   Targ.top   =Targ.update.top   +Targ.point.y;\r
51   Targ.bottom=Targ.update.bottom+Targ.point.y;\r
52 \r
53   return 0;\r
54 }\r
55 \r
56 int EmulateInit()\r
57 {\r
58   FILE *f=NULL;\r
59 \r
60   EmulateExit(); // Make sure exited\r
61 \r
62   TargetInit(); // Find out where to put the screen\r
63 \r
64   PicoInit();\r
65 \r
66   // Load cartridge\r
67   f=_wfopen(RomName,L"rb"); if (f==NULL) return 1;\r
68   PicoCartLoad(f,&RomData,&RomSize);\r
69   fclose(f);\r
70 \r
71   PicoCartInsert(RomData,RomSize);\r
72 \r
73   LastSecond=GetTickCount(); FramesDone=0;\r
74 \r
75   return 0;\r
76 }\r
77 \r
78 void EmulateExit()\r
79 {\r
80   // Remove cartridge\r
81   PicoCartInsert(NULL,0);\r
82   if (RomData) free(RomData); RomData=NULL; RomSize=0;\r
83   \r
84   PicoExit();\r
85 }\r
86 \r
87 // Callback for scanline data:\r
88 static int EmulateScan(unsigned int scan,unsigned short *sdata)\r
89 {\r
90   int len=0;\r
91   unsigned short *ps=NULL,*end=NULL;\r
92   unsigned char *pd=NULL;\r
93   int xpitch=0;\r
94 \r
95   if ((scan&3)==1) return 0;\r
96   scan+=scan<<1; scan>>=2; // Reduce size to 75%\r
97 \r
98   scan+=Targ.offset;\r
99   if ((int)scan< Targ.top) return 0; // Out of range\r
100   if ((int)scan>=Targ.bottom) return 0; // Out of range\r
101 \r
102   pd=Targ.screen+scan*GXDisp.cbyPitch;\r
103 \r
104   len=240;\r
105   xpitch=GXDisp.cbxPitch;\r
106   ps=sdata; end=ps+320;\r
107 \r
108   // Reduce 4 pixels into 3\r
109   do\r
110   {\r
111     *(unsigned short *)pd=ps[0]; pd+=xpitch;\r
112     *(unsigned short *)pd=(unsigned short)((ps[1]+ps[2])>>1); pd+=xpitch;\r
113     *(unsigned short *)pd=ps[3]; pd+=xpitch;\r
114     ps+=4;\r
115   }\r
116   while (ps<end);\r
117 \r
118   return 0;\r
119 }\r
120 \r
121 static int DoFrame()\r
122 {\r
123   int pad=0,i=0,ks=0;\r
124   char map[8]={0,1,2,3,5,6,4,7}; // u/d/l/r/b/c/a/start\r
125 \r
126   for (i=0;i<8;i++)\r
127   {\r
128     ks=GetAsyncKeyState(Config.key[map[i]]);\r
129     if (ks) pad|=1<<i;\r
130   }\r
131   PicoPad[0]=pad;\r
132 \r
133   PicoFrame();\r
134   return 0;\r
135 }\r
136 \r
137 static int DrawFrame()\r
138 {\r
139   // Now final frame is drawn:\r
140   InvalidateRect(FrameWnd,&Targ.view,0);\r
141 \r
142   if (Main3800) Targ.screen=(unsigned char *)0xac0755a0; // The real 3800 screen address\r
143   else          Targ.screen=(unsigned char *)GXBeginDraw();\r
144 \r
145   if (Targ.screen==NULL) return 1;\r
146 \r
147   TargetUpdate();\r
148 \r
149   PicoScan=EmulateScan; // Setup scanline callback\r
150   DoFrame();\r
151   PicoScan=NULL;\r
152 \r
153 \r
154   \r
155   if (Main3800==0) GXEndDraw();\r
156 \r
157   Targ.screen=NULL;\r
158 \r
159   ValidateRect(FrameWnd,&Targ.update);\r
160 \r
161   if (PicoStatus[0])\r
162   {\r
163     // Print the status of the 68000:\r
164     HDC hdc=GetDC(FrameWnd);\r
165     RECT rect={0,220, 240,260};\r
166     TCHAR status[128]={0};\r
167 \r
168     wsprintf(status,L"%.120S",PicoStatus);\r
169 \r
170     FillRect(hdc,&rect,(HBRUSH)GetStockObject(WHITE_BRUSH));\r
171     SetBkMode(hdc,TRANSPARENT);\r
172 \r
173     DrawText(hdc,status,lstrlen(status),&rect,0);\r
174     ReleaseDC(FrameWnd,hdc);\r
175   }\r
176 \r
177   return 0;\r
178 }\r
179 \r
180 int EmulateFrame()\r
181 {\r
182   int i=0,need=0;\r
183   int time=0,frame=0;\r
184 \r
185   if (RomData==NULL) return 1;\r
186 \r
187   // Speed throttle:\r
188   time=GetTickCount()-LastSecond; // This will be about 0-1000 ms\r
189   frame=time*FramesPerSecond/1000;\r
190   need=frame-FramesDone;\r
191   FramesDone=frame;\r
192 \r
193   if (FramesPerSecond>0)\r
194   {\r
195     // Carry over any >60 frame count to one second\r
196     while (FramesDone>=FramesPerSecond) { FramesDone-=FramesPerSecond; LastSecond+=1000; }\r
197   }\r
198 \r
199   if (need<=0) { Sleep(2); return 1; }\r
200   if (need>4) need=4; // Limit frame skipping\r
201 \r
202   for (i=0;i<need-1;i++) DoFrame(); // Frame skip if needed\r
203 \r
204   DrawFrame();\r
205   return 0;\r
206 }\r
207 \r
208 int SndRender()\r
209 {\r
210 //  int p=0;\r
211 \r
212   PsndRate=WaveRate;\r
213   PsndLen=WaveLen;\r
214   PsndOut=WaveDest;\r
215 \r
216   DrawFrame();\r
217   // Convert to signed:\r
218 //  for (p=0;p<PsndLen<<1;p++) PsndOut[p]+=0x8000;\r
219 \r
220   PsndRate=PsndLen=0;\r
221   PsndOut=NULL;\r
222 \r
223   return 0;\r
224 }\r