292f9317 |
1 | /* |
2 | Copyright (C) 2002 Rice1964 |
3 | Copyright (C) 2009-2011 Richard Goedeken |
4 | |
5 | This program is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU General Public License |
7 | as published by the Free Software Foundation; either version 2 |
8 | of the License, or (at your option) any later version. |
9 | |
10 | This program is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU General Public License |
16 | along with this program; if not, write to the Free Software |
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
18 | |
19 | */ |
20 | |
21 | #include <vector> |
22 | |
23 | #include <stdarg.h> |
24 | |
25 | #include "osal_opengl.h" |
26 | |
27 | #define M64P_PLUGIN_PROTOTYPES 1 |
28 | #include "m64p_types.h" |
29 | #include "m64p_common.h" |
30 | #include "m64p_plugin.h" |
31 | #include "osal_dynamiclib.h" |
32 | |
33 | #include "Config.h" |
34 | #include "Debugger.h" |
35 | #include "DeviceBuilder.h" |
36 | #include "FrameBuffer.h" |
37 | #include "GraphicsContext.h" |
38 | #include "Render.h" |
39 | #include "RSP_Parser.h" |
40 | #include "TextureFilters.h" |
41 | #include "TextureManager.h" |
42 | #include "Video.h" |
43 | #include "version.h" |
44 | |
45 | //======================================================= |
46 | // local variables |
47 | |
48 | static void (*l_DebugCallback)(void *, int, const char *) = NULL; |
49 | static void *l_DebugCallContext = NULL; |
50 | static int l_PluginInit = 0; |
51 | |
52 | //======================================================= |
53 | // global variables |
54 | |
55 | PluginStatus status; |
56 | GFX_INFO g_GraphicsInfo; |
57 | CCritSect g_CritialSection; |
58 | |
59 | unsigned int g_dwRamSize = 0x400000; |
60 | unsigned int *g_pRDRAMu32 = NULL; |
61 | signed char *g_pRDRAMs8 = NULL; |
62 | unsigned char *g_pRDRAMu8 = NULL; |
63 | |
64 | RECT frameWriteByCPURect; |
65 | std::vector<RECT> frameWriteByCPURects; |
66 | RECT frameWriteByCPURectArray[20][20]; |
67 | bool frameWriteByCPURectFlag[20][20]; |
68 | std::vector<uint32> frameWriteRecord; |
69 | |
70 | void (*renderCallback)(int) = NULL; |
71 | |
72 | /* definitions of pointers to Core config functions */ |
73 | ptr_ConfigOpenSection ConfigOpenSection = NULL; |
74 | ptr_ConfigSetParameter ConfigSetParameter = NULL; |
75 | ptr_ConfigGetParameter ConfigGetParameter = NULL; |
76 | ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL; |
77 | ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL; |
78 | ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat = NULL; |
79 | ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL; |
80 | ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL; |
81 | ptr_ConfigGetParamInt ConfigGetParamInt = NULL; |
82 | ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL; |
83 | ptr_ConfigGetParamBool ConfigGetParamBool = NULL; |
84 | ptr_ConfigGetParamString ConfigGetParamString = NULL; |
85 | |
86 | ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL; |
87 | ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath = NULL; |
88 | ptr_ConfigGetUserDataPath ConfigGetUserDataPath = NULL; |
89 | ptr_ConfigGetUserCachePath ConfigGetUserCachePath = NULL; |
90 | |
91 | /* definitions of pointers to Core video extension functions */ |
92 | ptr_VidExt_Init CoreVideo_Init = NULL; |
93 | ptr_VidExt_Quit CoreVideo_Quit = NULL; |
94 | ptr_VidExt_ListFullscreenModes CoreVideo_ListFullscreenModes = NULL; |
95 | ptr_VidExt_SetVideoMode CoreVideo_SetVideoMode = NULL; |
96 | ptr_VidExt_SetCaption CoreVideo_SetCaption = NULL; |
97 | ptr_VidExt_ToggleFullScreen CoreVideo_ToggleFullScreen = NULL; |
98 | ptr_VidExt_ResizeWindow CoreVideo_ResizeWindow = NULL; |
99 | ptr_VidExt_GL_GetProcAddress CoreVideo_GL_GetProcAddress = NULL; |
100 | ptr_VidExt_GL_SetAttribute CoreVideo_GL_SetAttribute = NULL; |
101 | ptr_VidExt_GL_GetAttribute CoreVideo_GL_GetAttribute = NULL; |
102 | ptr_VidExt_GL_SwapBuffers CoreVideo_GL_SwapBuffers = NULL; |
103 | |
ca22e7b7 |
104 | // For Fameskip |
105 | float mspervi = 1000.0f/60.0f; //default is shortest frame |
106 | float numvi = 0.0f; |
107 | bool skipping = false; |
108 | |
292f9317 |
109 | //--------------------------------------------------------------------------------------- |
110 | // Forward function declarations |
111 | |
112 | extern "C" EXPORT void CALL RomClosed(void); |
113 | |
114 | //--------------------------------------------------------------------------------------- |
115 | // Static (local) functions |
116 | static void ChangeWindowStep2() |
117 | { |
118 | status.bDisableFPS = true; |
119 | windowSetting.bDisplayFullscreen = !windowSetting.bDisplayFullscreen; |
120 | g_CritialSection.Lock(); |
121 | windowSetting.bDisplayFullscreen = CGraphicsContext::Get()->ToggleFullscreen(); |
122 | |
123 | CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); |
124 | CGraphicsContext::Get()->UpdateFrame(); |
125 | CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); |
126 | CGraphicsContext::Get()->UpdateFrame(); |
127 | CGraphicsContext::Get()->Clear(CLEAR_COLOR_AND_DEPTH_BUFFER); |
128 | CGraphicsContext::Get()->UpdateFrame(); |
129 | g_CritialSection.Unlock(); |
130 | status.bDisableFPS = false; |
131 | status.ToToggleFullScreen = FALSE; |
132 | } |
133 | |
134 | static void ResizeStep2(void) |
135 | { |
136 | g_CritialSection.Lock(); |
137 | |
138 | // Delete all OpenGL textures |
139 | gTextureManager.CleanUp(); |
140 | RDP_Cleanup(); |
141 | // delete our opengl renderer |
142 | CDeviceBuilder::GetBuilder()->DeleteRender(); |
143 | |
144 | // call video extension function with updated width, height (this creates a new OpenGL context) |
145 | windowSetting.uDisplayWidth = status.gNewResizeWidth; |
146 | windowSetting.uDisplayHeight = status.gNewResizeHeight; |
147 | CoreVideo_ResizeWindow(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight); |
148 | |
149 | // re-initialize our OpenGL graphics context state |
150 | bool res = CGraphicsContext::Get()->ResizeInitialize(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, !windowSetting.bDisplayFullscreen); |
151 | if (res) |
152 | { |
153 | // re-create the OpenGL renderer |
154 | CDeviceBuilder::GetBuilder()->CreateRender(); |
155 | CRender::GetRender()->Initialize(); |
156 | DLParser_Init(); |
157 | } |
158 | |
159 | g_CritialSection.Unlock(); |
160 | status.ToResize = false; |
161 | } |
162 | |
163 | static void UpdateScreenStep2 (void) |
164 | { |
165 | status.bVIOriginIsUpdated = false; |
166 | |
167 | if( status.ToToggleFullScreen && status.gDlistCount > 0 ) |
168 | { |
169 | ChangeWindowStep2(); |
170 | return; |
171 | } |
172 | if (status.ToResize && status.gDlistCount > 0) |
173 | { |
174 | ResizeStep2(); |
175 | return; |
176 | } |
177 | |
178 | g_CritialSection.Lock(); |
ca22e7b7 |
179 | |
180 | //framskip, count vi |
181 | numvi++; |
182 | |
292f9317 |
183 | if( status.bHandleN64RenderTexture ) |
184 | g_pFrameBufferManager->CloseRenderTexture(true); |
ca22e7b7 |
185 | |
186 | if (skipping) { |
187 | g_CritialSection.Unlock(); |
188 | return; |
189 | } |
292f9317 |
190 | |
191 | g_pFrameBufferManager->SetAddrBeDisplayed(*g_GraphicsInfo.VI_ORIGIN_REG); |
192 | |
ca22e7b7 |
193 | if(status.gDlistCount == 0) |
292f9317 |
194 | { |
195 | // CPU frame buffer update |
196 | uint32 width = *g_GraphicsInfo.VI_WIDTH_REG; |
197 | if( (*g_GraphicsInfo.VI_ORIGIN_REG & (g_dwRamSize-1) ) > width*2 && *g_GraphicsInfo.VI_H_START_REG != 0 && width != 0 ) |
198 | { |
199 | SetVIScales(); |
200 | CRender::GetRender()->DrawFrameBuffer(true); |
201 | CGraphicsContext::Get()->UpdateFrame(); |
202 | } |
203 | g_CritialSection.Unlock(); |
204 | return; |
205 | } |
206 | |
207 | TXTRBUF_DETAIL_DUMP(TRACE1("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG)); |
208 | |
209 | if( currentRomOptions.screenUpdateSetting == SCREEN_UPDATE_AT_VI_UPDATE ) |
210 | { |
211 | CGraphicsContext::Get()->UpdateFrame(); |
212 | |
213 | DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); |
214 | DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); |
215 | DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); |
216 | g_CritialSection.Unlock(); |
217 | return; |
218 | } |
219 | |
220 | TXTRBUF_DETAIL_DUMP(TRACE1("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG)); |
221 | |
222 | if( currentRomOptions.screenUpdateSetting == SCREEN_UPDATE_AT_VI_UPDATE_AND_DRAWN ) |
223 | { |
224 | if( status.bScreenIsDrawn ) |
225 | { |
226 | CGraphicsContext::Get()->UpdateFrame(); |
227 | DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); |
228 | } |
229 | else |
230 | { |
231 | DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Skip Screen Update: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); |
232 | } |
233 | |
234 | DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); |
235 | DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); |
236 | g_CritialSection.Unlock(); |
237 | return; |
238 | } |
239 | |
240 | if( currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_VI_CHANGE ) |
241 | { |
242 | |
243 | if( *g_GraphicsInfo.VI_ORIGIN_REG != status.curVIOriginReg ) |
244 | { |
245 | if( *g_GraphicsInfo.VI_ORIGIN_REG < status.curDisplayBuffer || *g_GraphicsInfo.VI_ORIGIN_REG > status.curDisplayBuffer+0x2000 ) |
246 | { |
247 | status.curDisplayBuffer = *g_GraphicsInfo.VI_ORIGIN_REG; |
248 | status.curVIOriginReg = status.curDisplayBuffer; |
249 | //status.curRenderBuffer = NULL; |
250 | |
251 | CGraphicsContext::Get()->UpdateFrame(); |
252 | DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("Update Screen: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); |
253 | DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); |
254 | DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); |
255 | } |
256 | else |
257 | { |
258 | status.curDisplayBuffer = *g_GraphicsInfo.VI_ORIGIN_REG; |
259 | status.curVIOriginReg = status.curDisplayBuffer; |
260 | DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("Skip Screen Update, closed to the display buffer, VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG);}); |
261 | } |
262 | } |
263 | else |
264 | { |
265 | DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("Skip Screen Update, the same VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG);}); |
266 | } |
267 | |
268 | g_CritialSection.Unlock(); |
269 | return; |
270 | } |
271 | |
272 | if( currentRomOptions.screenUpdateSetting >= SCREEN_UPDATE_AT_1ST_CI_CHANGE ) |
273 | { |
274 | status.bVIOriginIsUpdated=true; |
275 | DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_FRAME, {DebuggerAppendMsg("VI ORIG is updated to %08X", *g_GraphicsInfo.VI_ORIGIN_REG);}); |
276 | g_CritialSection.Unlock(); |
277 | return; |
278 | } |
279 | |
280 | DEBUGGER_IF_DUMP( pauseAtNext, TRACE1("VI is updated, No screen update: VIORIG=%08X", *g_GraphicsInfo.VI_ORIGIN_REG)); |
281 | DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_FRAME); |
282 | DEBUGGER_PAUSE_COUNT_N_WITHOUT_UPDATE(NEXT_SET_CIMG); |
283 | |
284 | g_CritialSection.Unlock(); |
285 | } |
286 | |
287 | static void ProcessDListStep2(void) |
288 | { |
289 | g_CritialSection.Lock(); |
290 | if( status.toShowCFB ) |
291 | { |
292 | CRender::GetRender()->DrawFrameBuffer(true); |
293 | status.toShowCFB = false; |
294 | } |
295 | |
296 | try |
297 | { |
298 | DLParser_Process((OSTask *)(g_GraphicsInfo.DMEM + 0x0FC0)); |
299 | } |
300 | catch (...) |
301 | { |
302 | TRACE0("Unknown Error in ProcessDList"); |
303 | TriggerDPInterrupt(); |
304 | TriggerSPInterrupt(); |
305 | } |
306 | |
307 | g_CritialSection.Unlock(); |
308 | } |
309 | |
310 | static bool StartVideo(void) |
311 | { |
312 | windowSetting.dps = windowSetting.fps = -1; |
313 | windowSetting.lastSecDlistCount = windowSetting.lastSecFrameCount = 0xFFFFFFFF; |
314 | |
315 | g_CritialSection.Lock(); |
316 | |
317 | memcpy(&g_curRomInfo.romheader, g_GraphicsInfo.HEADER, sizeof(ROMHeader)); |
318 | unsigned char *puc = (unsigned char *) &g_curRomInfo.romheader; |
319 | unsigned int i; |
320 | unsigned char temp; |
321 | for (i = 0; i < sizeof(ROMHeader); i += 4) /* byte-swap the ROM header */ |
322 | { |
323 | temp = puc[i]; |
324 | puc[i] = puc[i+3]; |
325 | puc[i+3] = temp; |
326 | temp = puc[i+1]; |
327 | puc[i+1] = puc[i+2]; |
328 | puc[i+2] = temp; |
329 | } |
330 | |
331 | ROM_GetRomNameFromHeader(g_curRomInfo.szGameName, &g_curRomInfo.romheader); |
332 | Ini_GetRomOptions(&g_curRomInfo); |
333 | char *p = (char *) g_curRomInfo.szGameName + (strlen((char *) g_curRomInfo.szGameName) -1); // -1 to skip null |
334 | while (p >= (char *) g_curRomInfo.szGameName) |
335 | { |
336 | if( *p == ':' || *p == '\\' || *p == '/' ) |
337 | *p = '-'; |
338 | p--; |
339 | } |
340 | |
341 | GenerateCurrentRomOptions(); |
342 | status.dwTvSystem = CountryCodeToTVSystem(g_curRomInfo.romheader.nCountryID); |
ca22e7b7 |
343 | if( status.dwTvSystem == TV_SYSTEM_NTSC ) { |
292f9317 |
344 | status.fRatio = 0.75f; |
ca22e7b7 |
345 | mspervi=1000.0f/60.0f; //for framskipping |
346 | } else { |
347 | status.fRatio = 9/11.0f; |
348 | mspervi=1000.0f/50.0f; //for framskipping |
349 | } |
292f9317 |
350 | |
351 | InitExternalTextures(); |
352 | |
353 | try { |
354 | CDeviceBuilder::GetBuilder()->CreateGraphicsContext(); |
355 | CGraphicsContext::InitWindowInfo(); |
356 | |
357 | bool res = CGraphicsContext::Get()->Initialize(640, 480, !windowSetting.bDisplayFullscreen); |
358 | if (!res) |
359 | { |
360 | g_CritialSection.Unlock(); |
361 | return false; |
362 | } |
363 | CDeviceBuilder::GetBuilder()->CreateRender(); |
364 | CRender::GetRender()->Initialize(); |
365 | DLParser_Init(); |
366 | status.bGameIsRunning = true; |
367 | } |
368 | catch(...) |
369 | { |
370 | DebugMessage(M64MSG_ERROR, "Exception caught while starting video renderer"); |
371 | throw 0; |
372 | } |
373 | |
374 | g_CritialSection.Unlock(); |
375 | return true; |
376 | } |
377 | |
378 | static void StopVideo() |
379 | { |
380 | g_CritialSection.Lock(); |
381 | status.bGameIsRunning = false; |
382 | |
383 | try { |
384 | CloseExternalTextures(); |
385 | |
386 | // Kill all textures? |
387 | gTextureManager.RecycleAllTextures(); |
388 | gTextureManager.CleanUp(); |
389 | RDP_Cleanup(); |
390 | |
391 | CDeviceBuilder::GetBuilder()->DeleteRender(); |
392 | CGraphicsContext::Get()->CleanUp(); |
393 | CDeviceBuilder::GetBuilder()->DeleteGraphicsContext(); |
394 | } |
395 | catch(...) |
396 | { |
397 | TRACE0("Some exceptions during RomClosed"); |
398 | } |
399 | |
400 | g_CritialSection.Unlock(); |
401 | windowSetting.dps = windowSetting.fps = -1; |
402 | windowSetting.lastSecDlistCount = windowSetting.lastSecFrameCount = 0xFFFFFFFF; |
403 | status.gDlistCount = status.gFrameCount = 0; |
404 | |
405 | } |
406 | |
407 | //--------------------------------------------------------------------------------------- |
408 | // Global functions, for use by other source files in this plugin |
409 | |
410 | void SetVIScales() |
411 | { |
412 | if( g_curRomInfo.VIHeight>0 && g_curRomInfo.VIWidth>0 ) |
413 | { |
414 | windowSetting.fViWidth = windowSetting.uViWidth = g_curRomInfo.VIWidth; |
415 | windowSetting.fViHeight = windowSetting.uViHeight = g_curRomInfo.VIHeight; |
416 | } |
417 | else if( g_curRomInfo.UseCIWidthAndRatio && g_CI.dwWidth ) |
418 | { |
419 | windowSetting.fViWidth = windowSetting.uViWidth = g_CI.dwWidth; |
420 | windowSetting.fViHeight = windowSetting.uViHeight = |
421 | g_curRomInfo.UseCIWidthAndRatio == USE_CI_WIDTH_AND_RATIO_FOR_NTSC ? g_CI.dwWidth/4*3 : g_CI.dwWidth/11*9; |
422 | } |
423 | else |
424 | { |
425 | float xscale, yscale; |
426 | uint32 val = *g_GraphicsInfo.VI_X_SCALE_REG & 0xFFF; |
427 | xscale = (float)val / (1<<10); |
428 | uint32 start = *g_GraphicsInfo.VI_H_START_REG >> 16; |
429 | uint32 end = *g_GraphicsInfo.VI_H_START_REG&0xFFFF; |
430 | uint32 width = *g_GraphicsInfo.VI_WIDTH_REG; |
431 | windowSetting.fViWidth = (end-start)*xscale; |
432 | if( abs((int)(windowSetting.fViWidth - width) ) < 8 ) |
433 | { |
434 | windowSetting.fViWidth = (float)width; |
435 | } |
436 | else |
437 | { |
438 | DebuggerAppendMsg("fViWidth = %f, Width Reg=%d", windowSetting.fViWidth, width); |
439 | } |
440 | |
441 | val = (*g_GraphicsInfo.VI_Y_SCALE_REG & 0xFFF);// - ((*g_GraphicsInfo.VI_Y_SCALE_REG>>16) & 0xFFF); |
442 | if( val == 0x3FF ) val = 0x400; |
443 | yscale = (float)val / (1<<10); |
444 | start = *g_GraphicsInfo.VI_V_START_REG >> 16; |
445 | end = *g_GraphicsInfo.VI_V_START_REG&0xFFFF; |
446 | windowSetting.fViHeight = (end-start)/2*yscale; |
447 | |
448 | if( yscale == 0 ) |
449 | { |
450 | windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio; |
451 | } |
452 | else |
453 | { |
454 | if( *g_GraphicsInfo.VI_WIDTH_REG > 0x300 ) |
455 | windowSetting.fViHeight *= 2; |
456 | |
457 | if( windowSetting.fViWidth*status.fRatio > windowSetting.fViHeight && (*g_GraphicsInfo.VI_X_SCALE_REG & 0xFF) != 0 ) |
458 | { |
459 | if( abs(int(windowSetting.fViWidth*status.fRatio - windowSetting.fViHeight)) < 8 ) |
460 | { |
461 | windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio; |
462 | } |
463 | /* |
464 | else |
465 | { |
466 | if( abs(windowSetting.fViWidth*status.fRatio-windowSetting.fViHeight) > windowSetting.fViWidth*0.1f ) |
467 | { |
468 | if( status.fRatio > 0.8 ) |
469 | windowSetting.fViHeight = windowSetting.fViWidth*3/4; |
470 | //windowSetting.fViHeight = (*g_GraphicsInfo.VI_V_SYNC_REG - 0x2C)/2; |
471 | } |
472 | } |
473 | */ |
474 | } |
475 | |
476 | if( windowSetting.fViHeight<100 || windowSetting.fViWidth<100 ) |
477 | { |
478 | //At sometime, value in VI_H_START_REG or VI_V_START_REG are 0 |
479 | windowSetting.fViWidth = (float)*g_GraphicsInfo.VI_WIDTH_REG; |
480 | windowSetting.fViHeight = windowSetting.fViWidth*status.fRatio; |
481 | } |
482 | } |
483 | |
484 | windowSetting.uViWidth = (unsigned short)(windowSetting.fViWidth/4); |
485 | windowSetting.fViWidth = windowSetting.uViWidth *= 4; |
486 | |
487 | windowSetting.uViHeight = (unsigned short)(windowSetting.fViHeight/4); |
488 | windowSetting.fViHeight = windowSetting.uViHeight *= 4; |
489 | uint16 optimizeHeight = (uint16)(windowSetting.uViWidth*status.fRatio); |
490 | optimizeHeight &= ~3; |
491 | |
492 | uint16 optimizeHeight2 = (uint16)(windowSetting.uViWidth*3/4); |
493 | optimizeHeight2 &= ~3; |
494 | |
495 | if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 ) |
496 | { |
497 | if( abs(windowSetting.uViHeight-optimizeHeight) <= 8 ) |
498 | windowSetting.fViHeight = windowSetting.uViHeight = optimizeHeight; |
499 | else if( abs(windowSetting.uViHeight-optimizeHeight2) <= 8 ) |
500 | windowSetting.fViHeight = windowSetting.uViHeight = optimizeHeight2; |
501 | } |
502 | |
503 | |
504 | if( gRDP.scissor.left == 0 && gRDP.scissor.top == 0 && gRDP.scissor.right != 0 ) |
505 | { |
506 | if( (*g_GraphicsInfo.VI_X_SCALE_REG & 0xFF) != 0x0 && gRDP.scissor.right == windowSetting.uViWidth ) |
507 | { |
508 | // Mario Tennis |
509 | if( abs(int( windowSetting.fViHeight - gRDP.scissor.bottom )) < 8 ) |
510 | { |
511 | windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom; |
512 | } |
513 | else if( windowSetting.fViHeight < gRDP.scissor.bottom ) |
514 | { |
515 | windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom; |
516 | } |
517 | windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom; |
518 | } |
519 | else if( gRDP.scissor.right == windowSetting.uViWidth - 1 && gRDP.scissor.bottom != 0 ) |
520 | { |
521 | if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 ) |
522 | { |
523 | if( status.fRatio != 0.75 && windowSetting.fViHeight > optimizeHeight/2 ) |
524 | { |
525 | windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom + gRDP.scissor.top + 1; |
526 | } |
527 | } |
528 | } |
529 | else if( gRDP.scissor.right == windowSetting.uViWidth && gRDP.scissor.bottom != 0 && status.fRatio != 0.75 ) |
530 | { |
531 | if( windowSetting.uViHeight != optimizeHeight && windowSetting.uViHeight != optimizeHeight2 ) |
532 | { |
533 | if( status.fRatio != 0.75 && windowSetting.fViHeight > optimizeHeight/2 ) |
534 | { |
535 | windowSetting.fViHeight = windowSetting.uViHeight = gRDP.scissor.bottom + gRDP.scissor.top + 1; |
536 | } |
537 | } |
538 | } |
539 | } |
540 | } |
541 | SetScreenMult(windowSetting.uDisplayWidth/windowSetting.fViWidth, windowSetting.uDisplayHeight/windowSetting.fViHeight); |
542 | } |
543 | |
544 | void TriggerDPInterrupt(void) |
545 | { |
546 | *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_DP; |
547 | g_GraphicsInfo.CheckInterrupts(); |
548 | } |
549 | |
550 | void TriggerSPInterrupt(void) |
551 | { |
552 | *(g_GraphicsInfo.MI_INTR_REG) |= MI_INTR_SP; |
553 | g_GraphicsInfo.CheckInterrupts(); |
554 | } |
555 | |
556 | void _VIDEO_DisplayTemporaryMessage(const char *Message) |
557 | { |
558 | } |
559 | |
560 | void DebugMessage(int level, const char *message, ...) |
561 | { |
562 | char msgbuf[1024]; |
563 | va_list args; |
564 | |
565 | if (l_DebugCallback == NULL) |
566 | return; |
567 | |
568 | va_start(args, message); |
569 | vsprintf(msgbuf, message, args); |
570 | |
571 | (*l_DebugCallback)(l_DebugCallContext, level, msgbuf); |
572 | |
573 | va_end(args); |
574 | } |
575 | |
576 | //--------------------------------------------------------------------------------------- |
577 | // Global functions, exported for use by the core library |
578 | |
579 | // since these functions are exported, they need to have C-style names |
580 | #ifdef __cplusplus |
581 | extern "C" { |
582 | #endif |
583 | |
584 | /* Mupen64Plus plugin functions */ |
585 | EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context, |
586 | void (*DebugCallback)(void *, int, const char *)) |
587 | { |
588 | if (l_PluginInit) |
589 | return M64ERR_ALREADY_INIT; |
590 | |
591 | /* first thing is to set the callback function for debug info */ |
592 | l_DebugCallback = DebugCallback; |
593 | l_DebugCallContext = Context; |
594 | |
595 | /* attach and call the CoreGetAPIVersions function, check Config and Video Extension API versions for compatibility */ |
596 | ptr_CoreGetAPIVersions CoreAPIVersionFunc; |
597 | CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions"); |
598 | if (CoreAPIVersionFunc == NULL) |
599 | { |
600 | DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found."); |
601 | return M64ERR_INCOMPATIBLE; |
602 | } |
603 | int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion; |
604 | (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL); |
605 | if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000)) |
606 | { |
607 | DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)", |
608 | VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION)); |
609 | return M64ERR_INCOMPATIBLE; |
610 | } |
611 | if ((VidextAPIVersion & 0xffff0000) != (VIDEXT_API_VERSION & 0xffff0000)) |
612 | { |
613 | DebugMessage(M64MSG_ERROR, "Emulator core Video Extension API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)", |
614 | VERSION_PRINTF_SPLIT(VidextAPIVersion), VERSION_PRINTF_SPLIT(VIDEXT_API_VERSION)); |
615 | return M64ERR_INCOMPATIBLE; |
616 | } |
617 | |
618 | /* Get the core config function pointers from the library handle */ |
619 | ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection"); |
620 | ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter"); |
621 | ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter"); |
622 | ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt"); |
623 | ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat"); |
624 | ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool"); |
625 | ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString"); |
626 | ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt"); |
627 | ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat"); |
628 | ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool"); |
629 | ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString"); |
630 | |
631 | ConfigGetSharedDataFilepath = (ptr_ConfigGetSharedDataFilepath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetSharedDataFilepath"); |
632 | ConfigGetUserConfigPath = (ptr_ConfigGetUserConfigPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserConfigPath"); |
633 | ConfigGetUserDataPath = (ptr_ConfigGetUserDataPath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserDataPath"); |
634 | ConfigGetUserCachePath = (ptr_ConfigGetUserCachePath) osal_dynlib_getproc(CoreLibHandle, "ConfigGetUserCachePath"); |
635 | |
636 | if (!ConfigOpenSection || !ConfigSetParameter || !ConfigGetParameter || |
637 | !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString || |
638 | !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString || |
639 | !ConfigGetSharedDataFilepath || !ConfigGetUserConfigPath || !ConfigGetUserDataPath || !ConfigGetUserCachePath) |
640 | { |
641 | DebugMessage(M64MSG_ERROR, "Couldn't connect to Core configuration functions"); |
642 | return M64ERR_INCOMPATIBLE; |
643 | } |
644 | |
645 | /* Get the core Video Extension function pointers from the library handle */ |
646 | CoreVideo_Init = (ptr_VidExt_Init) osal_dynlib_getproc(CoreLibHandle, "VidExt_Init"); |
647 | CoreVideo_Quit = (ptr_VidExt_Quit) osal_dynlib_getproc(CoreLibHandle, "VidExt_Quit"); |
648 | CoreVideo_ListFullscreenModes = (ptr_VidExt_ListFullscreenModes) osal_dynlib_getproc(CoreLibHandle, "VidExt_ListFullscreenModes"); |
649 | CoreVideo_SetVideoMode = (ptr_VidExt_SetVideoMode) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetVideoMode"); |
650 | CoreVideo_SetCaption = (ptr_VidExt_SetCaption) osal_dynlib_getproc(CoreLibHandle, "VidExt_SetCaption"); |
651 | CoreVideo_ToggleFullScreen = (ptr_VidExt_ToggleFullScreen) osal_dynlib_getproc(CoreLibHandle, "VidExt_ToggleFullScreen"); |
652 | CoreVideo_ResizeWindow = (ptr_VidExt_ResizeWindow) osal_dynlib_getproc(CoreLibHandle, "VidExt_ResizeWindow"); |
653 | CoreVideo_GL_GetProcAddress = (ptr_VidExt_GL_GetProcAddress) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_GetProcAddress"); |
654 | CoreVideo_GL_SetAttribute = (ptr_VidExt_GL_SetAttribute) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SetAttribute"); |
655 | CoreVideo_GL_GetAttribute = (ptr_VidExt_GL_GetAttribute) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_GetAttribute"); |
656 | CoreVideo_GL_SwapBuffers = (ptr_VidExt_GL_SwapBuffers) osal_dynlib_getproc(CoreLibHandle, "VidExt_GL_SwapBuffers"); |
657 | |
658 | if (!CoreVideo_Init || !CoreVideo_Quit || !CoreVideo_ListFullscreenModes || !CoreVideo_SetVideoMode || |
659 | !CoreVideo_ResizeWindow || !CoreVideo_SetCaption || !CoreVideo_ToggleFullScreen || !CoreVideo_GL_GetProcAddress || |
660 | !CoreVideo_GL_SetAttribute || !CoreVideo_GL_GetAttribute || !CoreVideo_GL_SwapBuffers) |
661 | { |
662 | DebugMessage(M64MSG_ERROR, "Couldn't connect to Core video extension functions"); |
663 | return M64ERR_INCOMPATIBLE; |
664 | } |
665 | |
666 | /* open config section handles and set parameter default values */ |
667 | if (!InitConfiguration()) |
668 | return M64ERR_INTERNAL; |
669 | |
670 | l_PluginInit = 1; |
671 | return M64ERR_SUCCESS; |
672 | } |
673 | |
674 | EXPORT m64p_error CALL PluginShutdown(void) |
675 | { |
676 | if (!l_PluginInit) |
677 | return M64ERR_NOT_INIT; |
678 | |
679 | if( status.bGameIsRunning ) |
680 | { |
681 | RomClosed(); |
682 | } |
683 | if (bIniIsChanged) |
684 | { |
685 | WriteIniFile(); |
686 | TRACE0("Write back INI file"); |
687 | } |
688 | |
689 | /* reset some local variables */ |
690 | l_DebugCallback = NULL; |
691 | l_DebugCallContext = NULL; |
692 | |
693 | l_PluginInit = 0; |
694 | return M64ERR_SUCCESS; |
695 | } |
696 | |
697 | EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities) |
698 | { |
699 | /* set version info */ |
700 | if (PluginType != NULL) |
701 | *PluginType = M64PLUGIN_GFX; |
702 | |
703 | if (PluginVersion != NULL) |
704 | *PluginVersion = PLUGIN_VERSION; |
705 | |
706 | if (APIVersion != NULL) |
707 | *APIVersion = VIDEO_PLUGIN_API_VERSION; |
708 | |
709 | if (PluginNamePtr != NULL) |
710 | *PluginNamePtr = PLUGIN_NAME; |
711 | |
712 | if (Capabilities != NULL) |
713 | { |
714 | *Capabilities = 0; |
715 | } |
716 | |
717 | return M64ERR_SUCCESS; |
718 | } |
719 | |
720 | //------------------------------------------------------------------------------------- |
721 | |
722 | |
723 | EXPORT void CALL ChangeWindow (void) |
724 | { |
725 | if( status.ToToggleFullScreen ) |
726 | status.ToToggleFullScreen = FALSE; |
727 | else |
728 | status.ToToggleFullScreen = TRUE; |
729 | } |
730 | |
731 | //--------------------------------------------------------------------------------------- |
732 | |
733 | EXPORT void CALL MoveScreen (int xpos, int ypos) |
734 | { |
735 | } |
736 | |
737 | //--------------------------------------------------------------------------------------- |
738 | EXPORT void CALL RomClosed(void) |
739 | { |
740 | TRACE0("To stop video"); |
741 | Ini_StoreRomOptions(&g_curRomInfo); |
742 | StopVideo(); |
743 | TRACE0("Video is stopped"); |
744 | } |
745 | |
746 | EXPORT int CALL RomOpen(void) |
747 | { |
748 | /* Read RiceVideoLinux.ini file, set up internal variables by reading values from core configuration API */ |
749 | LoadConfiguration(); |
750 | |
751 | if( g_CritialSection.IsLocked() ) |
752 | { |
753 | g_CritialSection.Unlock(); |
754 | TRACE0("g_CritialSection is locked when game is starting, unlock it now."); |
755 | } |
756 | status.bDisableFPS=false; |
757 | |
758 | g_dwRamSize = 0x800000; |
759 | |
760 | #ifdef DEBUGGER |
761 | if( debuggerPause ) |
762 | { |
763 | debuggerPause = FALSE; |
764 | usleep(100 * 1000); |
765 | } |
766 | #endif |
767 | |
768 | if (!StartVideo()) |
769 | return 0; |
770 | |
771 | return 1; |
772 | } |
773 | |
774 | |
775 | //--------------------------------------------------------------------------------------- |
776 | EXPORT void CALL UpdateScreen(void) |
777 | { |
778 | if(options.bShowFPS) |
779 | { |
780 | static unsigned int lastTick=0; |
781 | static int frames=0; |
782 | unsigned int nowTick = SDL_GetTicks(); |
783 | frames++; |
784 | if(lastTick + 5000 <= nowTick) |
785 | { |
786 | char caption[200]; |
787 | sprintf(caption, "%s v%i.%i.%i - %.3f VI/S", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION), frames/5.0); |
788 | CoreVideo_SetCaption(caption); |
789 | frames = 0; |
790 | lastTick = nowTick; |
791 | } |
792 | } |
793 | UpdateScreenStep2(); |
794 | } |
795 | |
796 | //--------------------------------------------------------------------------------------- |
797 | |
798 | EXPORT void CALL ViStatusChanged(void) |
799 | { |
800 | g_CritialSection.Lock(); |
801 | SetVIScales(); |
802 | CRender::g_pRender->UpdateClipRectangle(); |
803 | g_CritialSection.Unlock(); |
804 | } |
805 | |
806 | //--------------------------------------------------------------------------------------- |
807 | EXPORT void CALL ViWidthChanged(void) |
808 | { |
809 | g_CritialSection.Lock(); |
810 | SetVIScales(); |
811 | CRender::g_pRender->UpdateClipRectangle(); |
812 | g_CritialSection.Unlock(); |
813 | } |
814 | |
815 | EXPORT int CALL InitiateGFX(GFX_INFO Gfx_Info) |
816 | { |
817 | memset(&status, 0, sizeof(status)); |
818 | memcpy(&g_GraphicsInfo, &Gfx_Info, sizeof(GFX_INFO)); |
819 | |
820 | g_pRDRAMu8 = Gfx_Info.RDRAM; |
821 | g_pRDRAMu32 = (uint32*)Gfx_Info.RDRAM; |
822 | g_pRDRAMs8 = (signed char *)Gfx_Info.RDRAM; |
823 | |
824 | windowSetting.fViWidth = 320; |
825 | windowSetting.fViHeight = 240; |
826 | status.ToToggleFullScreen = FALSE; |
827 | status.ToResize = false; |
828 | status.bDisableFPS=false; |
829 | |
830 | if (!InitConfiguration()) |
831 | { |
832 | DebugMessage(M64MSG_ERROR, "Failed to read configuration data"); |
833 | return FALSE; |
834 | } |
835 | |
836 | CGraphicsContext::InitWindowInfo(); |
837 | CGraphicsContext::InitDeviceParameters(); |
838 | |
839 | return(TRUE); |
840 | } |
841 | |
842 | EXPORT void CALL ResizeVideoOutput(int width, int height) |
843 | { |
844 | // save the new window resolution. actual resizing operation is asynchronous (it happens later) |
845 | status.gNewResizeWidth = width; |
846 | status.gNewResizeHeight = height; |
847 | status.ToResize = true; |
848 | } |
849 | |
850 | //--------------------------------------------------------------------------------------- |
851 | |
852 | EXPORT void CALL ProcessRDPList(void) |
853 | { |
854 | try |
855 | { |
856 | RDP_DLParser_Process(); |
857 | } |
858 | catch (...) |
859 | { |
860 | TRACE0("Unknown Error in ProcessRDPList"); |
861 | TriggerDPInterrupt(); |
862 | TriggerSPInterrupt(); |
863 | } |
864 | } |
865 | |
866 | EXPORT void CALL ProcessDList(void) |
867 | { |
868 | ProcessDListStep2(); |
869 | } |
870 | |
871 | //--------------------------------------------------------------------------------------- |
872 | |
873 | /****************************************************************** |
874 | Function: FrameBufferRead |
875 | Purpose: This function is called to notify the dll that the |
876 | frame buffer memory is beening read at the given address. |
877 | DLL should copy content from its render buffer to the frame buffer |
878 | in N64 RDRAM |
879 | DLL is responsible to maintain its own frame buffer memory addr list |
880 | DLL should copy 4KB block content back to RDRAM frame buffer. |
881 | Emulator should not call this function again if other memory |
882 | is read within the same 4KB range |
883 | |
884 | Since depth buffer is also being watched, the reported addr |
885 | may belong to depth buffer |
886 | input: addr rdram address |
887 | val val |
888 | size 1 = uint8, 2 = uint16, 4 = uint32 |
889 | output: none |
890 | *******************************************************************/ |
891 | |
892 | EXPORT void CALL FBRead(uint32 addr) |
893 | { |
894 | g_pFrameBufferManager->FrameBufferReadByCPU(addr); |
895 | } |
896 | |
897 | |
898 | /****************************************************************** |
899 | Function: FrameBufferWrite |
900 | Purpose: This function is called to notify the dll that the |
901 | frame buffer has been modified by CPU at the given address. |
902 | |
903 | Since depth buffer is also being watched, the reported addr |
904 | may belong to depth buffer |
905 | |
906 | input: addr rdram address |
907 | val val |
908 | size 1 = uint8, 2 = uint16, 4 = uint32 |
909 | output: none |
910 | *******************************************************************/ |
911 | |
912 | EXPORT void CALL FBWrite(uint32 addr, uint32 size) |
913 | { |
914 | g_pFrameBufferManager->FrameBufferWriteByCPU(addr, size); |
915 | } |
916 | |
917 | /************************************************************************ |
918 | Function: FBGetFrameBufferInfo |
919 | Purpose: This function is called by the emulator core to retrieve frame |
920 | buffer information from the video plugin in order to be able |
921 | to notify the video plugin about CPU frame buffer read/write |
922 | operations |
923 | |
924 | size: |
925 | = 1 byte |
926 | = 2 word (16 bit) <-- this is N64 default depth buffer format |
927 | = 4 dword (32 bit) |
928 | |
929 | when frame buffer information is not available yet, set all values |
930 | in the FrameBufferInfo structure to 0 |
931 | |
932 | input: FrameBufferInfo pinfo[6] |
933 | pinfo is pointed to a FrameBufferInfo structure which to be |
934 | filled in by this function |
935 | output: Values are return in the FrameBufferInfo structure |
936 | Plugin can return up to 6 frame buffer info |
937 | ************************************************************************/ |
938 | |
939 | EXPORT void CALL FBGetFrameBufferInfo(void *p) |
940 | { |
941 | FrameBufferInfo * pinfo = (FrameBufferInfo *)p; |
942 | memset(pinfo,0,sizeof(FrameBufferInfo)*6); |
943 | |
944 | //if( g_ZI.dwAddr == 0 ) |
945 | //{ |
946 | // memset(pinfo,0,sizeof(FrameBufferInfo)*6); |
947 | //} |
948 | //else |
949 | { |
950 | for (int i=0; i<5; i++ ) |
951 | { |
952 | if( status.gDlistCount-g_RecentCIInfo[i].lastUsedFrame > 30 || g_RecentCIInfo[i].lastUsedFrame == 0 ) |
953 | { |
954 | //memset(&pinfo[i],0,sizeof(FrameBufferInfo)); |
955 | } |
956 | else |
957 | { |
958 | pinfo[i].addr = g_RecentCIInfo[i].dwAddr; |
959 | pinfo[i].size = 2; |
960 | pinfo[i].width = g_RecentCIInfo[i].dwWidth; |
961 | pinfo[i].height = g_RecentCIInfo[i].dwHeight; |
962 | TXTRBUF_DETAIL_DUMP(TRACE3("Protect 0x%08X (%d,%d)", g_RecentCIInfo[i].dwAddr, g_RecentCIInfo[i].dwWidth, g_RecentCIInfo[i].dwHeight)); |
963 | pinfo[5].width = g_RecentCIInfo[i].dwWidth; |
964 | pinfo[5].height = g_RecentCIInfo[i].dwHeight; |
965 | } |
966 | } |
967 | |
968 | pinfo[5].addr = g_ZI.dwAddr; |
969 | //pinfo->size = g_RecentCIInfo[5].dwSize; |
970 | pinfo[5].size = 2; |
971 | TXTRBUF_DETAIL_DUMP(TRACE3("Protect 0x%08X (%d,%d)", pinfo[5].addr, pinfo[5].width, pinfo[5].height)); |
972 | } |
973 | } |
974 | |
975 | // Plugin spec 1.3 functions |
976 | EXPORT void CALL ShowCFB(void) |
977 | { |
978 | status.toShowCFB = true; |
979 | } |
980 | |
981 | //void ReadScreen2( void *dest, int *width, int *height, int bFront ) |
982 | EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int bFront) |
983 | { |
984 | if (width == NULL || height == NULL) |
985 | return; |
986 | |
987 | *width = windowSetting.uDisplayWidth; |
988 | *height = windowSetting.uDisplayHeight; |
989 | |
990 | if (dest == NULL) |
991 | return; |
992 | |
993 | #if SDL_VIDEO_OPENGL |
994 | GLint oldMode; |
995 | glGetIntegerv( GL_READ_BUFFER, &oldMode ); |
996 | if (bFront) |
997 | glReadBuffer( GL_FRONT ); |
998 | else |
999 | glReadBuffer( GL_BACK ); |
1000 | glReadPixels( 0, 0, windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, |
1001 | GL_RGB, GL_UNSIGNED_BYTE, dest ); |
1002 | glReadBuffer( oldMode ); |
1003 | #endif |
1004 | } |
1005 | |
1006 | |
1007 | EXPORT void CALL SetRenderingCallback(void (*callback)(int)) |
1008 | { |
1009 | renderCallback = callback; |
1010 | } |
1011 | |
1012 | #ifdef __cplusplus |
1013 | } |
1014 | #endif |
1015 | |