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