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