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