· 4 years ago · Jun 27, 2021, 02:22 PM
1// ;..\..\portaudio\lib\portaudio_x86.lib
2
3#include "cbase.h"
4#include "aa_globals.h"
5
6//#include "aa_globals.h"
7#include "c_libretroinstance.h"
8#include "c_anarchymanager.h"
9#include "../../../public/vgui_controls/Controls.h"
10#include "vgui/IInput.h"
11#include "c_canvasregen.h"
12#include "c_embeddedinstance.h"
13//#include "pixelwriter.h"
14
15#include "../../public/bitmap/tgawriter.h"
16#include "../../public/pixelwriter.h"
17
18#include <algorithm>
19
20#include "XUnzip.h"
21
22#include <mutex>
23
24#include <glm/glm.hpp>
25
26// memdbgon must be the last include file in a .cpp file!!!
27#include "tier0/memdbgon.h"
28
29//bool C_LibretroInstance::s_bSoundInitialized = false;
30
31inline const char* WebStringToCharString3(WebString web_string)
32{
33 int len = web_string.ToUTF8(null, 0);
34 char* buf = new char[len + 1];
35 web_string.ToUTF8(buf, len);
36 buf[len] = 0; // null terminator
37
38 std::string title = buf;
39 delete[] buf;
40
41 return VarArgs("%s", title.c_str());
42}
43
44C_LibretroInstance::C_LibretroInstance()
45{
46 DevMsg("LibretroInstance: Constructor\n");
47 //m_pHud = null;// g_pAnarchyManager->GetAwesomiumBrowserManager()->FindAwesomiumBrowserInstance("hud");
48 m_bIsDirty = false;
49 m_iAdjustedStartTime = -1;
50 m_iLastDelta = 0; // for fast forwarding fake input
51 //m_bAudioIsPlaying = false;
52 m_pProjectorFixConVar = null;
53 m_pTexture = null;
54 m_iLastRenderedFrame = -1;
55 m_iLastVisibleFrame = -1;
56 m_iOriginalEntIndex = -1;
57 m_bGotTime = false;
58
59 //m_iCurrentSeconds = 0;
60 m_iFastForwardSeconds = 0;// 2000;
61
62 m_fLastMouseX = 0.5;
63 m_fLastMouseY = 0.5;
64
65 m_pLocalVideoBehaviorConVar = cvar->FindVar("local_video_behavior");
66
67 m_bShouldReopen = false;
68 m_info = null;
69
70 //m_pOverlayKV = null;
71 m_pOverlayKV = new KeyValues("overlay");
72
73 //{
74 //std::string id = "PANASONIC.DARK.cfg";
75 //if (id.length() < 5)
76 //id = id.substr(0, id.length() - 4);
77 //}
78 //m_fPositionX = 0.25;// 0;
79 //m_fPositionY = 0.25;// 0;
80 //m_fSizeX = 0.5;// 1;
81 //m_fSizeY = 0.5;// 1;
82 //m_pOverlayKV->deleteThis();
83// m_pOpenGLManager = null;
84}
85
86C_LibretroInstance::~C_LibretroInstance()
87{
88 DevMsg("LibretroInstance: Destructor\n");
89 this->CleanUpTexture();
90}
91
92void C_LibretroInstance::ClearOverlay(std::string type, std::string overlayId)
93{
94 std::string folder = "resource\\ui\\html\\overlays";
95 g_pFullFileSystem->CreateDirHierarchy(folder.c_str(), "DEFAULT_WRITE_PATH");
96 std::string file = VarArgs("%s\\%s.cfg", folder.c_str(), overlayId.c_str());
97
98 //m_pOverlayKV
99 std::string prettyCore = m_info->prettycore;
100 std::string prettyGame = m_info->prettygame;
101 KeyValues* pDefaultKV = m_pOverlayKV->FindKey("settings/default", true);
102 KeyValues* pTargetKV = null;
103
104 std::string testerCore;
105 std::string testerGame;
106 for (KeyValues *sub = m_pOverlayKV->FindKey("settings", true)->GetFirstSubKey(); sub; sub = sub->GetNextKey())
107 {
108 if (!Q_stricmp(sub->GetName(), "default"))
109 continue;
110
111 testerCore = sub->GetString("core");
112 testerGame = sub->GetString("game");
113
114 if (type == "core" && testerCore == prettyCore && testerGame == "")
115 pTargetKV = sub;
116 else if (testerCore == prettyCore && testerGame == prettyGame && type == "game")
117 {
118 pTargetKV = sub;
119 break;
120 }
121 }
122
123 if (pTargetKV)
124 {
125 pTargetKV->Clear();
126 pTargetKV->SetString(null, "");
127
128 if (!m_pOverlayKV->SaveToFile(g_pFullFileSystem, file.c_str(), "DEFAULT_WRITE_PATH"))
129 DevMsg("ERROR: Could not wite file %s\n", file.c_str());
130
131 this->SetOverlay(overlayId);
132 }
133}
134
135void C_LibretroInstance::SaveOverlay(std::string type, std::string overlayId, float x, float y, float width, float height)
136{
137 /*
138 if (overlayId == "none")
139 {
140 x = 0;
141 y = 0;
142 width = 1;
143 height = 1;
144 }
145 */
146
147 std::string folder = "resource\\ui\\html\\overlays";
148 g_pFullFileSystem->CreateDirHierarchy(folder.c_str(), "DEFAULT_WRITE_PATH");
149 std::string file = VarArgs("%s\\%s.cfg", folder.c_str(), overlayId.c_str());
150
151 //m_pOverlayKV
152 std::string prettyCore = m_info->prettycore;
153 std::string prettyGame = m_info->prettygame;
154 std::string preferredOverlayId = g_pAnarchyManager->GetLibretroManager()->DetermineOverlay(prettyCore, prettyGame);
155 KeyValues* pDefaultKV = m_pOverlayKV->FindKey("settings/default", true);
156 KeyValues* pCoreKV = null;
157 KeyValues* pGameKV = null;
158 //KeyValues* pTargetKV = null;
159
160 std::string testerCore;
161 std::string testerGame;
162 for (KeyValues *sub = m_pOverlayKV->FindKey("settings", true)->GetFirstSubKey(); sub; sub = sub->GetNextKey())
163 {
164 if (!Q_stricmp(sub->GetName(), "default"))
165 continue;
166
167 testerCore = sub->GetString("core");
168 testerGame = sub->GetString("game");
169
170 if (testerCore == prettyCore && testerGame == "")
171 pCoreKV = sub;
172 else if (testerCore == prettyCore && testerGame == prettyGame)
173 pGameKV = sub;
174 /*
175 if ((type == "core" || type == "default") && testerCore == prettyCore && testerGame == "")
176 pTargetKV = sub;
177 else if (testerCore == prettyCore && testerGame == prettyGame && (type == "game" || type == "default"))
178 {
179 pTargetKV = sub;
180 break;
181 }
182 */
183 }
184
185 if (type == "game")
186 {
187 if (!pGameKV)
188 {
189 pGameKV = m_pOverlayKV->FindKey("settings", true)->CreateNewKey();
190 pGameKV->SetName("setting");
191 pGameKV->SetString("core", prettyCore.c_str());
192 pGameKV->SetString("game", prettyGame.c_str());
193 }
194
195 pGameKV->SetFloat("x", x);
196 pGameKV->SetFloat("y", y);
197 pGameKV->SetFloat("width", width);
198 pGameKV->SetFloat("height", height);
199 }
200 else if (type == "core")
201 {
202 if (!pCoreKV)
203 {
204 pCoreKV = m_pOverlayKV->FindKey("settings", true)->CreateNewKey();
205 pCoreKV->SetName("setting");
206 pCoreKV->SetString("core", prettyCore.c_str());
207 }
208
209 pCoreKV->SetFloat("x", x);
210 pCoreKV->SetFloat("y", y);
211 pCoreKV->SetFloat("width", width);
212 pCoreKV->SetFloat("height", height);
213 }
214 else if (type == "default")
215 {
216 pDefaultKV->SetFloat("x", x);
217 pDefaultKV->SetFloat("y", y);
218 pDefaultKV->SetFloat("width", width);
219 pDefaultKV->SetFloat("height", height);
220 }
221
222 if (preferredOverlayId == overlayId)
223 {
224 m_pOverlayKV->SetFloat("current/x", x);
225 m_pOverlayKV->SetFloat("current/y", y);
226 m_pOverlayKV->SetFloat("current/width", width);
227 m_pOverlayKV->SetFloat("current/height", height);
228 }
229
230 if (!m_pOverlayKV->SaveToFile(g_pFullFileSystem, file.c_str(), "DEFAULT_WRITE_PATH"))
231 DevMsg("ERROR: Could not wite file %s\n", file.c_str());
232
233 if (g_pAnarchyManager->GetInputManager()->GetEmbeddedInstance() == this)
234 {
235 vgui::CInputSlate* pInputSlate = g_pAnarchyManager->GetInputManager()->GetInputSlate();
236 if (pInputSlate)
237 pInputSlate->AdjustOverlay(m_pOverlayKV->GetFloat("current/x", 0), m_pOverlayKV->GetFloat("current/y", 0), m_pOverlayKV->GetFloat("current/width", 1), m_pOverlayKV->GetFloat("current/height", 1), m_overlayId);
238 }
239}
240
241void C_LibretroInstance::SetOverlay(std::string overlayId)
242{
243 if (!m_info)
244 return;
245
246 std::string goodOverlayId = overlayId;
247
248 std::string prettyCore = m_info->prettycore;
249 std::string prettyGame = m_info->prettygame;
250
251 std::string preferredOverlayId = g_pAnarchyManager->GetLibretroManager()->DetermineOverlay(prettyCore, prettyGame);
252 //return;
253 //if (preferredOverlayId != goodOverlayId)
254 //return;
255 goodOverlayId = preferredOverlayId;
256
257 if (m_pOverlayKV)
258 m_pOverlayKV->Clear();
259
260 //m_overlayId = goodOverlayId;
261 if (goodOverlayId != "" && goodOverlayId != "none" && m_pOverlayKV->LoadFromFile(g_pFullFileSystem, VarArgs("resource\\ui\\html\\overlays\\%s.cfg", goodOverlayId.c_str()), "MOD"))
262 {
263 //m_overlayId = overlayId;
264 //m_pOverlayKV->SetString("current/overlayId", overlayId.c_str());
265
266 std::string testerCore;
267 std::string testerGame;
268
269 KeyValues* pDefaultOverlayKV = m_pOverlayKV->FindKey("settings/default");
270 if (!pDefaultOverlayKV)
271 {
272 pDefaultOverlayKV = m_pOverlayKV->FindKey("settings/default", true);
273 pDefaultOverlayKV->SetFloat("x", 0);
274 pDefaultOverlayKV->SetFloat("y", 0);
275 pDefaultOverlayKV->SetFloat("width", 1);
276 pDefaultOverlayKV->SetFloat("height", 1);
277 }
278
279 //KeyValues* pBestOverlayKV = null;
280 KeyValues* pCoreOverlayKV = null;
281 KeyValues* pGameOverlayKV = null;
282 for (KeyValues *sub = m_pOverlayKV->FindKey("settings", true)->GetFirstSubKey(); sub; sub = sub->GetNextKey())
283 {
284 if (sub == pDefaultOverlayKV)
285 continue;
286
287 testerCore = sub->GetString("core");
288 testerGame = sub->GetString("game");
289
290 if (testerCore == prettyCore && testerGame == "")
291 pCoreOverlayKV = sub;
292 else if (testerCore == prettyCore && testerGame == prettyGame)
293 pGameOverlayKV = sub;
294 }
295
296 KeyValues* pBestOverlayKV = (pGameOverlayKV) ? pGameOverlayKV : pCoreOverlayKV;
297 if (!pBestOverlayKV)
298 pBestOverlayKV = pDefaultOverlayKV;
299
300 if (preferredOverlayId == goodOverlayId)
301 {
302 m_pOverlayKV->SetFloat("current/x", pBestOverlayKV->GetFloat("x", 0));
303 m_pOverlayKV->SetFloat("current/y", pBestOverlayKV->GetFloat("y", 0));
304 m_pOverlayKV->SetFloat("current/width", pBestOverlayKV->GetFloat("width", 1));
305 m_pOverlayKV->SetFloat("current/height", pBestOverlayKV->GetFloat("height", 1));
306 }
307 }
308 else
309 {
310 m_pOverlayKV->SetFloat("current/x", 0);
311 m_pOverlayKV->SetFloat("current/y", 0);
312 m_pOverlayKV->SetFloat("current/width", 1);
313 m_pOverlayKV->SetFloat("current/height", 1);
314 }
315
316 if ( g_pAnarchyManager->GetInputManager()->GetEmbeddedInstance() == this)
317 {
318 vgui::CInputSlate* pInputSlate = g_pAnarchyManager->GetInputManager()->GetInputSlate();
319 if (pInputSlate)
320 pInputSlate->AdjustOverlay(m_pOverlayKV->GetFloat("current/x", 0), m_pOverlayKV->GetFloat("current/y", 0), m_pOverlayKV->GetFloat("current/width", 1), m_pOverlayKV->GetFloat("current/height", 1), goodOverlayId);
321 }
322
323 m_overlayId = goodOverlayId;
324}
325
326void C_LibretroInstance::SelfDestruct()
327{
328 DevMsg("LibretroInstance: SelfDestruct\n");
329
330 if (g_pAnarchyManager->ShouldAllowMultipleActive() && g_pAnarchyManager->IsLevelInitialized())
331 {
332 C_BaseEntity* pOriginalEntity = C_BaseEntity::Instance(m_iOriginalEntIndex);
333 if (pOriginalEntity)
334 {
335 C_PropShortcutEntity* pShortcut = dynamic_cast<C_PropShortcutEntity*>(pOriginalEntity);
336 pShortcut->PlaySequenceRegular("deactivated");
337 }
338 }
339
340 if (g_pAnarchyManager->GetCanvasManager()->GetDisplayInstance() == this)
341 g_pAnarchyManager->GetCanvasManager()->SetDifferentDisplayInstance(this);
342
343 g_pAnarchyManager->GetCanvasManager()->GetOrCreateRegen()->NotifyInstanceAboutToDie(this);
344 g_pAnarchyManager->GetCanvasManager()->RenderUnseen(this);
345
346 if (m_info)
347 {
348 m_info->libretroinstance = null;
349 m_info->close = true;
350 }
351
352 if (m_pOverlayKV)
353 m_pOverlayKV->deleteThis();
354 /*
355 if (m_pLastFrameData)
356 free(m_pLastFrameData);
357
358 if (m_pPostData)
359 free(m_pPostData);
360 */
361
362 engine->ClientCmd("exec 360controller");
363 delete this;
364}
365
366void C_LibretroInstance::CleanUpTexture()
367{
368 if (m_pTexture)
369 {
370 m_pTexture->SetTextureRegenerator(null);
371
372 // save the last rendered image out as a TGA to use as a thumbnail
373 if (m_info->lastframedata && !g_pAnarchyManager->GetCanvasManager()->GetItemTexture(m_originalItemId, "screen")) // Note: This makes it so "always_refresh_snapshots" is useless.
374 {
375 std::string filePath = "cache/snapshots";
376 std::string fileName = filePath + "/";
377 fileName += g_pAnarchyManager->GenerateLegacyHash(m_originalGame.c_str());
378 fileName += ".tga";
379
380 if (cvar->FindVar("always_refresh_snapshots")->GetBool() || !g_pFullFileSystem->FileExists(fileName.c_str(), "DEFAULT_WRITE_PATH"))
381 {
382 unsigned int depth = 4;
383 unsigned int width = AA_THUMBNAIL_SIZE;
384 unsigned int height = AA_THUMBNAIL_SIZE;
385 unsigned int bufferSize = width * height * depth;
386 unsigned int pitch = width * depth;
387
388 // Get the data from the render target and save to disk bitmap bits
389 unsigned char *pImage = (unsigned char *)malloc(width * height * depth);
390
391
392 //this->ResizeFrameFromRGB888(m_info->lastframedata, pImage, m_info->lastframewidth, m_info->lastframeheight, m_info->lastframepitch, m_info->depth, width, height, pitch, depth);
393
394 if (m_info->videoformat == RETRO_PIXEL_FORMAT_RGB565)
395 this->ResizeFrameFromRGB565(m_info->lastframedata, pImage, m_info->lastframewidth, m_info->lastframeheight, m_info->lastframepitch, 3, width, height, pitch, depth);
396 else if (m_info->videoformat == RETRO_PIXEL_FORMAT_XRGB8888)
397 this->ResizeFrameFromXRGB8888(m_info->lastframedata, pImage, m_info->lastframewidth, m_info->lastframeheight, m_info->lastframepitch, 4, width, height, pitch, depth);
398 else
399 this->ResizeFrameFromRGB1555(m_info->lastframedata, pImage, m_info->lastframewidth, m_info->lastframeheight, m_info->lastframepitch, 3, width, height, pitch, depth);
400
401 // allocate a buffer to write the tga into
402 int iMaxTGASize = (width * height * depth); // + 1024
403 void *pTGA = malloc(iMaxTGASize);
404 CUtlBuffer buffer(pTGA, iMaxTGASize);
405
406 if (m_info->videoformat == RETRO_PIXEL_FORMAT_RGB565)
407 {
408 if (!TGAWriter::WriteToBuffer(pImage, buffer, width, height, IMAGE_FORMAT_RGB565, IMAGE_FORMAT_RGBA8888))
409 DevMsg("Couldn't write bitmap data.\n");
410 }
411 else if (m_info->videoformat == RETRO_PIXEL_FORMAT_XRGB8888)
412 {
413 if (!TGAWriter::WriteToBuffer(pImage, buffer, width, height, IMAGE_FORMAT_BGRA8888, IMAGE_FORMAT_RGBA8888))
414 DevMsg("Couldn't write bitmap data.\n");
415 }
416 else
417 {
418 if (!TGAWriter::WriteToBuffer(pImage, buffer, width, height, IMAGE_FORMAT_BGRX5551, IMAGE_FORMAT_RGBA8888))
419 DevMsg("Couldn't write bitmap data.\n");
420 }
421
422 free(pImage);
423
424 // save the TGA out
425 g_pFullFileSystem->CreateDirHierarchy(filePath.c_str(), "DEFAULT_WRITE_PATH");
426
427 FileHandle_t fileTGA = filesystem->OpenEx(fileName.c_str(), "wb", 0, "DEFAULT_WRITE_PATH");
428 filesystem->Write(buffer.Base(), buffer.TellPut(), fileTGA);
429 filesystem->Close(fileTGA);
430 free(pTGA);
431
432 std::string mode = "ALL";
433 g_pAnarchyManager->GetCanvasManager()->PrepareRefreshItemTextures(m_originalItemId, mode);
434 g_pAnarchyManager->GetCanvasManager()->RefreshItemTextures(m_originalItemId, mode);
435 }
436 }
437 // now continue with regular stuff
438
439 DevMsg("Unref texture from: C_LibretroInstance::CleanUpTexture\n");
440 g_pAnarchyManager->GetCanvasManager()->UnreferenceEmbeddedInstance(this);
441 g_pAnarchyManager->GetCanvasManager()->UnreferenceTexture(m_pTexture);
442 g_pAnarchyManager->GetCanvasManager()->DoOrDeferTextureCleanup(m_pTexture);
443 m_pTexture = null;
444 }
445}
446
447void C_LibretroInstance::OnMouseMove(float x, float y)
448{
449 //unsigned int width = (m_id == "hud") ? AA_HUD_INSTANCE_WIDTH : AA_EMBEDDED_INSTANCE_WIDTH;
450 //unsigned int height = (m_id == "hud") ? AA_HUD_INSTANCE_HEIGHT : AA_EMBEDDED_INSTANCE_HEIGHT;
451
452 //int goodX = (width * x) / 1;
453 //int goodY = (height * y) / 1;
454 m_fLastMouseX = x;
455 m_fLastMouseY = y;
456
457 //steamapicontext->SteamHTMLSurface()->MouseMove(m_unHandle, goodX, goodY);
458}
459
460void C_LibretroInstance::Init(std::string id, std::string title, int iEntIndex)
461{
462 this->SetAdjustedStartTime();
463
464 //m_pHud = g_pAnarchyManager->GetAwesomiumBrowserManager()->FindAwesomiumBrowserInstance("hud");
465
466 std::string goodTitle = (title != "") ? title : "Untitled Libretro Tab";
467 m_title = goodTitle;
468 m_id = id;
469 if (m_id == "")
470 m_id = g_pAnarchyManager->GenerateUniqueId();
471
472 m_iOriginalEntIndex = iEntIndex;
473
474 m_pProjectorFixConVar = cvar->FindVar("projector_fix");
475
476 // create the texture (each instance has its own texture)
477 std::string textureName = "canvas_";
478 textureName += m_id;
479
480 int iWidth = (id == "hud") ? AA_HUD_INSTANCE_WIDTH : AA_EMBEDDED_INSTANCE_WIDTH;
481 int iHeight = (id == "hud") ? AA_HUD_INSTANCE_HEIGHT : AA_EMBEDDED_INSTANCE_HEIGHT;
482
483 int flags = (0x0100 | 0x0200 | 0x0800 | 0x2000000);
484
485 if (g_pAnarchyManager->ShouldTextureClamp())
486 flags |= (0x0004 | 0x0008);
487
488 //int iWidth = 1920;
489 //int iHeight = 1080;
490
491 //m_pTexture = g_pMaterialSystem->FindTexture(textureName.c_str(), TEXTURE_GROUP_VGUI, false, 1);
492
493 //if (!m_pTexture)
494
495 int multiplyer = 1.0;// g_pAnarchyManager->GetDynamicMultiplyer();
496 if (!g_pMaterialSystem->IsTextureLoaded(textureName.c_str()))
497 m_pTexture = g_pMaterialSystem->CreateProceduralTexture(textureName.c_str(), TEXTURE_GROUP_VGUI, iWidth * multiplyer, iHeight * multiplyer, IMAGE_FORMAT_BGR888, flags);
498 else
499 {
500 m_pTexture = g_pMaterialSystem->FindTexture(textureName.c_str(), TEXTURE_GROUP_VGUI, false, 1);
501 g_pAnarchyManager->GetCanvasManager()->TextureNotDeferred(m_pTexture);
502 }
503
504 // get the regen and assign it
505 CCanvasRegen* pRegen = g_pAnarchyManager->GetCanvasManager()->GetOrCreateRegen();
506 //pRegen->SetEmbeddedInstance(this);
507 m_pTexture->SetTextureRegenerator(pRegen);
508
509 m_raw = new libretro_raw();
510
511 engine->ClientCmd("exec strip_controller");
512
513 if (m_iOriginalEntIndex >= 0 && g_pAnarchyManager->ShouldAllowMultipleActive() && g_pAnarchyManager->IsLevelInitialized())
514 {
515 C_BaseEntity* pBaseEntity = C_BaseEntity::Instance(m_iOriginalEntIndex);
516 if (pBaseEntity)
517 {
518 C_PropShortcutEntity* pShortcut = dynamic_cast<C_PropShortcutEntity*>(pBaseEntity);
519 if (pShortcut)
520 pShortcut->PlaySequenceRegular("activated");
521 }
522 }
523}
524
525/*
526void C_LibretroInstance::Reinit()
527{
528 //LibretroInstanceInfo_t* pLibretroInstanceInfo = pLibretroInstance->GetInfo();
529}
530*/
531
532void C_LibretroInstance::Update()
533{
534 if (g_pAnarchyManager->GetSuspendEmbedded() && m_id != "init" )
535 return;
536
537 if (m_info->state == 1)
538 {
539 OnCoreLoaded();
540 }
541 else if (m_info->state == 5 )// && m_info->audiostream) // added m_info to try and detect failed video loads!! (FIXME: Should be removed after proper failed video load is added elsewhere.
542 {
543 unsigned int numPorts = m_info->numports;
544 if (numPorts == 0)
545 {
546 // how the funnuck are we supposd to know how many input ports need to be held in the input back buffer if the core doesn't tell us?? just assume 1 for now.
547 //DevMsg("WARNING: zero retro ports are active.\n");
548 numPorts = 1;
549 }
550
551 for (unsigned int i = 0; i < numPorts; i++)
552 g_pAnarchyManager->GetLibretroManager()->ManageInputUpdate(m_info, i, RETRO_DEVICE_JOYPAD);
553
554 /*
555 // update input state
556 m_info->inputstate["RETRO_DEVICE_ID_JOYPAD_SELECT"] = vgui::input()->IsKeyDown(KEY_XBUTTON_BACK);
557 m_info->inputstate["RETRO_DEVICE_ID_JOYPAD_START"] = vgui::input()->IsKeyDown(KEY_XBUTTON_START) || vgui::input()->IsKeyDown(KEY_ENTER);
558 m_info->inputstate["RETRO_DEVICE_ID_JOYPAD_UP"] = vgui::input()->IsKeyDown(KEY_XBUTTON_UP);
559 m_info->inputstate["RETRO_DEVICE_ID_JOYPAD_DOWN"] = vgui::input()->IsKeyDown(KEY_XBUTTON_DOWN);
560 m_info->inputstate["RETRO_DEVICE_ID_JOYPAD_LEFT"] = vgui::input()->IsKeyDown(KEY_XBUTTON_LEFT);
561 m_info->inputstate["RETRO_DEVICE_ID_JOYPAD_RIGHT"] = vgui::input()->IsKeyDown(KEY_XBUTTON_RIGHT);
562 m_info->inputstate["RETRO_DEVICE_ID_JOYPAD_A"] = vgui::input()->IsKeyDown(KEY_XBUTTON_B);
563 m_info->inputstate["RETRO_DEVICE_ID_JOYPAD_B"] = vgui::input()->IsKeyDown(KEY_XBUTTON_A);
564 m_info->inputstate["RETRO_DEVICE_ID_JOYPAD_X"] = vgui::input()->IsKeyDown(KEY_XBUTTON_Y);
565 m_info->inputstate["RETRO_DEVICE_ID_JOYPAD_Y"] = vgui::input()->IsKeyDown(KEY_XBUTTON_X);
566 m_info->inputstate["RETRO_DEVICE_ID_JOYPAD_L"] = vgui::input()->IsKeyDown(KEY_XBUTTON_LEFT_SHOULDER);
567 m_info->inputstate["RETRO_DEVICE_ID_JOYPAD_R"] = vgui::input()->IsKeyDown(KEY_XBUTTON_RIGHT_SHOULDER);
568 */
569
570 if (!m_bGotTime)
571 {
572 m_bGotTime = true;
573
574 // only if local videos should resume are enabled
575 if (m_pLocalVideoBehaviorConVar->GetInt() == 1 && m_info->core.find("ffmpeg") != std::string::npos && m_id != "init")
576 {
577 C_AwesomiumBrowserInstance* pNetwork = g_pAnarchyManager->GetAwesomiumBrowserManager()->FindAwesomiumBrowserInstance("network");// static_cast<C_AwesomiumBrowserInstance*>(m_pHudVoid);
578 if (pNetwork)
579 {
580 //DevMsg("Game Hash: %s\n", m_originalGameHash.c_str());
581 //"window.innerWidth"), WSLit(""));
582 JSValue result = pNetwork->GetWebView()->ExecuteJavascriptWithResult(WSLit(VarArgs("localStorage.getItem(\"libtime%s\");", m_originalGameHash.c_str())), WSLit(""));
583 if (!result.IsNull() && result.IsString())
584 {
585 int secs = Q_atoi(WebStringToCharString3(result.ToString()));
586 if (secs > 0)
587 {
588 DevMsg("AArcade skipping to %s seconds...\n", WebStringToCharString3(result.ToString()));
589 this->SetFastForwardSeconds(Q_atoi(WebStringToCharString3(result.ToString())));
590 }
591 }
592 }
593 }
594 }
595
596 this->OnProxyBind(null);
597
598 /*
599 if (m_raw)
600 {
601 DevMsg("LibretroInstance: Update\n");
602 //m_raw->run();
603 DevMsg("after\n");
604 }
605 */
606 }
607 else if (m_info->state == 6)
608 {
609 // even though the core wants to close, don't do anything at all. the core will keep waiting until the user closes this C_LibretroInstance like normal.
610 if (m_id == "init")
611 g_pAnarchyManager->GetLibretroManager()->DestroyLibretroInstance(this);
612 }
613}
614
615bool C_LibretroInstance::LoadCore(std::string coreFile)
616{
617 if (coreFile != "")
618 {
619 // first check for cores in the user folder, then check for cores in the frontend folder.
620
621 bool bReady = false;
622 std::string core = g_pAnarchyManager->GetLibretroManager()->GetLibretroPath(RETRO_USER_BASE) + g_pAnarchyManager->GetLibretroManager()->GetLibretroPath(RETRO_CORE_PATH) + std::string("\\") + coreFile;
623 if (g_pFullFileSystem->FileExists(core.c_str()))
624 bReady = true;
625 else
626 {
627 core = engine->GetGameDirectory() + g_pAnarchyManager->GetLibretroManager()->GetLibretroPath(RETRO_CORE_PATH) + std::string("\\") + coreFile;
628 if (g_pFullFileSystem->FileExists(core.c_str()))
629 bReady = true;
630 }
631
632 if ( bReady )
633 {
634 //g_pAnarchyManager->AddToastMessage(VarArgs("Libretro Core Opened (%i running)", g_pAnarchyManager->GetLibretroManager()->GetInstanceCount()));
635 CreateWorkerThread(core);
636 return true;
637 }
638 }
639
640 g_pAnarchyManager->AddToastMessage("Libretro Core Aborted");
641 return false;
642 /*
643
644 // struct retro_system_info info;
645 // s_raw->get_system_info(&info);
646
647 Msg("Successfully loaded libretro module at %s in %i milliseconds.\n", pFilename, pClientArcadeResources->GetSystemTime() - startTime);
648 s_bCoreIsLoaded = true;
649 */
650}
651
652void C_LibretroInstance::OnGameLoaded()
653{
654 DevMsg("Game finished loading.\n");
655
656 //m_info->state = 5;
657}
658
659
660std::string C_LibretroInstance::GetLibretroCore()
661{
662 if (m_info)
663 return m_info->core;
664 else
665 return "";
666}
667
668std::string C_LibretroInstance::GetLibretroFile()
669{
670 if (m_info)
671 return m_info->game;
672 else
673 return "";
674}
675
676void C_LibretroInstance::SetReset(bool bValue)
677{
678 // reset the seconds stats too
679 m_iLastDelta = 0;
680 m_iFastForwardSeconds = 0;
681 m_iAdjustedStartTime = static_cast<int>(ceil(engine->Time()));
682 C_AwesomiumBrowserInstance* pNetwork = g_pAnarchyManager->GetAwesomiumBrowserManager()->FindAwesomiumBrowserInstance("network");
683 if (pNetwork)
684 pNetwork->GetWebView()->ExecuteJavascript(WSLit(VarArgs("localStorage.setItem(\"libtime%s\", %i)", m_originalGameHash.c_str(), 0)), WSLit(""));
685
686 //this->OnSecondsUpdated();
687
688 if (m_info)
689 m_info->reset = bValue;
690}
691
692void C_LibretroInstance::SetPause(bool bValue)
693{
694 if (m_info)
695 m_info->paused = bValue;
696}
697
698void C_LibretroInstance::SetVolume(float fVolume)
699{
700 if (m_info)
701 m_info->volume = fVolume;
702}
703
704bool C_LibretroInstance::GetPause()
705{
706 if (!m_info)
707 return false;
708 else
709 return m_info->paused;
710}
711
712bool C_LibretroInstance::LoadGame()
713{
714 uint uId = ThreadGetCurrentId();
715 C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
716
717 if (!pLibretroInstance)
718 return false;
719
720 LibretroInstanceInfo_t* info = pLibretroInstance->GetInfo();
721
722 std::string filename = info->game;
723
724 // If this core *requires* a full file path, then we can check if the file extension is supported RIGHT NOW.
725 // OTHERWISE, we might have to open up a ZIP file before we can check the real file extension.
726
727 std::string fileExtension = filename;
728 std::transform(fileExtension.begin(), fileExtension.end(), fileExtension.begin(), ::tolower);
729 size_t extensionFound = fileExtension.find_last_of(".");
730 if (extensionFound != std::string::npos)
731 fileExtension = fileExtension.substr(extensionFound + 1);
732 else
733 fileExtension = "";
734
735 if (fileExtension == "")
736 {
737 DevMsg("libretro: ABORTED: The file has no file extension.\n");
738 //info->close = true;
739 return false;
740 }
741
742 // Format Example:
743 // valid_extensions: mkv|avi|f4v|f4f|3gp|ogm|flv|mp4|mp3|flac|ogg|m4a
744 std::string testerExtensions = info->valid_extensions;
745 std::transform(testerExtensions.begin(), testerExtensions.end(), testerExtensions.begin(), ::tolower);
746
747 std::vector<std::string> tokens;
748 g_pAnarchyManager->Tokenize(testerExtensions, tokens, "|");
749
750 bool bIsZip = (fileExtension == "zip");
751 bool bIsValidExtension = true;
752
753 // If this is NOT a ZIP (or if ZIP is a supported file extension for the core, OR(?) if the core requires fullpath) we can confirm validity RIGHT NOW.
754 if (info->need_fullpath || !bIsZip || std::find(tokens.begin(), tokens.end(), "zip") != tokens.end()) //info->need_fullpath
755 {
756 if (std::find(tokens.begin(), tokens.end(), fileExtension) != tokens.end())
757 DevMsg("Found extension %s within %s\n", fileExtension.c_str(), testerExtensions.c_str());
758 else
759 bIsValidExtension = false;
760 }
761
762 // FIXME: Why always pick this pixel format???
763 info->videoformat = RETRO_PIXEL_FORMAT_0RGB1555;
764
765 //s_bSupportsNoGame
766
767 void* fileData;
768 bool bDataLoaded = false;
769 bool bReadyToLoad = false;
770
771 struct retro_game_info game;
772 game.path = filename.c_str();
773
774 if (!bIsValidExtension)
775 {
776 DevMsg("libretro: ABORTED: Invalid file extension %s for this core. Valid extensions for %s are: %s\n", fileExtension.c_str(), info->prettycore.c_str(), testerExtensions.c_str());
777 //info->close = true;
778 }
779 else
780 {
781 if (info->need_fullpath)
782 {
783 game.data = NULL;
784 game.size = 0;
785 game.meta = NULL;
786
787 bReadyToLoad = true;
788 }
789 else
790 {
791 DevMsg("libretro: File must be loaded by frontend!\n");
792
793 // for easy char string access
794 //char pFilename[AA_MAX_STRING];
795 int iAAMaxString = filename.length() + 1;
796 char* pFilename = new char[iAAMaxString];
797 Q_strncpy(pFilename, filename.c_str(), iAAMaxString);
798
799 if (bIsZip)
800 {
801 DevMsg("libretro: ZIP file detected. Attempting to extract the 1st file..\n");
802
803 bool bFailedUnzip = false;
804 if (!g_pFullFileSystem->FileExists(filename.c_str()))
805 {
806 DevMsg("libretro: ABORTED: ZIP file does not exist %s\n", pFilename);
807 bFailedUnzip = true;
808 }
809 else
810 {
811 HZIP hz = OpenZip(pFilename, 0, ZIP_FILENAME);
812 if (!hz)
813 {
814 DevMsg("libretro: ABORTED: Failed to open ZIP file %s\n", pFilename);
815 bFailedUnzip = true;
816 }
817 else
818 {
819 int zipIndex = 0;
820 ZIPENTRY zipEntry;
821 ZRESULT result = GetZipItem(hz, zipIndex, &zipEntry);
822
823 std::string entryTesterExtension;
824 size_t entryExtensionFound;
825 bool bFoundFile = false;
826 while (result == ZR_OK)
827 {
828 if (zipEntry.attr & FILE_ATTRIBUTE_DIRECTORY)
829 {
830 zipIndex++;
831 result = GetZipItem(hz, zipIndex, &zipEntry);
832 continue;
833 }
834
835 if (testerExtensions == "")
836 bFoundFile = true;
837 else
838 {
839 entryTesterExtension = zipEntry.name;
840 std::transform(entryTesterExtension.begin(), entryTesterExtension.end(), entryTesterExtension.begin(), ::tolower);
841 entryExtensionFound = entryTesterExtension.find_last_of(".");
842 if (entryExtensionFound != std::string::npos)
843 entryTesterExtension = entryTesterExtension.substr(entryExtensionFound + 1);
844 else
845 entryTesterExtension = "";
846
847 if (entryTesterExtension != "" && std::find(tokens.begin(), tokens.end(), entryTesterExtension) != tokens.end())
848 bFoundFile = true;
849 }
850
851 if (bFoundFile)
852 break;
853 }
854
855 if (!bFoundFile || result != ZR_OK)
856 {
857 DevMsg("libretro: ABORTED: Failed to locate a valid file in ZIP.");
858 bFailedUnzip = true;
859 }
860 else
861 {
862 long fileSize = zipEntry.unc_size;
863 fileData = malloc(fileSize);
864 bDataLoaded = true;
865
866 result = UnzipItem(hz, zipIndex, fileData, fileSize, ZIP_MEMORY);
867
868 if (result != ZR_OK && result != ZR_MORE)
869 {
870 DevMsg("libretro: ABORTED: Failed to unzip the file. ERROR CODE %i\n", result);
871 bFailedUnzip = true;
872 }
873 else
874 {
875 game.data = fileData;
876 game.size = fileSize;
877 game.meta = NULL;
878
879 bReadyToLoad = true;
880 }
881 }
882
883 CloseZip(hz);
884 }
885 }
886
887 // if bFailedUnzip is false, we have failed to unzip.
888 }
889 else
890 {
891 game.data = NULL;
892 game.size = 0;
893 game.meta = NULL;
894
895 FileHandle_t fileHandle = filesystem->Open(pFilename, "rb");
896 if (!fileHandle)
897 {
898 DevMsg("libretro: ABORTED: Failed to open file %s\n", pFilename);
899 //info->close = true;
900 }
901 else
902 {
903 int bufferSize = filesystem->Size(fileHandle);
904 fileData = malloc(bufferSize);
905 bDataLoaded = true;
906
907 filesystem->Read(fileData, bufferSize, fileHandle);
908 filesystem->Close(fileHandle);
909
910 game.data = fileData;
911 game.size = bufferSize;
912
913 bReadyToLoad = true;
914 }
915 }
916
917 delete[] pFilename;
918 }
919 }
920
921 bool bSuccess = false;
922 if (bReadyToLoad)
923 {
924 // load any existing save state
925 //if (g_pFullFileSystem->FileExists(VarArgs("%s\\%s\\%s.sav", info->savepath.c_str(), info->prettycore.c_str(), info->prettygame.c_str())))
926 //{
927 if (info->settings && info->settings->GetBool("statesaves"))
928 {
929 FileHandle_t fileHandle = filesystem->Open(VarArgs("%s\\%s\\%s.sav", info->savepath.c_str(), info->prettycore.c_str(), info->prettygame.c_str()), "rb", "");
930 if (fileHandle)
931 {
932 info->statesize = filesystem->Size(fileHandle); // statesize remains ZERO if game was loaded state saves disabled. this prevents erroneous cleanup.
933 info->statedata = malloc(info->statesize);
934 filesystem->Read(info->statedata, info->statesize, fileHandle);
935 filesystem->Close(fileHandle);
936 }
937 }
938 //}
939
940 info->raw->init(); // could take a while
941
942 if (info->close) // somebody else could have closed us from a different thread while we were doing that bottleneck above
943 {
944 DevMsg("libretro: ABORTED: Canceled before loading game.\n");
945 //info->close = true;
946 }
947 else
948 {
949 if (!info->raw->load_game(&game))
950 {
951 DevMsg("libretro: ABORTED: Core could not load game.\n");
952 //info->close = true;
953 }
954 else
955 {
956 DevMsg("libretro: Finished loading game %s\n", filename.c_str());
957
958 if (!info->close)
959 {
960 info->state = 5;
961 bSuccess = true;
962 }
963 else
964 {
965 DevMsg("libretro: ABORTED: Canceled while loading game.\n");
966 bSuccess = false;
967 //info->close = true;
968 }
969 }
970 }
971 }
972
973 if (bDataLoaded)
974 free(fileData);
975
976 //pLibretroInstance->OnGameLoaded();
977 return bSuccess;
978}
979
980void C_LibretroInstance::OnCoreLoaded()
981{
982 DevMsg("Core finished loading!\n");
983 m_info->state = 2;
984
985 // automatically load a game right away...
986// m_info->game = "V:/Movies/Flash Gordon (1980).avi";//file
987 //m_info->game = "V:/Movies/Jay and silent Bob Strike Back (2001).avi";
988 //"V:\\Movies\\Judge Dredd (1995).mp4";
989}
990
991//bool C_LibretroManager::BuildInterface(void* pLib, struct libretro_raw * myInterface)
992bool C_LibretroInstance::BuildInterface(libretro_raw* raw, void* pLib)
993{
994 HMODULE hModule = *static_cast<HMODULE*>(pLib);
995
996 //void(*get_system_info)(struct retro_system_info * info);
997
998 // check if this is a libretro core...
999 if (!GetProcAddress(hModule, "retro_get_system_info"))
1000 return false;
1001
1002 raw->set_environment = (void(*)(retro_environment_t))GetProcAddress(hModule, "retro_set_environment");
1003 raw->set_video_refresh = (void(*)(retro_video_refresh_t))GetProcAddress(hModule, "retro_set_video_refresh");
1004 raw->set_audio_sample = (void(*)(retro_audio_sample_t))GetProcAddress(hModule, "retro_set_audio_sample");
1005 raw->set_audio_sample_batch = (void(*)(retro_audio_sample_batch_t))GetProcAddress(hModule, "retro_set_audio_sample_batch");
1006 raw->set_input_poll = (void(*)(retro_input_poll_t))GetProcAddress(hModule, "retro_set_input_poll");
1007 raw->set_input_state = (void(*)(retro_input_state_t))GetProcAddress(hModule, "retro_set_input_state");
1008 raw->init = (void(*)(void))GetProcAddress(hModule, "retro_init");
1009 raw->deinit = (void(*)(void))GetProcAddress(hModule, "retro_deinit");
1010 raw->api_version = (unsigned(*)(void))GetProcAddress(hModule, "retro_api_version");
1011 raw->get_system_info = (void(*)(struct retro_system_info*))GetProcAddress(hModule, "retro_get_system_info");
1012 raw->get_system_av_info = (void(*)(struct retro_system_av_info*))GetProcAddress(hModule, "retro_get_system_av_info");
1013 raw->set_controller_port_device = (void(*)(unsigned, unsigned))GetProcAddress(hModule, "retro_set_controller_port_device");
1014 raw->reset = (void(*)(void))GetProcAddress(hModule, "retro_reset");
1015 raw->run = (void(*)(void))GetProcAddress(hModule, "retro_run");
1016 raw->serialize_size = (size_t(*)(void))GetProcAddress(hModule, "retro_serialize_size");
1017 raw->serialize = (bool(*)(void* data, size_t size))GetProcAddress(hModule, "retro_serialize");
1018 raw->unserialize = (bool(*)(const void* data, size_t size))GetProcAddress(hModule, "retro_unserialize");
1019 raw->cheat_reset = (void(*)(void))GetProcAddress(hModule, "retro_cheat_reset");
1020 raw->cheat_set = (void(*)(unsigned, bool, const char*))GetProcAddress(hModule, "retro_cheat_set");
1021 raw->load_game = (bool(*)(const struct retro_game_info *))GetProcAddress(hModule, "retro_load_game");
1022 raw->load_game_special = (bool(*)(unsigned, const struct retro_game_info*, size_t))GetProcAddress(hModule, "retro_load_game_special");
1023 raw->unload_game = (void(*)(void))GetProcAddress(hModule, "retro_unload_game");
1024 raw->get_region = (unsigned(*)(void))GetProcAddress(hModule, "retro_get_region");
1025 raw->get_memory_data = (void*(*)(unsigned))GetProcAddress(hModule, "retro_get_memory_data");
1026 raw->get_memory_size = (size_t(*)(unsigned))GetProcAddress(hModule, "retro_get_memory_size");
1027 return true;
1028}
1029
1030//float lastAudioFrame = 0;
1031/*
1032typedef float SAMPLE;
1033static int audiocallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
1034{
1035 uint uId = ThreadGetCurrentId();
1036 //DevMsg("Audio Thread ID: %u\n", uId);
1037
1038 LibretroInstanceInfo_t* info = (LibretroInstanceInfo_t*)userData;
1039 // DevMsg("Pos: %i\n", info->audiobufferpos);
1040 if (info->audiobufferpos < info->audiobuffersize)
1041 {
1042 info->processingaudio = false;
1043 return paContinue;
1044 }
1045 //if (info->processingaudio)
1046 // return paContinue;
1047
1048 // if (!inputBuffer)
1049 // return paContinue;
1050
1051 // if (lastAudioFrame != gpGlobals->framecount)
1052 //{
1053 // lastAudioFrame = gpGlobals->framecount;
1054 // lastFrameNumber = gpGlobals->framecount;
1055
1056 //Q_memcpy(outputBuffer, info->audiobuffer, info->audiobufferframes * 2 * sizeof(int16_t));
1057
1058 //int16_t* copyBuffer = new int16_t[info->audiobufferpos * 2];
1059 // Q_memcpy(copyBuffer, info->audiobuffer, info->audiobufferpos * 2 * sizeof(int16_t));
1060
1061 Q_memcpy(outputBuffer, info->audiobuffer, info->audiobufferpos * 2 * sizeof(int16_t));
1062 info->audiobufferpos = 0;
1063 info->processingaudio = false;
1064 // }
1065
1066 return paContinue;
1067 //Q_memcpy(outputBuffer, inputBuffer, framesPerBuffer * 2 * sizeof(int16_t));
1068 */
1069 /*
1070 unsigned int i;
1071 SAMPLE *out = (SAMPLE*)outputBuffer;
1072 if (!inputBuffer)
1073 {
1074 for (i = 0; i < framesPerBuffer; i++)
1075 {
1076 *out++ = 0;
1077 *out++ = 0;
1078 }
1079 }
1080 else
1081 {
1082 const SAMPLE *in = (const SAMPLE*)inputBuffer;
1083 for (int i = 0; i < framesPerBuffer; i++)
1084 {
1085 *out++ = *in++;
1086 *out++ = *in++;
1087 }
1088 }
1089
1090 return paContinue;
1091 */
1092//}
1093
1094void C_LibretroInstance::CreateAudioStream()
1095{
1096 uint uId = ThreadGetCurrentId();
1097 C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
1098 LibretroInstanceInfo_t* info = pLibretroInstance->GetInfo();
1099
1100 if (!info->soundAllowed)
1101 return;
1102
1103 DevMsg("Sample rate is: %i\n", info->samplerate);
1104
1105 PaStreamParameters outputParameters;
1106 outputParameters.device = Pa_GetDefaultOutputDevice(); // default output device
1107
1108 if (outputParameters.device == -1)
1109 {
1110 DevMsg("FAILED TO GET PORT AUDIO DEVICE!! PREPARE FOR CRASH!\n");
1111 }
1112
1113 outputParameters.channelCount = 2;
1114 outputParameters.sampleFormat = paInt16;
1115 //outputParameters.suggestedLatency = 0.032;// 0.064;// Pa_GetDeviceInfo(outputParameters.device)->defaultHighOutputLatency;
1116 outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultHighOutputLatency; // FIXME: Add better error handling here!! sometimes this can't be called!!
1117 //outputParameters.suggestedLatency = 1 / (info->framerate * 1.0);
1118 outputParameters.hostApiSpecificStreamInfo = NULL;
1119
1120 PaStream *stream;
1121 PaError err = Pa_OpenStream(
1122 &stream,
1123 NULL,
1124 &outputParameters,
1125 info->samplerate,
1126 paFramesPerBufferUnspecified,
1127 paNoFlag,//paClipOff, // we won't output out of range samples so don't bother clipping them
1128 null, //audiocallback no callback, use blocking API
1129 info); // no callback, so no callback userData
1130
1131 info->audiostream = stream;
1132
1133 //info->audiobuffersize = 1024;
1134 //info->audiobuffer = new int16_t[info->audiobuffersize];
1135 //info->audiobufferpos = 0;
1136
1137 // info->safebuffersize = info->audiobuffersize;
1138 // info->safebuffer = new int16_t[info->safebuffersize];
1139 // info->safebufferpos = 0;
1140
1141
1142 if (err != paNoError)
1143 DevMsg("Failed to open stream.\n");
1144 else
1145 DevMsg("Opened PA stream!\n");
1146
1147 err = Pa_StartStream(stream);
1148
1149 if (err != paNoError)
1150 DevMsg("Failed to start stream.\n");
1151 else
1152 DevMsg("Started stream!\n");
1153}
1154
1155void C_LibretroInstance::DestroyAudioStream()
1156{
1157 uint uId = ThreadGetCurrentId();
1158 C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
1159 LibretroInstanceInfo_t* info = pLibretroInstance->GetInfo();
1160
1161 if (!info->soundAllowed || !info->audiostream)
1162 return;
1163
1164 PaStream *stream = static_cast<PaStream*>(info->audiostream);
1165
1166 PaError err = Pa_StopStream(stream);
1167
1168 if (err != paNoError)
1169 DevMsg("Failed to stop stream.\n");
1170 else
1171 DevMsg("Stopped PA stream!\n");
1172
1173 err = Pa_CloseStream(stream);
1174 if (err != paNoError)
1175 DevMsg("Failed to close stream.\n");
1176 else
1177 DevMsg("Closed PA stream!\n");
1178
1179 info->samplerate = 0;
1180 // info->audiobufferpos = 0;
1181}
1182
1183unsigned MyThread(void *params)
1184{
1185 bool bDidRun = false;
1186
1187 LibretroInstanceInfo_t* info = (LibretroInstanceInfo_t*)params; // always use a struct!
1188
1189 CSysModule* pModule;
1190 bool bDidLoadDll = false;
1191 if (info->libretroinstance && !info->close)
1192 {
1193 bool bDidLoadModule = false;
1194 //HMODULE hModule;
1195 pModule = Sys_LoadModule(info->core.c_str());
1196 if (!pModule)
1197 {
1198 DevMsg("libretro: ERROR - Failed to load %s\n", info->core.c_str());
1199 info->runninglibretrocores->last_error = "Core Load Failed";
1200 info->state = 6;
1201 }
1202 else
1203 {
1204 bDidLoadDll = true;
1205 HMODULE hModule = reinterpret_cast<HMODULE>(pModule);
1206 if (!hModule || !C_LibretroInstance::BuildInterface(info->raw, &hModule))
1207 {
1208 DevMsg("libretro: ERROR - Failed to build interface!\n");
1209 info->runninglibretrocores->last_error = "Core Initialization Failed";
1210 info->state = 6;
1211 }
1212 else
1213 {
1214 bDidLoadModule = true;
1215
1216 info->module = pModule;
1217 info->threadid = ThreadGetCurrentId();
1218 info->coreloaded = true;
1219
1220 struct retro_system_info system_info;
1221 info->raw->get_system_info(&system_info);
1222
1223 info->library_name = system_info.library_name;
1224 info->library_version = system_info.library_version;
1225 info->valid_extensions = system_info.valid_extensions;
1226 info->need_fullpath = system_info.need_fullpath;
1227 info->block_extract = system_info.block_extract;
1228
1229 DevMsg("Loaded libretro core:\n");
1230 DevMsg("\tlibrary_name: %s\n", info->library_name.c_str());
1231 DevMsg("\tlibrary_version: %s\n", info->library_version.c_str());
1232 DevMsg("\tvalid_extensions: %s\n", info->valid_extensions.c_str());
1233 DevMsg("\tneed_fullpath: %i\n", info->need_fullpath);
1234 DevMsg("\tblock_extract: %i\n", info->block_extract);
1235
1236 g_pAnarchyManager->GetLibretroManager()->OnLibretroInstanceCreated(info); // FIXME: If instance is closed by the time this line is reached, might cause the crash!
1237
1238 DevMsg("Thread: core loaded.\n");
1239 }
1240 }
1241
1242 bool bIsInit = (info->id == "init");
1243 int state;
1244 libretro_raw* raw = info->raw;
1245 while (!info->close) //&& glfwWindowShouldClose(window) == 0
1246 {
1247 // glfwPollEvents();
1248 state = info->state;
1249
1250 if (info->window && glfwWindowShouldClose(info->window))
1251 info->close = true;
1252
1253 if (state == 2)
1254 {
1255 CSysModule* myModule = Sys_LoadModule(VarArgs("%s\\bin\\portaudio_x86.dll", engine->GetGameDirectory()));
1256 if (myModule)
1257 {
1258 DevMsg("portaudio_x86.dll loaded successfully.\n");
1259
1260 PaError err = Pa_Initialize();
1261 if (err != paNoError)
1262 DevMsg("Failed to initialize PA.\n");
1263 else
1264 DevMsg("Initialized PA successfuly!\n");
1265 }
1266 else
1267 DevMsg("Failed to load portaudio_x86.dll.\n");
1268
1269 info->state = 3;
1270 }
1271 else if (state == 3)
1272 {
1273 //raw->set_hw_context_reset(C_LibretroInstance::cbHWContextReset);
1274 raw->set_environment(C_LibretroInstance::cbEnvironment);
1275 raw->set_video_refresh(C_LibretroInstance::cbVideoRefresh);
1276 raw->set_audio_sample(C_LibretroInstance::cbAudioSample);
1277 raw->set_audio_sample_batch(C_LibretroInstance::cbAudioSampleBatch);
1278 raw->set_input_poll(C_LibretroInstance::cbInputPoll);
1279 if (raw->set_input_state)
1280 raw->set_input_state(C_LibretroInstance::cbInputState);
1281 info->state = 4;
1282 }
1283 else if (state == 4)
1284 {
1285 // load a game if we have one
1286 if (info->game != "")
1287 {
1288 DevMsg("Load the game next!!\n");
1289 //info->state = 5;
1290 if (C_LibretroInstance::LoadGame())
1291 {
1292 if (info->state == 5)
1293 {
1294 // setup the memory map prior to the 1st call to run
1295
1296 /*
1297 info->memorymap->rtcsize = info->raw->get_memory_size(RETRO_MEMORY_RTC);
1298 if (info->memorymap->rtcsize > 0)
1299 {
1300 info->memorymap->rtcdata = (uint8_t*)info->raw->get_memory_data(RETRO_MEMORY_RTC);
1301
1302 // data must be altered PRIOR to the 1st run
1303 // TODO: work
1304 }
1305 */
1306 if (true)
1307 {
1308 info->memorymap->saveramsize = info->raw->get_memory_size(RETRO_MEMORY_SAVE_RAM);
1309 if (info->memorymap->saveramsize > 0)
1310 {
1311 info->memorymap->saveramdata = (uint8_t*)info->raw->get_memory_data(RETRO_MEMORY_SAVE_RAM);
1312
1313 // data must be altered PRIOR to the 1st run
1314 if (info->settings && info->settings->GetBool("cartsaves") && g_pFullFileSystem->FileExists(VarArgs("%s\\%s\\%s.srm", info->savepath.c_str(), info->prettycore.c_str(), info->prettygame.c_str())))
1315 {
1316 FileHandle_t fileHandle = filesystem->Open(VarArgs("%s\\%s\\%s.srm", info->savepath.c_str(), info->prettycore.c_str(), info->prettygame.c_str()), "rb", "");
1317 if (fileHandle)
1318 {
1319 filesystem->Read((void*)info->memorymap->saveramdata, info->memorymap->saveramsize, fileHandle);
1320 filesystem->Close(fileHandle);
1321 }
1322 }
1323 }
1324 }
1325
1326 /*
1327 info->memorymap->systemramsize = info->raw->get_memory_size(RETRO_MEMORY_SYSTEM_RAM);
1328 if (info->memorymap->systemramsize > 0)
1329 {
1330 info->memorymap->systemramdata = (uint8_t*)info->raw->get_memory_data(RETRO_MEMORY_SYSTEM_RAM);
1331
1332 // data must be altered PRIOR to the 1st run
1333 // TODO: work
1334 }
1335
1336 info->memorymap->videoramsize = info->raw->get_memory_size(RETRO_MEMORY_VIDEO_RAM);
1337 if (info->memorymap->videoramsize > 0)
1338 {
1339 info->memorymap->videoramdata = (uint8_t*)info->raw->get_memory_data(RETRO_MEMORY_VIDEO_RAM);
1340
1341 // data must be altered PRIOR to the 1st run
1342 // TODO: work
1343 }
1344 */
1345
1346 //DevMsg("Pt A\n");
1347 info->raw->run(); // complete the game loading by executing 1 run
1348
1349
1350 // remember old state size
1351 if (info->settings && info->settings->GetBool("statesaves"))
1352 {
1353 // get current state size
1354 size_t currentStateSize = raw->serialize_size();
1355
1356 size_t oldStateSize = info->statesize;
1357
1358 // handle auto-loaded save states
1359 if (oldStateSize != 0)
1360 {
1361 if (oldStateSize != currentStateSize)
1362 {
1363 free(info->statedata);
1364 info->statedata = malloc(currentStateSize);
1365 raw->serialize(info->statedata, currentStateSize); // so it's never empty or garbage
1366 }
1367 else if (oldStateSize == currentStateSize)
1368 {
1369 // load the state already contained within statedata
1370 if( raw->unserialize(info->statedata, oldStateSize) )
1371 info->runninglibretrocores->last_msg = "State Loaded";
1372 }
1373 }
1374 else
1375 {
1376 info->statedata = malloc(currentStateSize);
1377 raw->serialize(info->statedata, currentStateSize); // so it's never empty or garbage
1378 }
1379
1380 // *always* accept the statesize provided by the core... UNLESS we have state saves disabled, then statesize MUST remain zero to avoid erroneous cleanup
1381 info->statesize = currentStateSize;
1382 }
1383
1384 bDidRun = true;
1385
1386 //DevMsg("Pt B\n");
1387 }
1388 }
1389 else
1390 {
1391 info->runninglibretrocores->last_error = "Game Load Failed";
1392 info->state = 6;
1393 }
1394 // DevMsg("cuatro\n");
1395 }
1396 }
1397 else if (state == 5)
1398 {
1399 if (info->reset)
1400 {
1401 info->reset = false;
1402 info->paused = false;
1403 info->raw->reset();
1404 }
1405 else if (!info->paused)
1406 {
1407 /*
1408 if (!info->processingaudio)
1409 {
1410 info->processingaudio = true;
1411 info->raw->run();
1412 }
1413 */
1414 //DevMsg("Pt C\n");
1415
1416 info->raw->run();
1417 /*info->runs++;
1418
1419 while (info->fastforward)// && info->runs < info->startruns)
1420 {
1421 info->raw->run();
1422 info->runs++;
1423
1424 if (info->runs >= info->startruns)
1425 info->fastforward = false;
1426 }*/
1427
1428 if (AA_LIBRETRO_3D)
1429 {
1430 /*
1431 info->lastrendered = gpGlobals->curtime;
1432
1433 if (info->readyfornextframe && !info->copyingframe)
1434 {
1435 info->readyfornextframe = false;
1436 info->readytocopyframe = false;
1437
1438 if (info->samplerate == 0)
1439 {
1440 DevMsg("Get AV info\n");
1441 struct retro_system_av_info avinfo;
1442 info->raw->get_system_av_info(&avinfo);
1443
1444 if (avinfo.timing.sample_rate > 0)
1445 {
1446 info->samplerate = int(avinfo.timing.sample_rate);
1447 info->framerate = int(avinfo.timing.fps);
1448 C_LibretroInstance::CreateAudioStream();
1449 }
1450 }
1451
1452
1453 //glDisable(GL_DEPTH_TEST); // here for illustrative purposes, depth test is initially DISABLED (key!)
1454 //glClearColor(0.3f, 0.4f, 0.1f, 1.0f);
1455 //glClear(GL_COLOR_BUFFER_BIT);
1456 //glfwMakeContextCurrent(info->window);
1457 //glfwSwapBuffers(info->window);
1458 //glfwPollEvents(); // this is what makes the window actually be responsive
1459
1460
1461 //WORD red_mask = 0xF800;
1462 //WORD green_mask = 0x7E0;
1463 //WORD blue_mask = 0x1F;
1464
1465 //DevMsg("Doin it\n");
1466
1467 //DevMsg("video refresh\n");
1468
1469 unsigned int width = info->lastframewidth;
1470 unsigned int height = info->lastframeheight;
1471 size_t pitch = info->lastframepitch;
1472 if (!info->lastframedata)
1473 info->lastframedata = malloc(pitch*height);
1474 //void* dest = malloc(pitch*height);
1475 if (AA_LIBRETRO_3D && info->context_type != RETRO_HW_CONTEXT_NONE)
1476 {
1477 //DevMsg("Format is: %i %i x %i\n", info->videoformat, pitch, height);
1478 //glfwSwapBuffers(info->window);
1479 glReadPixels(0, 0, pitch / 3, height, GL_RGB, GL_UNSIGNED_BYTE, info->lastframedata);// GL_RGBA8
1480 //glfwSwapBuffers(info->window);
1481 }
1482
1483 //if (info->lastframedata)
1484 //free(info->lastframedata);
1485
1486 //info->lastframedata = dest;
1487 info->readytocopyframe = true;
1488 }
1489 */
1490 }
1491
1492 if (bIsInit)
1493 info->state = 6;
1494 /*
1495 if (info->window)
1496 {
1497 //DevMsg("Pt 1\n");
1498 // background color
1499 glDisable(GL_DEPTH_TEST); // here for illustrative purposes, depth test is initially DISABLED (key!)
1500 glClearColor(0.3f, 0.4f, 0.1f, 1.0f);
1501 glClear(GL_COLOR_BUFFER_BIT);
1502 //DevMsg("Pt 2\n");
1503 glfwSwapBuffers(info->window);
1504 //DevMsg("Pt 3\n");
1505 glfwPollEvents();
1506 //DevMsg("Pt 4\n");
1507 }
1508 */
1509
1510 /*
1511 bool bShouldRender = false;
1512 if (lastFrameNumber != gpGlobals->framecount)
1513 {
1514 lastFrameNumber = gpGlobals->framecount;
1515
1516 if (info->framerate == 0)
1517 bShouldRender = true;
1518 else
1519 {
1520 float dif = 1 / (info->framerate * 1.0);
1521 if (gpGlobals->curtime - info->lastrendered >= dif * 1.5 || true) // sense the blocking audio API is being used, we should render every chance we get to be synced to audio.
1522 bShouldRender = true;
1523 }
1524
1525 if (bShouldRender)
1526 {
1527 // info->lastrendered = gpGlobals->curtime;
1528 // if (info->readyfornextframe)
1529 info->raw->run();
1530 }
1531 }
1532 */
1533 }
1534 }
1535 else if (state == 6) // waiting to die (requested by the libretro core)
1536 {
1537 // do nothing
1538 }
1539 }
1540 }
1541
1542 if (info)
1543 {
1544 // save any current state contained in the core to a file.
1545 if (bDidRun)
1546 {
1547 //g_pFullFileSystem->
1548 //filesystem->WriteFile(char* name, char* path, CUtlBuffer &buf)
1549
1550 if (info->statesize > 0 && info->settings && info->settings->GetBool("statesaves"))
1551 {
1552 info->raw->serialize(info->statedata, info->statesize);
1553
1554 CUtlBuffer buf;
1555 buf.Put(info->statedata, info->statesize);
1556 g_pFullFileSystem->CreateDirHierarchy(VarArgs("%s\\%s", info->savepath.c_str(), info->prettycore.c_str()));
1557 g_pFullFileSystem->WriteFile(VarArgs("%s\\%s\\%s.sav", info->savepath.c_str(), info->prettycore.c_str(), info->prettygame.c_str()), "", buf);
1558 buf.Purge();
1559
1560 info->runninglibretrocores->last_msg = "State Saved";
1561 }
1562
1563 if (info->memorymap->saveramsize > 0 && info->settings && info->settings->GetBool("cartsaves"))
1564 {
1565 CUtlBuffer buf;
1566 buf.Put(info->memorymap->saveramdata, info->memorymap->saveramsize);
1567 g_pFullFileSystem->CreateDirHierarchy(VarArgs("%s\\%s", info->savepath.c_str(), info->prettycore.c_str()));
1568 g_pFullFileSystem->WriteFile(VarArgs("%s\\%s\\%s.srm", info->savepath.c_str(), info->prettycore.c_str(), info->prettygame.c_str()), "", buf);
1569 buf.Purge();
1570 }
1571 }
1572
1573 if (info->statesize > 0 && info->statedata)
1574 free(info->statedata);
1575
1576 RunningLibretroCores_t* pRunningLibretroCores = info->runninglibretrocores;
1577
1578 info->statesize = 0;
1579
1580 // clean up the memory
1581 if (bDidLoadDll)//info->module)
1582 {
1583 Sys_UnloadModule(pModule);
1584 DevMsg("Unloaded Libretro core.\n");
1585 }
1586
1587 if (info->lastframedata)
1588 free(info->lastframedata);
1589
1590 if (AA_LIBRETRO_3D && info->framebuffer)
1591 {
1592 //glBindFramebuffer(GL_FRAMEBUFFER, 0);
1593 //glDeleteFramebuffers(1, &info->framebuffer);
1594 }
1595
1596 info->libretrokeybinds->deleteThis();
1597 info->corekeybinds->deleteThis();
1598 info->gamekeybinds->deleteThis();
1599 info->inputstate->deleteThis();
1600 info->coreCoreOptions->deleteThis();
1601 info->gameCoreOptions->deleteThis();
1602
1603 delete info->memorymap;
1604 delete info;
1605
1606 pRunningLibretroCores->count--;
1607 }
1608
1609 return 0;
1610}
1611
1612bool C_LibretroInstance::IsSelected()
1613{
1614 return (this == g_pAnarchyManager->GetLibretroManager()->GetSelectedLibretroInstance());
1615}
1616
1617bool C_LibretroInstance::HasFocus()
1618{
1619 return (this == g_pAnarchyManager->GetLibretroManager()->GetFocusedLibretroInstance());
1620}
1621
1622bool C_LibretroInstance::Focus()
1623{
1624 return g_pAnarchyManager->GetLibretroManager()->FocusLibretroInstance(this);
1625}
1626
1627bool C_LibretroInstance::Select()
1628{
1629 return g_pAnarchyManager->GetLibretroManager()->SelectLibretroInstance(this);
1630}
1631
1632bool C_LibretroInstance::Blur()
1633{
1634 if (g_pAnarchyManager->GetLibretroManager()->GetFocusedLibretroInstance())
1635 g_pAnarchyManager->GetLibretroManager()->FocusLibretroInstance(null);
1636
1637 return true;
1638}
1639
1640bool C_LibretroInstance::Deselect()
1641{
1642 return g_pAnarchyManager->GetLibretroManager()->SelectLibretroInstance(null);
1643}
1644
1645void C_LibretroInstance::Close()
1646{
1647 g_pAnarchyManager->GetLibretroManager()->DestroyLibretroInstance(this);
1648}
1649
1650void C_LibretroInstance::GetFullscreenInfo(float& fPositionX, float& fPositionY, float& fSizeX, float& fSizeY, std::string& overlayId)
1651{
1652 fPositionX = m_pOverlayKV->GetFloat("current/x", 0);// m_fPositionX;
1653 fPositionY = m_pOverlayKV->GetFloat("current/y", 0);// m_fPositionY;
1654 fSizeX = m_pOverlayKV->GetFloat("current/width", 1);// m_fSizeX;
1655 fSizeY = m_pOverlayKV->GetFloat("current/height", 1);// m_fSizeY;
1656 //file = m_pOverlayKV->GetString("file", "");// m_file;
1657 overlayId = m_overlayId;// m_pOverlayKV->GetString("current/overlayId", "");// m_overlayId;
1658}
1659
1660bool C_LibretroInstance::CreateWorkerThread(std::string core)
1661{
1662 /*
1663 CSysModule* pModule = Sys_LoadModule(core.c_str());
1664
1665 if (!pModule)
1666 {
1667 Msg("Failed to load %s\n", core.c_str());
1668 // FIXME FIX ME Probably need to clean up!
1669 return false;
1670 }
1671
1672 HMODULE hModule = reinterpret_cast<HMODULE>(pModule);
1673 if (!C_LibretroInstance::BuildInterface(m_raw, &hModule))
1674 {
1675 DevMsg("libretro: Failed to build interface!\n");
1676 // FIXME FIX ME Probably need to clean up!
1677 return false;
1678 }
1679 */
1680
1681 std::string corePath = core.substr(0, core.find_last_of("/\\") + 1);
1682
1683 m_info = new LibretroInstanceInfo_t;
1684 //m_info->runs = 0;
1685 //m_info->startruns = 6000;
1686 //m_info->fastforward = true;
1687 m_info->soundAllowed = g_pAnarchyManager->GetLibretroManager()->IsSoundAllowed();
1688 m_info->runninglibretrocores = g_pAnarchyManager->GetLibretroManager()->GetLibretroRunningCores();
1689 m_info->state = 0;
1690 m_info->paused = false;
1691 m_info->reset = false;
1692 m_info->close = false;
1693 m_info->id = "";
1694 m_info->ready = false;
1695
1696 float volume = cvar->FindVar("libretro_volume")->GetFloat();
1697 if (volume > 1.0)
1698 volume = 1.0;
1699 m_info->volume = volume;
1700 m_info->readyfornextframe = true;
1701 m_info->copyingframe = false;
1702 m_info->readytocopyframe = false;
1703 m_info->coreloaded = false;
1704 m_info->gameloaded = false;
1705 m_info->raw = m_raw;
1706 m_info->corepath = corePath;// m_corePath;
1707 m_info->assetspath = g_pAnarchyManager->GetLibretroManager()->GetLibretroPath(RETRO_ASSETS_PATH);
1708 m_info->systempath = g_pAnarchyManager->GetLibretroManager()->GetLibretroPath(RETRO_SYSTEM_PATH);
1709 m_info->savepath = g_pAnarchyManager->GetLibretroManager()->GetLibretroPath(RETRO_SAVE_PATH);
1710 m_info->module = null;// pModule;
1711 m_info->threadid = 0;
1712 m_info->libretroinstance = this;
1713 m_info->core = core;
1714 m_info->game = m_originalGame;
1715 m_info->lastframedata = null;
1716 m_info->lastframewidth = 0;
1717 m_info->lastframeheight = 0;
1718 m_info->lastframepitch = 0;
1719 m_info->videoformat = RETRO_PIXEL_FORMAT_UNKNOWN;
1720 m_info->optionshavechanged = false;
1721 //m_info->numOptions = 0;
1722// m_info->audiobuffer = null;
1723// m_info->audiobuffersize = 1024;
1724// m_info->audiobufferpos = 0;
1725 m_info->audiostream = null;
1726 m_info->samplerate = 0;
1727 m_info->framerate = 30;
1728 m_info->lastrendered = 0;
1729// m_info->audiobuffer = null;
1730 //m_info->audiobuffersize = 0;
1731 //m_info->audiobufferpos = 0;
1732 //m_info->safebuffer = null;
1733 //m_info->safebuffersize = 0;
1734 //m_info->safebufferpos = 0;
1735 m_info->processingaudio = false;
1736 m_info->window = null;
1737 m_info->framebuffer = null;
1738 m_info->portdata = null;
1739 //m_info->currentPortTypes;
1740 m_info->numports = 0;
1741
1742 // hardware acceleration stuff
1743 m_info->context_type = RETRO_HW_CONTEXT_NONE;
1744 m_info->depth = false;
1745 m_info->stencil = false;
1746 m_info->bottom_left_origin = true;
1747 m_info->version_major = 0;
1748 m_info->version_minor = 0;
1749 m_info->cache_context = true;
1750 m_info->debug_context = false;
1751
1752 // system info stuff
1753 m_info->library_name = "";
1754 m_info->library_version = "";
1755 m_info->valid_extensions = "";
1756 m_info->need_fullpath = true;
1757 m_info->block_extract = false;
1758
1759 // state stuff
1760 m_info->statesize = 0;
1761 m_info->statedata = null;
1762
1763 m_info->memorymap = new memory_map_t;
1764 m_info->memorymap->rtcsize = 0;
1765 m_info->memorymap->rtcdata = null;
1766 m_info->memorymap->saveramsize = 0;
1767 m_info->memorymap->saveramdata = null;
1768 m_info->memorymap->systemramsize = 0;
1769 m_info->memorymap->systemramdata = null;
1770 m_info->memorymap->videoramsize = 0;
1771 m_info->memorymap->videoramdata = null;
1772
1773 // LIBRETRO-WIDE KEYBINDS
1774 KeyValues* kv = new KeyValues("keybinds");
1775 if (kv->LoadFromFile(g_pFullFileSystem, "libretro\\user\\keybinds.key", "MOD"))
1776 DevMsg("Loaded libretro keybinds!\n");
1777 m_info->libretrokeybinds = kv;
1778
1779 // CORE-SPECIFIC KEYBINDS
1780 std::string prettyCore = m_info->core;
1781 size_t found = prettyCore.find_last_of("/\\");
1782 if ( found != std::string::npos )
1783 prettyCore = prettyCore.substr(found + 1);
1784
1785 found = prettyCore.find_last_of(".");
1786 if (found != std::string::npos)
1787 prettyCore = prettyCore.substr(0, found);
1788 prettyCore.erase(std::remove(prettyCore.begin(), prettyCore.end(), '.'), prettyCore.end());
1789
1790 std::string kvPath = VarArgs("libretro\\user\\%s", prettyCore.c_str());
1791 //g_pFullFileSystem->CreateDirHierarchy(kvPath.c_str(), "DEFAULT_WRITE_PATH");
1792
1793 kv = new KeyValues("keybinds");
1794 kv->LoadFromFile(g_pFullFileSystem, VarArgs("%s\\keybinds.key", kvPath.c_str()), "MOD");
1795 m_info->corekeybinds = kv;
1796
1797 // GAME-SPECIFIC KEYBINDS
1798 std::string prettyGame = m_info->game;
1799 found = prettyGame.find_last_of("/\\");
1800 if (found != std::string::npos)
1801 prettyGame = prettyGame.substr(found + 1);
1802
1803 found = prettyGame.find_last_of(".");
1804 if (found != std::string::npos)
1805 prettyGame = prettyGame.substr(0, found);
1806 prettyGame.erase(std::remove(prettyGame.begin(), prettyGame.end(), '.'), prettyGame.end());
1807
1808 m_info->prettygame = prettyGame;
1809 m_info->prettycore = prettyCore;
1810
1811 kvPath = VarArgs("libretro\\user\\%s\\%s", prettyCore.c_str(), prettyGame.c_str());
1812 //g_pFullFileSystem->CreateDirHierarchy(kvPath.c_str(), "DEFAULT_WRITE_PATH");
1813
1814 kv = new KeyValues("keybinds");
1815 kv->LoadFromFile(g_pFullFileSystem, VarArgs("%s\\keybinds.key", kvPath.c_str()), "MOD");
1816 m_info->gamekeybinds = kv;
1817
1818 // CURRENT KEYBINDS
1819 m_info->inputstate = new KeyValues("keybinds"); // just like the other structs, but holds backbuffer input values instead of source engine key enums.
1820
1821 // CORE-SPECIFIC OPTIONS
1822 //kvPath = VarArgs("libretro\\user\\%s", prettyCore.c_str());
1823 kvPath = "libretro\\user\\" + prettyCore + "\\options.key";
1824
1825 kv = new KeyValues("options");
1826 kv->LoadFromFile(g_pFullFileSystem, kvPath.c_str(), "MOD");
1827 m_info->coreCoreOptions = kv;
1828
1829 // GAME-SPECIFIC OPTIONS
1830 kvPath = "libretro\\user\\" + prettyCore + "\\" + prettyGame + "\\options.key";
1831
1832 kv = new KeyValues("options");
1833 kv->LoadFromFile(g_pFullFileSystem, kvPath.c_str(), "MOD");
1834 m_info->gameCoreOptions = kv;
1835
1836 // we are null settings by default
1837 m_info->settings = null;
1838
1839 // but try to find us
1840 KeyValues* pCoreSettingsKV = g_pAnarchyManager->GetLibretroManager()->GetCoreSettingsKV();
1841 std::string compareCore = prettyCore + ".dll";
1842 std::string testerCore;
1843 for (KeyValues *sub = pCoreSettingsKV->GetFirstSubKey(); sub; sub = sub->GetNextKey())
1844 {
1845 testerCore = sub->GetString("file");
1846 if (testerCore == compareCore)
1847 {
1848 m_info->settings = sub;
1849 break;
1850 }
1851 }
1852
1853 //std::string prettyCore = m_info->prettycore;
1854 //std::string prettyGame = m_info->prettygame;
1855 std::string overlayId = g_pAnarchyManager->GetLibretroManager()->DetermineOverlay(prettyCore, prettyGame);
1856 this->SetOverlay(overlayId);
1857 g_pAnarchyManager->HudStateNotify();
1858
1859 m_info->runninglibretrocores->count++;
1860 g_pAnarchyManager->AddToastMessage(VarArgs("Libretro Opened (%i running)", m_info->runninglibretrocores->count));
1861 CreateSimpleThread(MyThread, m_info);
1862
1863 //ThreadId_t pThreadId = 420L;
1864 //CreateSimpleThread(MyThread, m_info, &pThreadId, 0U);
1865
1866 /*
1867 if (!g_CMyAsyncThread.IsAlive())
1868 g_CMyAsyncThread.Start();
1869
1870 if (!g_CMyAsyncThread.IsAlive())
1871 DevMsg("CreateAThreadAndCallTheFunction() failed to start the thread!\n");
1872
1873 // Thread safety: make some local copies! The real ones could be deleted/changed while we execute.
1874 char* NewParameter1 = "init";// FUNCTION_THAT_CREATES_A_COPY_OF_THE_MEMORY(Parameter1);
1875 char* NewParameter2 = "Another test";// FUNCTION_THAT_CREATES_A_COPY_OF_THE_MEMORY(Parameter1);
1876
1877 g_CMyAsyncThread.CallThreadFunction(NewParameter1, NewParameter2);
1878 g_CMyAsyncThread.CallWorker(CMyAsyncThread::EXIT);
1879 */
1880 return true;
1881}
1882
1883/*
1884bool CMyAsyncThread::FunctionToBeRunFromInsideTheThread(char* Parameter1, char* Parameter2)
1885{
1886 if (!Q_strcmp(Parameter1, "init"))
1887 {
1888 //DevMsg("Thread yo: %s %s\n", Parameter1, Parameter2);
1889 C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->GetSelectedLibretroInstance();
1890 if (pLibretroInstance)
1891 {
1892 libretro_raw* raw = pLibretroInstance->GetRaw();
1893 raw->set_environment(&this->cbEnvironment);
1894 }
1895 }
1896 return true;
1897}
1898
1899void CMyAsyncThread::Update()
1900{
1901 DevMsg("once?\n");
1902 C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->GetSelectedLibretroInstance();
1903 if (pLibretroInstance)
1904 {
1905 DevMsg("Yarbles\n");
1906 libretro_raw* raw = pLibretroInstance->GetRaw();
1907 // raw->run();
1908 }
1909}
1910*/
1911/*
1912unsigned C_LibretroInstance::Worker(void *params)
1913{
1914 DevMsg("whaaaaat\n");
1915}
1916*/
1917
1918/*
1919int16_t C_LibretroInstance::GetInputState(LibretroInstanceInfo_t* info, unsigned int port, unsigned int device, unsigned int index, unsigned int id)
1920{
1921 return g_pAnarchyManager->GetLibretroManager()->GetInputState(info, port, device, index, id);
1922}
1923*/
1924/*
1925void C_LibretroInstance::cbRetroFrameTime(retro_usec_t usec)
1926{
1927 DevMsg("Value: %llu\n", (uint64)usec);
1928}
1929*/
1930void C_LibretroInstance::cbMessage(enum retro_log_level level, const char * fmt, ...)
1931{
1932 va_list args;
1933
1934 //char* msg = new char[AA_MAX_STRING];
1935 char msg[AA_MAX_STRING];
1936
1937 va_start(args, fmt);
1938 int neededlen = Q_vsnprintf(msg, AA_MAX_STRING, fmt, args);
1939 va_end(args);
1940
1941 std::string buf = msg;
1942 if (buf.at(buf.length() - 1) != '\n')
1943 buf += "\n";
1944
1945 DevMsg("libretro: %s", buf.c_str());
1946
1947 //delete[] msg;
1948}
1949
1950///*
1951HMODULE GetCurrentModule()
1952{ // NB: XP+ solution!
1953 HMODULE hModule = NULL;
1954 GetModuleHandleEx(
1955 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
1956 (LPCTSTR)GetCurrentModule,
1957 &hModule);
1958
1959 return hModule;
1960}
1961//*/
1962
1963// http://stackoverflow.com/questions/215963/how-do-you-properly-use-widechartomultibyte
1964// Convert a wide Unicode string to an UTF8 string
1965std::string utf8_encode(const std::wstring &wstr)
1966{
1967 if (wstr.empty()) return std::string();
1968 int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
1969 std::string strTo(size_needed, 0);
1970 WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
1971 return strTo;
1972}
1973
1974// Convert an UTF8 string to a wide Unicode String
1975std::wstring utf8_decode(const std::string &str)
1976{
1977 if (str.empty()) return std::wstring();
1978 int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
1979 std::wstring wstrTo(size_needed, 0);
1980 MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
1981 return wstrTo;
1982}
1983
1984const char* GetFormatName(int format)
1985{
1986 if (format == 0)
1987 return "0RGB1555";
1988 else if (format == 1)
1989 return "XRGB8888";
1990 else if (format == 2)
1991 return "RGB565";
1992 else
1993 return "UNKOWN";
1994}
1995
1996/*
1997retro_hw_context_reset_t context_destroy;
1998
1999void v3d_context_destroy()
2000{
2001 DevMsg("Destroy the context!\n");
2002}
2003
2004void v3d_context_reset()
2005{
2006 DevMsg("Reset the context!\n");
2007}
2008*/
2009
2010static retro_proc_address_t v3d_get_proc_address(const char * sym)
2011{
2012 //DevMsg("Getting proc address for %s\n", sym);
2013 GLFWglproc proc = glfwGetProcAddress(sym);
2014 //DevMsg("Found proc: %u\n", (bool)(proc));
2015 return proc;
2016 //return 0;
2017}
2018
2019static uintptr_t v3d_get_current_framebuffer()
2020{
2021 //return 0;
2022 //return 0; // alcaro says this is related to shaders, and even tho cores don't explicity expect 0 as a response, they handle it well.
2023
2024 //DevMsg("Getting frame buffer...\n");
2025 return (uintptr_t)0;
2026 /*
2027 uint uId = ThreadGetCurrentId();
2028 C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
2029
2030 if (!pLibretroInstance)
2031 return false;
2032
2033 LibretroInstanceInfo_t* info = pLibretroInstance->GetInfo();
2034
2035 DevMsg("2nd pitt stop: %u\n", info->framebuffer);
2036
2037// int width, height;
2038// glfwGetFramebufferSize(info->window, &width, &height);
2039// DevMsg("Width: %i Height: %i\n", width, height);
2040
2041 return (uintptr_t)info->framebuffer;//(uintptr_t)GL_FRAMEBUFFER;// (uintptr_t)info->framebuffer;// info->framebuffer;
2042 //return GL_FRAMEBUFFER;// info->framebuffer;// GL_FRAMEBUFFER;// glfwGetCurrentContext();
2043 */
2044}
2045
2046void framebuffer_size_callback(GLFWwindow* window, int width, int height)
2047{
2048 DevMsg("OpenGL framebuffer size has changed to: %i x %i\n", width, height);
2049 glViewport(0, 0, width, height);
2050}
2051
2052bool set_rumble_state(unsigned port, enum retro_rumble_effect effect, uint16_t strength)
2053{
2054 //DevMsg("libretro: Ignoring %s rumble effect on port %u w/ strength %u\n", (effect == 0) ? "STRONG" : "WEAK", port, strength);
2055 return true;
2056}
2057
2058bool C_LibretroInstance::cbEnvironment(unsigned cmd, void* data)
2059{
2060 uint uId = ThreadGetCurrentId();
2061 C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
2062
2063 if (!pLibretroInstance)
2064 return false;
2065
2066 LibretroInstanceInfo_t* info = pLibretroInstance->GetInfo();
2067
2068 // DevMsg("libretro: Environment called %u.\n", (unsigned int)cmd);
2069
2070 //1 SET_ROTATION, no known supported core uses that. Cores are expected to deal with failures, anyways.
2071 //2 GET_OVERSCAN, I have no opinion. Use the default.
2072 if (cmd == RETRO_ENVIRONMENT_GET_OVERSCAN) //2
2073 {
2074 DevMsg("libretro: Asking frontend if overscan should be included or cropped.\n");
2075 *(bool*)data = false;
2076 return true;
2077 }
2078
2079 if (cmd == RETRO_ENVIRONMENT_GET_CAN_DUPE) //3
2080 {
2081 DevMsg("libretro: Asking frontend if CAN_DUPE.\n");
2082 *(bool*)data = true;
2083 return true;
2084 }
2085
2086 //4 was removed and can safely be ignored.
2087 //5 was removed and can safely be ignored.
2088 //6 SET_MESSAGE, ignored because I don't know what to do with that.
2089 if (cmd == RETRO_ENVIRONMENT_SET_MESSAGE)
2090 {
2091 const struct retro_message* msg = (const struct retro_message*)data;
2092 std::string text = msg->msg;
2093 DevMsg("libretro: Set Message (%u): %s\n", msg->frames, text.c_str());
2094 return true;
2095 }
2096
2097 //7 SHUTDOWN, ignored because no supported core has any reason to have Off buttons.
2098 //8 SET_PERFORMANCE_LEVEL, ignored because I don't support a wide range of powers.
2099 if (cmd == RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY || cmd == RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY || cmd == RETRO_ENVIRONMENT_GET_LIBRETRO_PATH || cmd == RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY || cmd == RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY) // note that libretro path might be wanting a full file location including extension, but ignore that for now and treat it like the others.
2100 {
2101 // FIXME: MEMORY LEAK
2102 // FIXME: there needs to be book keeping so that these temp const char*'s can be cleaned up!!!
2103 DevMsg("String requested...\n");
2104 std::string folder;
2105
2106 if (cmd == RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY || cmd == RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY)
2107 folder = info->assetspath + "\\" + info->prettycore;// +"\\assets";
2108 else if (cmd == RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY)
2109 folder = info->systempath + "\\" + info->prettycore;// +"\\system";
2110 else if (cmd == RETRO_ENVIRONMENT_GET_LIBRETRO_PATH)
2111 folder = info->corepath + "\\" + info->core; // this is a full file location w/ extension
2112 else if (cmd == RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY)
2113 folder = info->savepath + "\\" + info->prettycore;// +"\\save";
2114
2115 if (cmd != RETRO_ENVIRONMENT_GET_LIBRETRO_PATH)
2116 g_pFullFileSystem->CreateDirHierarchy(folder.c_str());
2117
2118 char* buf = new char[AA_MAX_STRING];
2119 Q_strcpy(buf, folder.c_str());
2120
2121 //V_FixSlashes(buf, '/');
2122
2123 DevMsg("libretro: Returning string for ");
2124 if (cmd == RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY)
2125 DevMsg("system");
2126 else if (cmd == RETRO_ENVIRONMENT_GET_LIBRETRO_PATH)
2127 DevMsg("libretro");
2128 else if (cmd == RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY)
2129 DevMsg("core assets");
2130 else if (cmd == RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY)
2131 DevMsg("content");
2132
2133 DevMsg(" directory %s\n", buf);
2134
2135 (*(const char**)data) = buf;
2136
2137 //delete[] buf; // Are we SURE we don't have to delete this on our end now? We probably do not. The core probably manages it from here on in.
2138 return true;
2139 }
2140
2141 /*
2142 if (cmd == RETRO_ENVIRONMENT_SET_VARIABLES)//16
2143 {
2144 //HMODULE hModule = GetCurrentModule(); // client.dll
2145 //HINSTANCE hInstance = GetModuleHandle(0); // AArcade.exe
2146 WCHAR cwBuffer[2048] = { 0 };
2147 LPWSTR pszBuffer = cwBuffer;
2148 DWORD dwMaxChars = _countof(cwBuffer);
2149 DWORD dwLength = 0;
2150
2151 GetModuleFileNameW(hModule, pszBuffer, dwMaxChars);
2152
2153 std::wstring wString = cwBuffer;
2154 std::string result = utf8_encode(wString);
2155 DevMsg("Result: %s\n", result.c_str());
2156
2157 //long threadId = GetCurrentThreadId();
2158 //DevMsg("ID is: %l\n", threadId);
2159 //ThreadSetDebugName()
2160
2161 //DevMsg("Value is: %s\n", m_info->id.c_str());
2162// GetThreadHandle();
2163
2164 if (ThreadInMainThread())
2165 DevMsg("MAIN THREAD!\n");
2166 else
2167 DevMsg("CHILD THREAD!\n");
2168
2169 uint uId = ThreadGetCurrentId();
2170 C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
2171 DevMsg("Size is: %i\n", pLibretroInstance->GetInfo()->options.size());
2172 }
2173 */
2174
2175 if (cmd == RETRO_ENVIRONMENT_SET_PIXEL_FORMAT) //10
2176 {
2177 enum retro_pixel_format newfmt = *(enum retro_pixel_format *)data;
2178 if (newfmt == RETRO_PIXEL_FORMAT_0RGB1555 || newfmt == RETRO_PIXEL_FORMAT_XRGB8888 ||
2179 newfmt == RETRO_PIXEL_FORMAT_RGB565)
2180 {
2181 DevMsg("libretro: Setting video format to %s\n", GetFormatName(newfmt));
2182 info->videoformat = newfmt;
2183 return true;
2184 }
2185 else
2186 {
2187 DevMsg("libretro: Failed at setting video to format %s\n", GetFormatName(newfmt));
2188 return false;
2189 }
2190 }
2191
2192 if (cmd == RETRO_ENVIRONMENT_SET_HW_RENDER) //14
2193 {
2194 if (!AA_LIBRETRO_3D)
2195 {
2196 DevMsg("libretro: Denying request for OpenGL context.\n");
2197 return false;
2198 }
2199 else
2200 {
2201 DevMsg("libretro: Core requesting HW context: ");
2202
2203 struct retro_hw_render_callback * render = (struct retro_hw_render_callback*)data;
2204 render->get_current_framebuffer = v3d_get_current_framebuffer;
2205 render->get_proc_address = v3d_get_proc_address;
2206
2207 info->raw->context_reset = (retro_hw_context_reset_t)render->context_reset;
2208 info->raw->context_destroy = (retro_hw_context_reset_t)render->context_destroy;
2209 info->context_type = render->context_type;
2210 info->depth = render->depth;
2211 info->stencil = render->stencil;
2212 info->bottom_left_origin = render->bottom_left_origin;
2213 //info->version_major;
2214 //info->version_minor;
2215 info->cache_context = render->cache_context;
2216 info->debug_context = render->debug_context;
2217
2218 //GLFW_ORIGIN_UL_BIT;
2219 //glfwReadImage with the GLFW_ORIGIN_UL_BIT
2220
2221 unsigned api;
2222 switch (info->context_type)
2223 {
2224 case RETRO_HW_CONTEXT_NONE:
2225 DevMsg("NONE (UNSUPPORTED)\n");
2226 api = GLFW_NO_API;
2227 info->version_major = 0;
2228 info->version_minor = 0;
2229 break;
2230
2231 case RETRO_HW_CONTEXT_OPENGL:
2232 DevMsg("OpenGL (2.x)\n");
2233 api = GLFW_OPENGL_API;
2234 info->version_major = 2;
2235 info->version_minor = 0;
2236 break;
2237
2238 case RETRO_HW_CONTEXT_OPENGLES2:
2239 DevMsg("OpenGL ES (2.0)\n");
2240 api = GLFW_OPENGL_ES_API;
2241 info->version_major = 2;
2242 info->version_minor = 0;
2243 break;
2244
2245 case RETRO_HW_CONTEXT_OPENGL_CORE:
2246 DevMsg("OpenGL (%u.%u)\n", render->version_major, render->version_minor);
2247 api = GLFW_OPENGL_API;
2248 info->version_major = render->version_major;
2249 info->version_minor = render->version_minor;
2250 break;
2251
2252 case RETRO_HW_CONTEXT_OPENGLES3:
2253 DevMsg("OpenGL ES (3.0)\n");
2254 api = GLFW_OPENGL_ES_API;
2255 info->version_major = 3;
2256 info->version_minor = 0;
2257 break;
2258
2259 case RETRO_HW_CONTEXT_OPENGLES_VERSION:
2260 DevMsg("OpenGL ES (%u.%u)\n", render->version_major, render->version_minor);
2261 api = GLFW_OPENGL_ES_API;
2262 info->version_major = render->version_major;
2263 info->version_minor = render->version_minor;
2264 break;
2265
2266 case RETRO_HW_CONTEXT_VULKAN:
2267 DevMsg("Vulkan (UNSUPPORTED)\n");
2268 api = GLFW_NO_API;
2269 info->version_major = 0;
2270 info->version_minor = 0;
2271 break;
2272
2273 default:
2274 DevMsg("UNKNOWN (UNSUPPORTED)\n");
2275 api = GLFW_NO_API;
2276 info->version_major = 0;
2277 info->version_minor = 0;
2278 break;
2279 }
2280
2281 DevMsg("\tdepth: %i\n", info->depth);
2282 DevMsg("\tstencil: %i\n", info->stencil);
2283 DevMsg("\tbottom_left_origin: %i\n", info->bottom_left_origin);
2284 DevMsg("\tversion_major: %u\n", info->version_major);
2285 DevMsg("\tversion_minor: %u\n", info->version_minor);
2286 DevMsg("\tcache_context: %i\n", info->cache_context);
2287 DevMsg("\tdebug_context: %i\n", info->debug_context);
2288
2289 // init 3d
2290 if (glfwInit())
2291 {
2292 //glfwWindowHint(GLFW_SAMPLES, 4);
2293 //glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
2294 //glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
2295 glfwWindowHint(GLFW_CLIENT_API, api);
2296 glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API);
2297 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, info->version_major);
2298 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, info->version_minor);
2299 glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
2300 glfwWindowHint(GLFW_DECORATED, GL_FALSE);
2301 //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
2302 //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);// GLFW_OPENGL_ANY_PROFILE);// GLFW_OPENGL_CORE_PROFILE);
2303 glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // invisible window
2304
2305 //GLFWwindow* window = glfwCreateWindow(640, 480, "", NULL, NULL);
2306 //HWND myHWnd = FindWindow(null, "AArcade: Source");
2307 GLFWwindow* window = glfwCreateWindow(1280, 720, "My OPENGL", NULL, NULL);
2308 //glfwGetWGLContext(window);
2309
2310 if (window)
2311 {
2312 // render->get_current_framebuffer = v3d_get_current_framebuffer;
2313 //render->get_proc_address = v3d_get_proc_address;
2314 // return true;
2315
2316 glewExperimental = GL_TRUE; // Needed in core profile
2317 glfwMakeContextCurrent(window);
2318 glewInit();
2319
2320 DevMsg("Window created!\n");
2321 info->window = window;
2322 glfwSetFramebufferSizeCallback(info->window, framebuffer_size_callback); // to detect framebuffer size changes (probably not needed for libretro)
2323
2324 //glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); // to detect framebuffer size changes (probably not needed for libretro)
2325
2326 // get version info
2327 const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
2328 const GLubyte* version = glGetString(GL_VERSION); // version as a string
2329 DevMsg("Renderer: %s\n", renderer);
2330 DevMsg("OpenGL version supported %s\n", version);
2331 DevMsg("=========================\n");
2332
2333 //info->framebuffer = new GLuint[1];
2334 //glGenFramebuffers(1, &info->framebuffer[0]);
2335 //glBindFramebuffer(GL_FRAMEBUFFER, info->framebuffer[0]);
2336
2337
2338 /*
2339 info->framebuffer = new GLuint[1];
2340 GLuint* tex = new GLuint[1];
2341 glGenTextures(1, tex);
2342 glBindTexture(GL_TEXTURE_2D, tex[0]);
2343 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1280, 720, 0, GL_RGB8, GL_UNSIGNED_BYTE, null); // GL_RGB
2344 glGenFramebuffers(1, &info->framebuffer[0]);
2345 glBindFramebuffer(GL_FRAMEBUFFER, info->framebuffer[0]);
2346 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex[0], 0);
2347 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
2348 DevMsg("Something went wrong.\n");
2349 else
2350 {
2351 int width, height;
2352 glfwGetFramebufferSize(window, &width, &height);
2353 DevMsg("Frame buffer ready: %i x %i\n", width, height);
2354 }
2355 */
2356
2357 //glfwPollEvents();
2358
2359 //glDisable(GL_DEPTH_TEST); // here for illustrative purposes, depth test is initially DISABLED (key!)
2360 //glClearColor(0.3f, 0.4f, 0.1f, 1.0f);
2361 //glClear(GL_COLOR_BUFFER_BIT);
2362 //glfwSwapBuffers(info->window);
2363 //glfwPollEvents();
2364
2365 //render->context_reset = v3d_context_reset;
2366 //render->context_destroy = v3d_context_destroy;
2367
2368 glDisable(GL_DEPTH_TEST);
2369 //glfwSwapInterval(1);
2370
2371 // The depth buffer
2372 /*
2373 GLuint depthrenderbuffer;
2374 glGenRenderbuffers(1, &depthrenderbuffer);
2375 glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer);
2376 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1280, 720);
2377 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer);
2378 glEnable(GL_DEPTH_TEST);
2379 */
2380
2381 //glEnable(GL_DOUBLEBUFFER);
2382 //glEnable(GL_RGB);
2383 //glPixelStorei(GL_PACK_ALIGNMENT, 3);
2384 glClearColor(0.3f, 0.4f, 0.1f, 1.0f);
2385 /*
2386 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
2387 DevMsg("Something went wrong.\n");
2388 else
2389 {
2390 int width, height;
2391 glfwGetFramebufferSize(window, &width, &height);
2392 DevMsg("Frame buffer ready: %i x %i\n", width, height);
2393 }
2394 */
2395
2396 //glViewport(0, 0, 1280, 720); // Render on the whole framebuffer, complete from the lower left corner to the upper right
2397 // reset the context (TODO: Make sure the window is ready to reset its context!
2398 info->raw->context_reset();
2399
2400 DevMsg("done.\n");
2401
2402
2403
2404
2405
2406
2407
2408
2409 // The texture we're going to render to
2410 //GLuint renderedTexture;
2411 //glGenTextures(1, &renderedTexture);
2412
2413 // "Bind" the newly created texture : all future texture functions will modify this texture
2414 //glBindTexture(GL_TEXTURE_2D, renderedTexture);
2415
2416 // Give an empty image to OpenGL ( the last "0" )
2417 //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024, 1024, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
2418
2419 // Poor filtering. Needed !
2420 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2421 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2422
2423 // just make sure to tell glfw you want depth/stencil buffers; if you're using fb0, you can't change that after creating the window
2424 // Alcaro: glfw deals with context creation, if you're using that then you can ignore anything in the ifdefs
2425
2426 // The depth buffer
2427 //GLuint depthrenderbuffer;
2428 //glGenRenderbuffers(1, &depthrenderbuffer);
2429 //glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer);
2430 //glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1024, 1024);
2431 //glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer);
2432
2433 // Set "renderedTexture" as our colour attachement #0
2434 //glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0);
2435
2436 // Set the list of draw buffers.
2437 //GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
2438 //glGenFramebuffers(1, &info->framebuffer);
2439 //glBindFramebuffer(GL_FRAMEBUFFER, info->framebuffer);
2440 //glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
2441
2442 // Always check that our framebuffer is ok
2443 //if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
2444 //{
2445 //// DevMsg("Something went wrong.\n");
2446 //}
2447 //else
2448 // DevMsg("Frame buffer ready.\n");
2449
2450 // Render to our framebuffer
2451 //glBindFramebuffer(GL_FRAMEBUFFER, info->framebuffer);
2452 //glViewport(0, 0, 1024, 1024); // Render on the whole framebuffer, complete from the lower left corner to the upper right
2453
2454 //glCreateContex()
2455
2456 //glfwGetWGLContext(window);
2457
2458 //glfwGetWGLContext
2459
2460 //DevMsg("done changing frame buffer.\n");
2461 }
2462 else
2463 DevMsg("Failed to create openGL window.\n");
2464
2465 //if (info->window)
2466 //{
2467 //DevMsg("Painting initial frame...\n");
2468 /*
2469 // background color
2470 glDisable(GL_DEPTH_TEST); // here for illustrative purposes, depth test is initially DISABLED (key!)
2471 glClearColor(0.3f, 0.4f, 0.1f, 1.0f);
2472 glClear(GL_COLOR_BUFFER_BIT);
2473
2474 glfwSwapBuffers(info->window);
2475 glfwPollEvents();
2476 */
2477
2478 //glfwPollEvents();
2479 //render->context_reset = v3d_context_reset;
2480 //render->context_destroy = v3d_context_destroy;
2481 //render->get_current_framebuffer = //(uintptr_t)GL_FRAMEBUFFER;// (uintptr_t)info->framebuffer;// info->framebuffer;
2482 //render->get_current_framebuffer = v3d_get_current_framebuffer;
2483 //render->get_proc_address = v3d_get_proc_address;
2484 //}
2485
2486 DevMsg("Fin\n");
2487 return true;
2488 }
2489
2490 return false;
2491 }
2492 /*
2493 if (!this->create3d) return false;
2494 struct retro_hw_render_callback * render = (struct retro_hw_render_callback*)data;
2495 this->v3d = this->create3d(render);
2496 if (!this->v3d) return false;
2497 render->get_current_framebuffer = v3d_get_current_framebuffer;
2498 render->get_proc_address = v3d_get_proc_address;
2499 */
2500 //return true;
2501
2502 //return false;
2503 }
2504
2505 if (cmd == RETRO_ENVIRONMENT_GET_VARIABLE) //15
2506 {
2507 struct retro_variable * variable = (struct retro_variable*)data;
2508
2509 variable->value = NULL;
2510
2511 DevMsg("Requesting variable: %s = ", variable->key);
2512
2513 bool bFoundVal = false;
2514 std::string val;
2515 KeyValues* kv;
2516 unsigned int index;
2517 unsigned int numOptions = info->options.size();
2518 for (index = 0; index < numOptions; index++)
2519 {
2520 if (std::string(variable->key) == info->options[index]->name_internal)
2521 break;
2522 }
2523
2524 kv = info->gameCoreOptions;
2525 if (!Q_strcmp(kv->GetString(variable->key, "default"), "default"))
2526 kv = info->coreCoreOptions;
2527
2528 if (Q_strcmp(kv->GetString(variable->key, "default"), "default"))
2529 {
2530 val = kv->GetString(variable->key);
2531 bFoundVal = true;
2532 }
2533 else if (index < numOptions)
2534 {
2535 val = info->options[index]->values[0].c_str();
2536 bFoundVal = true;
2537 }
2538 else
2539 {
2540 DevMsg("WARNING: Libretro core requested a variable that it did not tell us about before hand!: %s\n", variable->key);
2541
2542 // try to reply with a default response (even tho we dont know what a default response is cuz this core never told us shit.)
2543 if (info->core.find("mame") != std::string::npos)
2544 {
2545 val = "disabled";
2546 bFoundVal = true;
2547 }
2548 }
2549
2550 if (bFoundVal)
2551 {
2552 // FIXME: MEMORY LEAK
2553 // FIXME: there needs to be book keeping so that these temp const char*'s can be cleaned up!!!
2554 char* buf = new char[AA_MAX_STRING];
2555 Q_strcpy(buf, val.c_str());
2556 variable->value = buf;
2557 DevMsg("%s\n", buf);
2558
2559 //V_FixSlashes(buf, '/');
2560 //(*(const char**)data) = buf;
2561 //delete[] buf;
2562 }
2563 else
2564 variable->value = null;
2565
2566 info->optionshavechanged = false;
2567 return true;
2568 }
2569
2570 if (cmd == RETRO_ENVIRONMENT_SET_VARIABLES)//16
2571 {
2572 DevMsg("libretro: RETRO_ENVIRONMENT_SET_VARIABLES\n");
2573 const struct retro_variable * variables = (const struct retro_variable*)data;
2574
2575 // variables are stored as const chars and must be manually dealloc OBSOLTETE: i think they are strings now.
2576 while (!info->options.empty())
2577 {
2578 // libretro_core_option* pOption = info->options[info->options.size() - 1];
2579 // free(pOption->name_display);
2580 info->options.pop_back();
2581 }
2582
2583 const struct retro_variable * variables_count = variables;
2584
2585 while (variables_count->key) variables_count++;
2586 unsigned int numvars = variables_count - variables;
2587
2588 bool bOptionListHasChanged = true;
2589 bool bOptionsHaveChanged = true;
2590 DevMsg("Num vars is: %i\n", numvars);
2591 for (unsigned int i = 0; i<numvars; i++)
2592 {
2593 // Initialize to 0 index for this variable's value
2594
2595// info->optionscurrentvalues.push_back(0);
2596
2597 DevMsg("libretro: Setting up environment variable %s with definition %s of %u\n", variables[i].key, variables[i].value, i);
2598
2599 libretro_core_option* pOption = new libretro_core_option();
2600 pOption->name_internal = variables[i].key;
2601
2602 const char * values = Q_strstr(variables[i].value, "; ");
2603
2604 //if the value does not contain "; ", the core is broken, and broken cores can break shit in whatever way they want, anyways.
2605 //let's segfault.
2606 // In other words, values would be null and a crash would occur when we tried to use it.
2607 //pOption->name_display = VarArgs("%s", variables[i].value);
2608
2609 /*
2610 unsigned int namelen = values - variables[i].value;
2611 values += 2;
2612
2613 char* name = (char*)malloc(namelen + 1);
2614 memcpy(name, variables[i].value, namelen);
2615 name[namelen] = '\0';
2616 pOption->name_display = name;
2617 */
2618
2619 //buf = VarArgs("%s", variables[i].value);
2620 pOption->name_display = variables[i].value;
2621 size_t found = pOption->name_display.find("; ");
2622 if (found != std::string::npos)
2623 pOption->name_display = pOption->name_display.substr(0, found);
2624
2625 unsigned int numvalues = 1;
2626 const char * valuescount = values;
2627 while (*valuescount)
2628 {
2629 if (*valuescount == '|') numvalues++;
2630 valuescount++;
2631 }
2632
2633 std::string buf;
2634 const char * nextvalue = values;
2635 for (unsigned int j = 0; j<numvalues; j++)
2636 {
2637 nextvalue = values;
2638 while (*nextvalue && *nextvalue != '|') nextvalue++;
2639 unsigned int valuelen = nextvalue - values;
2640
2641 buf = values;
2642 if (j == 0)
2643 buf = buf.substr(2, valuelen - 2);
2644 else
2645 buf = buf.substr(0, valuelen);
2646
2647 pOption->values.push_back(buf);
2648 values = nextvalue + 1;
2649 }
2650
2651 info->options.push_back(pOption);
2652 }
2653
2654 return true;
2655 }
2656
2657 if (cmd == RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE) //17
2658 {
2659 //DevMsg("libretro: Fetching if options have changed (%s).\n", (s_bOptionsHaveChanged)?"true":"false");
2660 *(bool*)data = info->optionshavechanged;
2661 return true;
2662 }
2663
2664 if (cmd == RETRO_ENVIRONMENT_GET_PERF_INTERFACE) //18
2665 {
2666 DevMsg("libretro: UNHANDLED RETRO_ENVIRONMENT_GET_PERF_INTERFACE\n");
2667 struct retro_perf_callback *cb = (struct retro_perf_callback*)data;
2668
2669 cb->get_time_usec = null;
2670 cb->get_cpu_features = null;
2671 cb->get_perf_counter = null;
2672
2673 cb->perf_register = null;
2674 cb->perf_start = null;
2675 cb->perf_stop = null;
2676 cb->perf_log = null;
2677 return false;
2678 }
2679
2680 /*
2681 if (cmd == RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK) //21
2682 {
2683 DevMsg("SetFrameTimeCallback\n");
2684 const struct retro_frame_time_callback *info = (const struct retro_frame_time_callback*)data;
2685 //info->callback(1000);
2686 //info->callback = &C_LibretroInstance::cbRetroFrameTime;
2687 //info->reference = 1000;
2688 return true;
2689 }
2690 */
2691
2692 if (cmd == RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE) //23
2693 {
2694 struct retro_rumble_interface * iface = (struct retro_rumble_interface*)data;
2695 DevMsg("libretro: Rumble interface requested.\n");
2696 iface->set_rumble_state = set_rumble_state;
2697 return true;
2698 }
2699
2700 if (cmd == RETRO_ENVIRONMENT_GET_LOG_INTERFACE) //27
2701 {
2702 struct retro_log_callback * logcb = (struct retro_log_callback*)data;
2703 logcb->log = &C_LibretroInstance::cbMessage;
2704 return true;
2705 }
2706
2707
2708 if (cmd == RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO) //32
2709 {
2710 DevMsg("libretro: acknowledging RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO\n");
2711 return true;
2712 }
2713
2714 if (cmd == RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS)
2715 {
2716 DevMsg("libretro: RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS\n");
2717
2718 unsigned controller, typeIndex;
2719 const struct retro_input_descriptor *controllerData = (const struct retro_input_descriptor*)data;
2720
2721 //info->currentPortTypes.clear();
2722
2723 for (controller = 0; controllerData[controller].description; controller++)
2724 {
2725 DevMsg("Unhandled Controller info:\n");
2726 DevMsg("\tPort: %u\n", controllerData[controller].port);
2727 DevMsg("\tDevice: %u\n", controllerData[controller].device);
2728 DevMsg("\tIndex: %u\n", controllerData[controller].index);
2729 DevMsg("\tID: %u\n", controllerData[controller].id);
2730 DevMsg("\tDescription: %u\n", controllerData[controller].description);
2731
2732 //info->currentPortTypes.push_back(1); // set every joystick to use the 1st entry (should always be RetroPad w/ id 1).
2733 // NOTE: 0 must ALWAYS gets inserted to the front when the current ports are gotten, which would mean Unplugged.
2734 // NOTE: These are vector indecies, NOT retro device IDs
2735
2736 //for (typeIndex = 0; typeIndex < portData[port].num_types; typeIndex++)
2737 // DevMsg("\t%s (ID: %u)\n", portData[port].types[typeIndex].desc, portData[port].types[typeIndex].id);
2738 }
2739
2740 //free((void*)info->portdata);
2741 //info->portdata = (struct retro_controller_info*)
2742 // calloc(port, sizeof(*info->portdata));
2743 //memcpy((void*)info->portdata, portData,
2744 // port * sizeof(*info->portdata));
2745
2746 //info->numports = port;
2747
2748
2749
2750 /*
2751 if (system)
2752 {
2753 free(system->ports.data);
2754 system->ports.data = (struct retro_controller_info*)
2755 calloc(i, sizeof(*system->ports.data));
2756 if (!system->ports.data)
2757 return false;
2758
2759 memcpy(system->ports.data, info,
2760 i * sizeof(*system->ports.data));
2761 system->ports.size = i;
2762 }
2763 break;
2764 */
2765
2766 return false;
2767 }
2768
2769 if (cmd == RETRO_ENVIRONMENT_SET_CONTROLLER_INFO) //35
2770 {
2771 DevMsg("libretro: RETRO_ENVIRONMENT_SET_CONTROLLER_INFO\n");
2772
2773 unsigned port, typeIndex;
2774 const struct retro_controller_info *portData = (const struct retro_controller_info*)data;
2775
2776 info->currentPortTypes.clear();
2777 for (port = 0; portData[port].types; port++)
2778 {
2779 DevMsg("Controller port: %u\n", port + 1);
2780 info->currentPortTypes.push_back(1); // set every joystick to use the 1st entry (should always be RetroPad w/ id 1).
2781 // NOTE: 0 must ALWAYS gets inserted to the front when the current ports are gotten, which would mean Unplugged.
2782 // NOTE: These are vector indecies, NOT retro device IDs
2783
2784 for (typeIndex = 0; typeIndex < portData[port].num_types; typeIndex++)
2785 DevMsg("\t%s (ID: %u)\n", portData[port].types[typeIndex].desc, portData[port].types[typeIndex].id);
2786 }
2787
2788 free((void*)info->portdata);
2789 info->portdata = (struct retro_controller_info*)
2790 calloc(port, sizeof(*info->portdata));
2791 memcpy((void*)info->portdata, portData,
2792 port * sizeof(*info->portdata));
2793
2794 //info->portdata = portData;
2795 info->numports = port;
2796 /*
2797 if (system)
2798 {
2799 free(system->ports.data);
2800 system->ports.data = (struct retro_controller_info*)
2801 calloc(i, sizeof(*system->ports.data));
2802 if (!system->ports.data)
2803 return false;
2804
2805 memcpy(system->ports.data, info,
2806 i * sizeof(*system->ports.data));
2807 system->ports.size = i;
2808 }
2809 break;
2810 */
2811
2812 return true;
2813 }
2814
2815 if (cmd == RETRO_ENVIRONMENT_SHUTDOWN)
2816 {
2817 //info->close = true;
2818 info->runninglibretrocores->last_error = "Core Shutdown";
2819 //if (info->core.find("ffmpeg_libretro.dll") != (info->core.length()-19)) // ffmpeg cores are gonna restart instead of shutting down.
2820 info->state = 6;
2821 // should probably show some kind of related items screen when a video ends.
2822 return true;
2823 }
2824
2825 const char * const names[] = {
2826 "(invalid)",
2827 "SET_ROTATION",
2828 "GET_OVERSCAN",
2829 "GET_CAN_DUPE",
2830 "(removed)",
2831 "(removed)",
2832 "SET_MESSAGE",
2833 "SHUTDOWN",
2834 "SET_PERFORMANCE_LEVEL",
2835 "GET_SYSTEM_DIRECTORY",
2836 "SET_PIXEL_FORMAT",
2837 "SET_INPUT_DESCRIPTORS",
2838 "SET_KEYBOARD_CALLBACK",
2839 "SET_DISK_CONTROL_INTERFACE",
2840 "SET_HW_RENDER",
2841 "GET_VARIABLE",
2842 "SET_VARIABLES",
2843 "GET_VARIABLE_UPDATE",
2844 "SET_SUPPORT_NO_GAME",
2845 "GET_LIBRETRO_PATH",
2846 "(removed)",
2847 "SET_FRAME_TIME_CALLBACK",
2848 "SET_AUDIO_CALLBACK",
2849 "GET_RUMBLE_INTERFACE",
2850 "GET_INPUT_DEVICE_CAPABILITIES",
2851 "GET_SENSOR_INTERFACE",
2852 "GET_CAMERA_INTERFACE",
2853 "GET_LOG_INTERFACE",
2854 "GET_PERF_INTERFACE",
2855 "GET_LOCATION_INTERFACE",
2856 "GET_CONTENT_DIRECTORY",
2857 "GET_SAVE_DIRECTORY",
2858 "SET_SYSTEM_AV_INFO",
2859 "SET_PROC_ADDRESS_CALLBACK",
2860 "SET_SUBSYSTEM_INFO",
2861 "SET_CONTROLLER_INFO",
2862 "SET_MEMORY_MAPS",
2863 "SET_GEOMETRY",
2864 "GET_USERNAME",
2865 "GET_LANGUAGE",
2866 };
2867
2868 if ((cmd&~RETRO_ENVIRONMENT_EXPERIMENTAL) < sizeof(names) / sizeof(*names))
2869 C_LibretroInstance::cbMessage(RETRO_LOG_WARN, "Ignored unsupported environment command #%u %s.", cmd, names[cmd&~RETRO_ENVIRONMENT_EXPERIMENTAL]);
2870 else
2871 C_LibretroInstance::cbMessage(RETRO_LOG_WARN, "Ignored unsupported environment command #%u.", cmd);
2872
2873 return false;
2874}
2875
2876void C_LibretroInstance::cbVideoRefresh(const void * data, unsigned width, unsigned height, size_t pitch)
2877{
2878// if (!data || AA_LIBRETRO_3D)
2879 // return;
2880 //glXSwapBuffers();
2881 //DevMsg("Video Refresh: %u %u %i\n", width, height, pitch);
2882 uint uId = ThreadGetCurrentId();
2883 C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
2884 if (!pLibretroInstance)
2885 return;
2886
2887 LibretroInstanceInfo_t* info = pLibretroInstance->GetInfo();
2888 if (info->close)
2889 return;
2890
2891 //if (pLibretroInstance->GetAdjustedStartTime() < 0)
2892 // pLibretroInstance->SetAdjustedStartTime();
2893
2894 if (!info->readyfornextframe || info->copyingframe || !data || AA_LIBRETRO_3D || pLibretroInstance->FastForwardSeconds() > pLibretroInstance->CurrentSeconds() + 10)
2895 {
2896 if (data)
2897 {
2898 //if (pLibretroInstance->GetNumSkippedFrames() > 10000)
2899 // info->fastforward = false;
2900
2901 pLibretroInstance->IncrementSkippedFrames();
2902 }
2903 return;
2904 }
2905
2906 info->lastframewidth = width;
2907 info->lastframeheight = height;
2908 info->lastframepitch = pitch;
2909
2910 //if (AA_LIBRETRO_3D && info->context_type != RETRO_HW_CONTEXT_NONE && data == RETRO_HW_FRAME_BUFFER_VALID)
2911 //glfwSwapBuffers(info->window);
2912
2913// if (data == RETRO_HW_FRAME_BUFFER_VALID)
2914 // DevMsg("hardware rendered frame given...\n");
2915
2916 //glfwSwapBuffers(info->window);
2917 //return;
2918
2919 info->lastrendered = gpGlobals->curtime;
2920
2921 info->readyfornextframe = false;
2922 info->readytocopyframe = false;
2923
2924 if (info->samplerate == 0)
2925 {
2926 DevMsg("Get AV info\n");
2927 struct retro_system_av_info avinfo;
2928 info->raw->get_system_av_info(&avinfo);
2929
2930 if (avinfo.timing.sample_rate > 0)
2931 {
2932 info->samplerate = float(avinfo.timing.sample_rate);
2933 info->framerate = float(avinfo.timing.fps);
2934 pLibretroInstance->SetFramerate(info->framerate);
2935 C_LibretroInstance::CreateAudioStream();
2936 }
2937 }
2938
2939
2940 //glDisable(GL_DEPTH_TEST); // here for illustrative purposes, depth test is initially DISABLED (key!)
2941 //glClearColor(0.3f, 0.4f, 0.1f, 1.0f);
2942 //glClear(GL_COLOR_BUFFER_BIT);
2943 //glfwMakeContextCurrent(info->window);
2944 //glfwSwapBuffers(info->window);
2945 //glfwPollEvents(); // this is what makes the window actually be responsive
2946
2947
2948 //WORD red_mask = 0xF800;
2949 //WORD green_mask = 0x7E0;
2950 //WORD blue_mask = 0x1F;
2951
2952 //DevMsg("Doin it\n");
2953
2954 //DevMsg("video refresh\n");
2955
2956 void* dest = malloc(pitch*height);
2957 if (AA_LIBRETRO_3D && info->context_type != RETRO_HW_CONTEXT_NONE && data == RETRO_HW_FRAME_BUFFER_VALID)
2958 {
2959 //DevMsg("Format is: %i %i x %i\n", info->videoformat, pitch, height);
2960 glReadPixels(0, 0, pitch / 3, height, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, dest);// GL_RGBA8 //GL_RGB
2961 //glfwSwapInterval(1);
2962 //glfwSwapBuffers(info->window);
2963 //glfwPollEvents();
2964 }
2965 else
2966 {
2967 Q_memcpy(dest, data, pitch*height);
2968 }
2969
2970 if (info->lastframedata)
2971 free(info->lastframedata);
2972
2973 info->lastframedata = dest;
2974 info->lastframewidth = width;
2975 info->lastframeheight = height;
2976 info->lastframepitch = pitch;
2977
2978 info->readytocopyframe = true;
2979 pLibretroInstance->MarkAsDirty();
2980 pLibretroInstance->IncrementRenderedFrames();
2981 //pLibretroInstance->m_mutex.unlock();
2982 //DevMsg("Child Unlock\n");
2983}
2984
2985void C_LibretroInstance::cbAudioSample(int16_t left, int16_t right)
2986{
2987 uint uId = ThreadGetCurrentId();
2988 C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
2989 LibretroInstanceInfo_t* info = pLibretroInstance->GetInfo();
2990 DevMsg("cbAudioSample\n");
2991 /*
2992 if (info->audiobufferpos < 512)
2993 {
2994 double leftRegular = (int)left * 1.0;// pLibretroVolumeScaleConVar->GetFloat();
2995 if (left > 32767)
2996 leftRegular = 32767.0;
2997 if (left < -32768.0)
2998 leftRegular = -32768.0;
2999
3000 double rightRegular = (int)right * 1.0;// s_pLibretroVolumeScaleConVar->GetFloat();
3001 if (right > 32767)
3002 rightRegular = 32767.0;
3003 if (right < -32768.0)
3004 rightRegular = -32768.0;
3005
3006 info->audiobuffer[info->audiobufferpos++] = (int16_t)leftRegular;
3007 info->audiobuffer[info->audiobufferpos++] = (int16_t)rightRegular;
3008 }
3009 */
3010}
3011
3012size_t C_LibretroInstance::cbAudioSampleBatch(const int16_t * data, size_t frames)
3013{
3014 uint uId = ThreadGetCurrentId();
3015 C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
3016
3017 if (!pLibretroInstance)
3018 return 0;
3019
3020 LibretroInstanceInfo_t* info = pLibretroInstance->GetInfo();
3021 if (!info->soundAllowed)
3022 return 0;
3023
3024 if (pLibretroInstance->FastForwardSeconds() > pLibretroInstance->CurrentSeconds() + 10)
3025 return 0;
3026 /*
3027 if ( info->processingaudio)
3028 return 0;
3029 else
3030 info->processingaudio = true;
3031 */
3032
3033 if (info->samplerate == 0)
3034 {
3035 struct retro_system_av_info avinfo;
3036 info->raw->get_system_av_info(&avinfo);
3037
3038 if (avinfo.timing.sample_rate > 0)
3039 {
3040 info->samplerate = int(avinfo.timing.sample_rate);
3041 info->framerate = int(avinfo.timing.fps);
3042 pLibretroInstance->SetFramerate(info->framerate);
3043 C_LibretroInstance::CreateAudioStream();
3044 }
3045 }
3046
3047 if (info->samplerate <= 0 || frames <= 0 || !info->audiostream ) // || s_threadAudioParams.frames
3048 return 0;
3049
3050 //DevMsg("Writing %u frames: %i\n", frames, data);
3051
3052 //if ( info->volume > 0.0f )
3053
3054 /*
3055 //float buffer[SAMPLES_PER_BUFFER];
3056 //volume in dB 0db = unity gain, no attenuation, full amplitude signal
3057 // -20db = 10x attenuation, significantly more quiet
3058 float volumeLevelDb = -6.f; //cut amplitude in half; same as 0.5 above
3059 const float VOLUME_REFERENCE = 1.f;
3060 const float volumeMultiplier = (VOLUME_REFERENCE * pow(10, (volumeLevelDb / 20.f);
3061 for (int i = 0; i < SAMPLES_PER_BUFFER; ++i)
3062 {
3063 data[i] *= volumeMultiplier;
3064 }
3065 */
3066
3067 //PaError err = Pa_WriteStream(info->audiostream, data, frames);// paFramesPerBufferUnspecified);
3068
3069 // AMPLIFY THE AUDIO HERE!
3070 float volume = info->volume;
3071 int16_t sample[2];
3072 double leftRegular, rightRegular;
3073 int16_t left, right;
3074
3075 //pLibretroInstance->SetIsAudioPlaying(true);
3076 for (int i = 0; i < frames * 2; i = i + 2)
3077 {
3078 left = data[i];
3079 right = data[i + 1];
3080
3081 leftRegular = (double)left * volume;
3082 if (left > 32767)
3083 leftRegular = 32767.0;
3084 if (left < -32768.0)
3085 leftRegular = -32768.0;
3086
3087 rightRegular = (double)right * volume;
3088 if (right > 32767)
3089 rightRegular = 32767.0;
3090 if (right < -32768.0)
3091 rightRegular = -32768.0;
3092
3093 sample[0] = (int16_t)leftRegular;
3094 sample[1] = (int16_t)rightRegular;
3095
3096 PaError err = Pa_WriteStream(info->audiostream, sample, 1);
3097 }
3098 //pLibretroInstance->SetIsAudioPlaying(false);
3099
3100 return frames;
3101 /*
3102 int16_t* buffer = info->audiobuffer;
3103 unsigned int size = info->audiobuffersize;
3104 unsigned int pos = info->audiobufferpos;
3105
3106 unsigned int processedCount = size - pos;
3107 if (processedCount > frames)
3108 processedCount = frames;
3109
3110 if (processedCount > 0)
3111 {
3112 Q_memcpy(buffer + (pos * 2), data, sizeof(int16_t) * processedCount * 2);
3113 info->audiobufferpos += processedCount;
3114 }
3115
3116 return processedCount;
3117 */
3118}
3119
3120void C_LibretroInstance::cbInputPoll(void)
3121{
3122 //DevMsg("cbInputPoll\n");
3123 // TODO: Implement this. it might be related to timing of analog & mouse input devices because those expect offsets relative to the last time they were polled.
3124 // This is likely supposed to trigger the polling of input states on the FE for the core to later retrieve with InputState.
3125 //DevMsg("libretro: Input Poll called.\n");
3126}
3127
3128int16_t C_LibretroInstance::cbInputState(unsigned port, unsigned device, unsigned index, unsigned id)
3129{
3130 uint uId = ThreadGetCurrentId();
3131 C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
3132
3133 if (!pLibretroInstance)
3134 return (int16_t)0;
3135
3136 int iCurrentSeconds = pLibretroInstance->CurrentSeconds();
3137 LibretroInstanceInfo_t* info = pLibretroInstance->GetInfo();
3138
3139 // only accept input from port0 device1 index0
3140 if (info->close || !info->inputstate || port != 0 || device != 1 || index != 0)
3141 return (int16_t)0;
3142
3143 if (pLibretroInstance->FastForwardSeconds() > iCurrentSeconds + 10)
3144 {
3145 //DevMsg("Dif: %i\n", (pLibretroInstance->FastForwardSeconds() > iCurrentSeconds + 10));
3146 if (port == 0 && device == 1 && index == 0)
3147 {
3148 if (id == 4 && pLibretroInstance->FastForwardSeconds() > iCurrentSeconds + 60) // 4 = 60 seconds
3149 {
3150 if (pLibretroInstance->GetLastDelta() == 0)
3151 {
3152 pLibretroInstance->FastForward(60, true);
3153 return (int16_t)1;
3154 }
3155 else
3156 {
3157 pLibretroInstance->SetLastDelta(0);
3158 return (int16_t)0;
3159 }
3160 }
3161 else if (id == 7 && pLibretroInstance->FastForwardSeconds() <= iCurrentSeconds + 60) // 7 = 10 seconds
3162 {
3163 if (pLibretroInstance->GetLastDelta() == 0 || pLibretroInstance->GetLastDelta() == 60)
3164 {
3165 pLibretroInstance->FastForward(10, true);
3166 return (int16_t)1;
3167 }
3168 else
3169 {
3170 pLibretroInstance->SetLastDelta(0);
3171 return (int16_t)0;
3172 }
3173 }
3174 }
3175 return (int16_t)0;
3176 }
3177
3178 //int intVal = info->inputstate->GetInt(VarArgs("port%u/device%u/index%u/key%u", port, device, index, id), 0);
3179 //return (int16_t)intVal;
3180
3181 std::string keyPath = "port" + std::to_string(port) + "/device" + std::to_string(device) + "/index" + std::to_string(index) + "/key" + std::to_string(id);
3182 int val = (int16_t)info->inputstate->GetInt(keyPath.c_str());
3183
3184 if (port == 0 && device == 1 && index == 0)// && val == 1 && pLibretroInstance->GetLastDelta() == 0)
3185 {
3186 if (id == 4) // 4 = 60 seconds
3187 {
3188 //DevMsg("%i vs %i\n", val, pLibretroInstance->GetLastDelta());
3189 if (val != 0 && pLibretroInstance->GetLastDelta() == 0)
3190 pLibretroInstance->FastForward(60);
3191 else if (val == 0 && pLibretroInstance->GetLastDelta() == 60)
3192 pLibretroInstance->SetLastDelta(0);
3193 }
3194 else if (id == 7) // 7 = 10 seconds
3195 {
3196 if (val != 0 && pLibretroInstance->GetLastDelta() == 0)
3197 pLibretroInstance->FastForward(10);
3198 else if (val == 0 && pLibretroInstance->GetLastDelta() == 10)
3199 pLibretroInstance->SetLastDelta(0);
3200 }
3201 else if (id == 5) // 5 = -60 seconds
3202 {
3203 if (val != 0 && pLibretroInstance->GetLastDelta() == 0)
3204 pLibretroInstance->Rewind(-60);
3205 else if (val == 0 && pLibretroInstance->GetLastDelta() == -60)
3206 pLibretroInstance->SetLastDelta(0);
3207 }
3208 else if (id == 6) // 6 = -10 seconds
3209 {
3210 if (val != 0 && pLibretroInstance->GetLastDelta() == 0)
3211 pLibretroInstance->Rewind(-10);
3212 else if (val == 0 && pLibretroInstance->GetLastDelta() == -10)
3213 pLibretroInstance->SetLastDelta(0);
3214 }
3215 }
3216 //if (info->inputstate->GetInt(keyPath.c_str()))
3217 // DevMsg("KEY: %s\n", keyPath.c_str());
3218 return (int16_t)val;
3219
3220 //KeyValues* kv = info->inputstate->FindKey();
3221 //if (!kv)
3222// return (int16_t)0;
3223
3224 //int intVal = kv->GetInt();
3225 //if ( id > 11 && intVal != 0)
3226 // DevMsg("Looking for ID: %u = %i\n", id, intVal);
3227
3228 //return (int16_t)intVal;
3229 //pLibretroInstance->GetInputState(info, port, device, index, id);
3230
3231 /*
3232 #define RETRO_DEVICE_ID_JOYPAD_B 0
3233 #define RETRO_DEVICE_ID_JOYPAD_Y 1
3234 #define RETRO_DEVICE_ID_JOYPAD_SELECT 2
3235 #define RETRO_DEVICE_ID_JOYPAD_START 3
3236 #define RETRO_DEVICE_ID_JOYPAD_UP 4
3237 #define RETRO_DEVICE_ID_JOYPAD_DOWN 5
3238 #define RETRO_DEVICE_ID_JOYPAD_LEFT 6
3239 #define RETRO_DEVICE_ID_JOYPAD_RIGHT 7
3240 #define RETRO_DEVICE_ID_JOYPAD_A 8
3241 #define RETRO_DEVICE_ID_JOYPAD_X 9
3242 #define RETRO_DEVICE_ID_JOYPAD_L 10
3243 #define RETRO_DEVICE_ID_JOYPAD_R 11
3244 #define RETRO_DEVICE_ID_JOYPAD_L2 12
3245 #define RETRO_DEVICE_ID_JOYPAD_R2 13
3246 #define RETRO_DEVICE_ID_JOYPAD_L3 14
3247 #define RETRO_DEVICE_ID_JOYPAD_R3 15
3248 */
3249 //DevMsg("libretro: Input State called.\n");
3250 //DevMsg("libretro: Input State called with port %u, device %u, index %u, and ID %u.\n", port, device, index, id);
3251
3252 // only accept input from player 1
3253 //if (port != 0 || device != 1 || index != 0)
3254 // return (int16_t)0;
3255
3256 //DevMsg("%i %i %i\n", port, device, index);
3257 // FIXME: index could allow for additional devices PER port, which would require significant changes to support. However AArcade will rarely be used by more than 1 local player, so support for index probably isn't needed. supoorting N input ports is enough.
3258
3259 //std::string retrokey = g_pAnarchyManager->GetLibretroManager()->RetroKeyboardKeyToString((retro_key)index);
3260 //std::string retrodevice = g_pAnarchyManager->GetLibretroManager()->RetroDeviceToString(device);
3261
3262 //int max = 32767;
3263 //max *= info->inputstate[retrokey];
3264 //int16_t max = 0x7fff; //32767
3265
3266
3267// if (info->inputstate.find(retrokey) != info->inputstate.end() )
3268// return (int16_t)info->inputstate[retrokey];
3269// else
3270// return (int16_t)0;
3271}
3272
3273void C_LibretroInstance::ResizeFrameFromRGB565(const void* pSrc, void* pDst, unsigned int sourceWidth, unsigned int sourceHeight, size_t sourcePitch, unsigned int sourceDepth, unsigned int destWidth, unsigned int destHeight, size_t destPitch, unsigned int destDepth)
3274{
3275// uint uId = ThreadGetCurrentId();
3276// C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
3277// LibretroInstanceInfo_t* info = pLibretroInstance->GetInfo();
3278
3279 LibretroInstanceInfo_t* info = m_info;
3280 if (!info->lastframedata)
3281 return;
3282
3283 //info->readyfornextframe = false;
3284
3285 // DevMsg("Resizing a %ux%u %iBBP (%i pitch) image to %ux%u %iBBP (%i pitch)\n", sourceWidth, sourceHeight, sourceDepth, sourcePitch, destWidth, destHeight, destDepth, destPitch);
3286
3287 WORD red_mask = 0xF800;
3288 WORD green_mask = 0x7E0;
3289 WORD blue_mask = 0x1F;
3290
3291 uint16* pRealSrc = (uint16*)pSrc;
3292
3293 unsigned char* pDstRow = (unsigned char*)pDst;
3294 for (int dstY = 0; dstY<destHeight; dstY++)
3295 {
3296
3297 unsigned int srcY = dstY * sourceHeight / destHeight;
3298 uint16* pSrcRow = pRealSrc + (srcY * ((int)sourcePitch / 2));
3299
3300 unsigned char* pDstCur = pDstRow;
3301
3302 for (int dstX = 0; dstX<destWidth; dstX++)
3303 {
3304 int srcX = dstX * sourceWidth / destWidth;
3305
3306 int red = (pSrcRow[srcX] & red_mask) >> 11;
3307 int green = (pSrcRow[srcX] & green_mask) >> 5;
3308 int blue = (pSrcRow[srcX] & blue_mask);
3309
3310 pDstCur[0] = blue * (255 / 31);
3311 pDstCur[1] = green * (255 / 63);
3312 pDstCur[2] = red * (255 / 31);
3313
3314 pDstCur[3] = 255;
3315
3316 pDstCur += destDepth;
3317 }
3318
3319 pDstRow += destPitch;
3320 }
3321
3322 //info->readyfornextframe = true;
3323}
3324
3325void C_LibretroInstance::ResizeFrameFromRGB1555(const void* pSrc, void* pDst, unsigned int sourceWidth, unsigned int sourceHeight, size_t sourcePitch, unsigned int sourceDepth, unsigned int destWidth, unsigned int destHeight, size_t destPitch, unsigned int destDepth)
3326{
3327// uint uId = ThreadGetCurrentId();
3328// C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
3329// LibretroInstanceInfo_t* info = pLibretroInstance->GetInfo();
3330
3331 LibretroInstanceInfo_t* info = m_info;
3332 if (!info->lastframedata)
3333 return;
3334
3335 //info->readyfornextframe = false;
3336
3337 // DevMsg("Resizing a %ux%u %iBBP (%i pitch) image to %ux%u %iBBP (%i pitch)\n", sourceWidth, sourceHeight, sourceDepth, sourcePitch, destWidth, destHeight, destDepth, destPitch);
3338
3339 WORD red_mask = 0x7C00;
3340 WORD green_mask = 0x03E0;
3341 WORD blue_mask = 0x001F;
3342
3343 uint16* pRealSrc = (uint16*)pSrc;
3344
3345 unsigned char* pDstRow = (unsigned char*)pDst;
3346 for (int dstY = 0; dstY<destHeight; dstY++)
3347 {
3348
3349 unsigned int srcY = dstY * sourceHeight / destHeight;
3350 uint16* pSrcRow = pRealSrc + (srcY * ((int)sourcePitch / 2));
3351
3352 unsigned char* pDstCur = pDstRow;
3353
3354 for (int dstX = 0; dstX<destWidth; dstX++)
3355 {
3356 int srcX = dstX * sourceWidth / destWidth;
3357
3358 int red = (pSrcRow[srcX] & red_mask) >> 10;
3359 int green = (pSrcRow[srcX] & green_mask) >> 5;
3360 int blue = (pSrcRow[srcX] & blue_mask);
3361
3362 pDstCur[0] = blue * (255 / 31);
3363 pDstCur[1] = green * (255 / 31);
3364 pDstCur[2] = red * (255 / 31);
3365
3366 pDstCur[3] = 255;
3367
3368 pDstCur += destDepth;
3369 }
3370
3371 pDstRow += destPitch;
3372 }
3373
3374 //info->readyfornextframe = true;
3375}
3376
3377void C_LibretroInstance::ResizeFrameFromXRGB8888(const void* pSrc, void* pDst, unsigned int sourceWidth, unsigned int sourceHeight, size_t sourcePitch, unsigned int sourceDepth, unsigned int destWidth, unsigned int destHeight, size_t destPitch, unsigned int destDepth)
3378{
3379 //DevMsg("Thread ID: %u\n", ThreadGetCurrentId);
3380// uint uId = ThreadGetCurrentId();
3381// C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
3382// LibretroInstanceInfo_t* info = pLibretroInstance->GetInfo();
3383 //LibretroInstanceInfo_t* info = m_info;
3384
3385 //if (!m_info->lastframedata)
3386// DevMsg("Main Lock\n");
3387 if (!m_info->lastframedata)
3388 return;
3389
3390// m_mutex.lock();
3391// if (!m_info->lastframedata || !m_info->readyfornextframe)
3392 // return;
3393
3394
3395 //m_info->readyfornextframe = false;
3396
3397 //DevMsg("Resizing a %ux%u %iBBP (%i pitch) image to %ux%u %iBBP (%i pitch)\n", sourceWidth, sourceHeight, sourceDepth, sourcePitch, destWidth, destHeight, destDepth, destPitch);
3398// DevMsg("Test: %s\n", pDest);
3399
3400 unsigned int sourceWidthCopy = sourceWidth;
3401 unsigned int sourceHeightCopy = sourceHeight;
3402 size_t sourcePitchCopy = sourcePitch;
3403 unsigned int sourceDepthCopy = sourceDepth;
3404
3405 //void* pSrcCopy = malloc(sourcePitchCopy * sourceHeightCopy);
3406 //Q_memcpy(pSrcCopy, pSrc, sourcePitchCopy * sourceHeightCopy);
3407
3408
3409 const unsigned char* pRealSrc = (const unsigned char*)pSrc;
3410 unsigned char* pDstRow = (unsigned char*)pDst;
3411 for (int dstY = 0; dstY<destHeight; dstY++)
3412 {
3413 unsigned int srcY = dstY * sourceHeight / destHeight;
3414 const unsigned char* pSrcRow = pRealSrc + srcY*(sourcePitch);
3415
3416 unsigned char* pDstCur = pDstRow;
3417
3418 for (int dstX = 0; dstX<destWidth; dstX++)
3419 {
3420 int srcX = dstX * sourceWidth / destWidth;
3421 pDstCur[0] = pSrcRow[srcX*sourceDepth + 0];
3422 pDstCur[1] = pSrcRow[srcX*sourceDepth + 1];
3423 pDstCur[2] = pSrcRow[srcX*sourceDepth + 2];
3424
3425 pDstCur[3] = 255;
3426
3427 pDstCur += destDepth;
3428 }
3429
3430 pDstRow += destPitch;
3431 }
3432
3433 /*
3434 const unsigned char* pRealSrc = (const unsigned char*)pSrc;
3435 unsigned char* pDstRow = (unsigned char*)pDst;
3436 for (int dstY = 0; dstY<destHeight; dstY++)
3437 {
3438 unsigned int srcY = dstY * sourceHeight / destHeight;
3439 const unsigned char* pSrcRow = pRealSrc + srcY*(sourcePitch);
3440
3441 unsigned char* pDstCur = pDstRow;
3442
3443 for (int dstX = 0; dstX<destWidth; dstX++)
3444 {
3445 int srcX = dstX * sourceWidth / destWidth;
3446 pDstCur[0] = pSrcRow[srcX*sourceDepth + 0];
3447 pDstCur[1] = pSrcRow[srcX*sourceDepth + 1];
3448 pDstCur[2] = pSrcRow[srcX*sourceDepth + 2];
3449
3450 pDstCur[3] = 255;
3451
3452 pDstCur += destDepth;
3453 }
3454
3455 pDstRow += destPitch;
3456 }
3457 */
3458
3459// free(pSrcCopy);
3460
3461 //m_info->readyfornextframe = true;
3462
3463// m_mutex.unlock();
3464// DevMsg("Main Unlock\n");
3465}
3466
3467void C_LibretroInstance::ResizeFrameFromRGB888(const void* pSrc, void* pDst, unsigned int sourceWidth, unsigned int sourceHeight, size_t sourcePitch, unsigned int sourceDepth, unsigned int destWidth, unsigned int destHeight, size_t destPitch, unsigned int destDepth)
3468{
3469 //DevMsg("Thread ID: %u\n", ThreadGetCurrentId);
3470 // uint uId = ThreadGetCurrentId();
3471 // C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
3472 // LibretroInstanceInfo_t* info = pLibretroInstance->GetInfo();
3473 //LibretroInstanceInfo_t* info = m_info;
3474
3475 //if (!m_info->lastframedata)
3476 // DevMsg("Main Lock\n");
3477 if (!m_info->lastframedata)
3478 return;
3479
3480 // m_mutex.lock();
3481 // if (!m_info->lastframedata || !m_info->readyfornextframe)
3482 // return;
3483
3484
3485 //m_info->readyfornextframe = false;
3486
3487 //DevMsg("Resizing a %ux%u %iBBP (%i pitch) image to %ux%u %iBBP (%i pitch)\n", sourceWidth, sourceHeight, sourceDepth, sourcePitch, destWidth, destHeight, destDepth, destPitch);
3488 // DevMsg("Test: %s\n", pDest);
3489
3490 unsigned int sourceWidthCopy = sourceWidth;
3491 unsigned int sourceHeightCopy = sourceHeight;
3492 size_t sourcePitchCopy = sourcePitch;
3493 unsigned int sourceDepthCopy = sourceDepth;
3494
3495 //void* pSrcCopy = malloc(sourcePitchCopy * sourceHeightCopy);
3496 //Q_memcpy(pSrcCopy, pSrc, sourcePitchCopy * sourceHeightCopy);
3497
3498
3499 const unsigned char* pRealSrc = (const unsigned char*)pSrc;
3500 unsigned char* pDstRow = (unsigned char*)pDst;
3501 for (int dstY = 0; dstY<destHeight; dstY++)
3502 {
3503 unsigned int srcY = dstY * sourceHeight / destHeight;
3504 const unsigned char* pSrcRow = pRealSrc + srcY*(sourcePitch);
3505
3506 unsigned char* pDstCur = pDstRow;
3507
3508 for (int dstX = 0; dstX<destWidth; dstX++)
3509 {
3510 int srcX = dstX * sourceWidth / destWidth;
3511 pDstCur[0] = pSrcRow[srcX*sourceDepth + 2];
3512 pDstCur[1] = pSrcRow[srcX*sourceDepth + 1];
3513 pDstCur[2] = pSrcRow[srcX*sourceDepth + 0];
3514
3515 pDstCur[3] = 255;
3516
3517 pDstCur += destDepth;
3518 }
3519
3520 pDstRow += destPitch;
3521 }
3522
3523 /*
3524 const unsigned char* pRealSrc = (const unsigned char*)pSrc;
3525 unsigned char* pDstRow = (unsigned char*)pDst;
3526 for (int dstY = 0; dstY<destHeight; dstY++)
3527 {
3528 unsigned int srcY = dstY * sourceHeight / destHeight;
3529 const unsigned char* pSrcRow = pRealSrc + srcY*(sourcePitch);
3530
3531 unsigned char* pDstCur = pDstRow;
3532
3533 for (int dstX = 0; dstX<destWidth; dstX++)
3534 {
3535 int srcX = dstX * sourceWidth / destWidth;
3536 pDstCur[0] = pSrcRow[srcX*sourceDepth + 0];
3537 pDstCur[1] = pSrcRow[srcX*sourceDepth + 1];
3538 pDstCur[2] = pSrcRow[srcX*sourceDepth + 2];
3539
3540 pDstCur[3] = 255;
3541
3542 pDstCur += destDepth;
3543 }
3544
3545 pDstRow += destPitch;
3546 }
3547 */
3548
3549 // free(pSrcCopy);
3550
3551 //m_info->readyfornextframe = true;
3552
3553 // m_mutex.unlock();
3554 // DevMsg("Main Unlock\n");
3555}
3556
3557void C_LibretroInstance::CopyLastFrame(unsigned char* dest, unsigned int width, unsigned int height, size_t pitch, unsigned int depth)
3558{
3559 if ( m_info->copyingframe || !m_info->readytocopyframe || g_pAnarchyManager->GetSuspendEmbedded())
3560 return;
3561
3562 m_info->copyingframe = true;
3563 m_info->readytocopyframe = false;
3564
3565
3566
3567 //DevMsg("Render: Do it!\n");
3568 //RETRO_PIXEL_FORMAT_0RGB1555
3569
3570// uint uId = ThreadGetCurrentId();
3571// C_LibretroInstance* pLibretroInstance = g_pAnarchyManager->GetLibretroManager()->FindLibretroInstance(uId);
3572 //LibretroInstanceInfo_t* info = pLibretroInstance->GetInfo();
3573 //LibretroInstanceInfo_t* info = m_info;
3574
3575
3576 if (m_info->context_type != RETRO_HW_CONTEXT_NONE)
3577 {
3578 this->ResizeFrameFromRGB888(m_info->lastframedata, dest, m_info->lastframewidth, m_info->lastframeheight, m_info->lastframepitch, 3, width, height, pitch, depth);
3579 }
3580 else
3581 {
3582 if (m_info->videoformat == RETRO_PIXEL_FORMAT_RGB565)
3583 this->ResizeFrameFromRGB565(m_info->lastframedata, dest, m_info->lastframewidth, m_info->lastframeheight, m_info->lastframepitch, 3, width, height, pitch, depth);
3584 else if (m_info->videoformat == RETRO_PIXEL_FORMAT_XRGB8888)
3585 this->ResizeFrameFromXRGB8888(m_info->lastframedata, dest, m_info->lastframewidth, m_info->lastframeheight, m_info->lastframepitch, 4, width, height, pitch, depth);
3586 else
3587 this->ResizeFrameFromRGB1555(m_info->lastframedata, dest, m_info->lastframewidth, m_info->lastframeheight, m_info->lastframepitch, 3, width, height, pitch, depth);
3588 }
3589
3590 m_info->copyingframe = false;
3591}
3592
3593void C_LibretroInstance::OnProxyBind(C_BaseEntity* pBaseEntity)
3594{
3595 if (g_pAnarchyManager->GetSuspendEmbedded())
3596 return;
3597
3598// if (m_id == "images")
3599// return;
3600
3601 /*
3602 if ( pBaseEntity )
3603 DevMsg("WebTab: OnProxyBind: %i\n", pBaseEntity->entindex());
3604 else
3605 DevMsg("WebTab: OnProxyBind\n");
3606 */
3607
3608 // visiblity test
3609 if (m_iLastVisibleFrame < gpGlobals->framecount)
3610 {
3611 m_iLastVisibleFrame = gpGlobals->framecount;
3612 //g_pAnarchyManager->GetCanvasManager()->RenderSeen(this);
3613 /*
3614 if (!g_pAnarchyManager->GetCanvasManager()->IsPriorityEmbeddedInstance(this))
3615 {
3616 if (!g_pAnarchyManager->GetCanvasManager()->IncrementVisibleCanvasesCurrentFrame(this))
3617 return;
3618 }
3619 else
3620 {
3621 if (!g_pAnarchyManager->GetCanvasManager()->IncrementVisiblePriorityCanvasesCurrentFrame(this))
3622 return;
3623 }*/
3624
3625
3626 //if (m_iLastRenderedFrame < gpGlobals->framecount)
3627 //{
3628 /*
3629 if (!g_pAnarchyManager->GetCanvasManager()->IsPriorityEmbeddedInstance(this))
3630 g_pAnarchyManager->GetCanvasManager()->IncrementVisibleCanvasesCurrentFrame();
3631 else
3632 g_pAnarchyManager->GetCanvasManager()->IncrementVisiblePriorityCanvasesCurrentFrame();
3633 */
3634
3635 //m_info->readytocopyframe
3636 //
3637 if (m_bIsDirty && g_pAnarchyManager->GetCanvasManager()->RenderSeen(this) && g_pAnarchyManager->GetCanvasManager()->ShouldRender(this))
3638 Render();
3639 //}
3640 }
3641}
3642
3643bool C_LibretroInstance::IsDirty()
3644{
3645 //return m_bIsDirty && m_info->readyfornextframe;
3646 return m_bIsDirty && !m_info->readyfornextframe && m_info->readytocopyframe;
3647
3648
3649
3650 /*if (!!!m_info || !m_info->readytocopyframe)
3651 return false;
3652 else
3653 return true;*/
3654}
3655
3656void C_LibretroInstance::Render()
3657{
3658// if (m_id == "images")
3659 // return;
3660 //DevMsg("Rendering texture: %s\n", m_pTexture->GetName());
3661 // DevMsg("Render Web Tab: %s\n", this->GetTexture()->Ge>GetId().c_str());
3662 //DevMsg("WebTab: Render: %s on %i\n", m_id.c_str(), gpGlobals->framecount);
3663 g_pAnarchyManager->GetCanvasManager()->GetOrCreateRegen()->SetEmbeddedInstance(this);
3664 m_pTexture->Download();
3665 g_pAnarchyManager->GetCanvasManager()->GetOrCreateRegen()->SetEmbeddedInstance(null);
3666
3667 m_iLastRenderedFrame = gpGlobals->framecount;
3668
3669 g_pAnarchyManager->GetCanvasManager()->AllowRender(this);
3670 //if (g_pAnarchyManager->GetCanvasManager()->IsPriorityEmbeddedInstance(this))
3671 // g_pAnarchyManager->GetCanvasManager()->SetLastPriorityRenderedFrame(gpGlobals->framecount);
3672 //else
3673 // g_pAnarchyManager->GetCanvasManager()->SetLastRenderedFrame(gpGlobals->framecount);
3674}
3675
3676void C_LibretroInstance::RegenerateTextureBits(ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect)
3677{
3678 if (g_pAnarchyManager->GetSuspendEmbedded())
3679 return;
3680
3681 if (!m_info->state == 5)
3682 return;
3683
3684 this->CopyLastFrame(pVTFTexture->ImageData(0, 0, 0), pSubRect->width, pSubRect->height, pSubRect->width * 4, 4);
3685
3686 // fix the bleeding edges on projectors
3687 if (m_pProjectorFixConVar->GetBool())
3688 {
3689 CPixelWriter pixelWriter;
3690 pixelWriter.SetPixelMemory(pVTFTexture->Format(), pVTFTexture->ImageData(0, 0, 0), pVTFTexture->RowSizeInBytes(0));
3691
3692 int xmax = pSubRect->x + pSubRect->width;
3693 int ymax = pSubRect->y + pSubRect->height;
3694 int x, y;
3695 for (y = pSubRect->y; y < ymax; ++y)
3696 {
3697 pixelWriter.Seek(pSubRect->x, y);
3698 x = pSubRect->x;
3699 while (x < xmax)
3700 {
3701 if (y == pSubRect->y || y == ymax - 1 || x == xmax - 1)
3702 {
3703 pixelWriter.WritePixel(0, 0, 0, 0);
3704 x++;
3705 }
3706 else if (x == pSubRect->x)
3707 {
3708 pixelWriter.WritePixel(0, 0, 0, 0);
3709 pixelWriter.SkipPixels(xmax - 2);
3710 x = xmax - 1;
3711 }
3712 else
3713 {
3714 pixelWriter.SkipPixels(1);
3715 x++;
3716 }
3717 }
3718 }
3719 }
3720
3721 m_bIsDirty = false;
3722 m_info->readyfornextframe = true;
3723}
3724
3725C_InputListener* C_LibretroInstance::GetInputListener()
3726{
3727 return g_pAnarchyManager->GetLibretroManager()->GetInputListener();
3728}
3729
3730bool C_LibretroInstance::SetGame(std::string file)
3731{
3732 if (!m_info || m_info->gameloaded || m_info->close)
3733 return false;
3734
3735 m_info->game = file;
3736 return true;
3737}
3738
3739void C_LibretroInstance::SetOriginalGame(std::string file)
3740{
3741 m_originalGame = file;
3742 m_originalGameHash = g_pAnarchyManager->GenerateLegacyHash(file.c_str());
3743}
3744
3745C_EmbeddedInstance* C_LibretroInstance::GetParentSelectedEmbeddedInstance()
3746{
3747 return g_pAnarchyManager->GetLibretroManager()->GetSelectedLibretroInstance();
3748}
3749
3750void C_LibretroInstance::SaveLibretroKeybind(std::string type, unsigned int retroport, unsigned int retrodevice, unsigned int retroindex, unsigned int retrokey, std::string steamkey)
3751{
3752 // pretty CORE
3753 std::string prettyCore = m_info->core;
3754 size_t found = prettyCore.find_last_of("/\\");
3755 if (found != std::string::npos)
3756 prettyCore = prettyCore.substr(found + 1);
3757
3758 found = prettyCore.find_last_of(".");
3759 if (found != std::string::npos)
3760 prettyCore = prettyCore.substr(0, found);
3761 prettyCore.erase(std::remove(prettyCore.begin(), prettyCore.end(), '.'), prettyCore.end());
3762
3763 // pretty GAME
3764 std::string prettyGame = m_info->game;
3765 found = prettyGame.find_last_of("/\\");
3766 if (found != std::string::npos)
3767 prettyGame = prettyGame.substr(found + 1);
3768
3769 found = prettyGame.find_last_of(".");
3770 if (found != std::string::npos)
3771 prettyGame = prettyGame.substr(0, found);
3772 prettyGame.erase(std::remove(prettyGame.begin(), prettyGame.end(), '.'), prettyGame.end());
3773
3774 //std::replace(prettyGame.begin(), prettyGame.end(), '.', '-');
3775
3776 // now do keybind stuff
3777 KeyValues* kv;
3778 std::string savePath;
3779 if (type == "libretro")
3780 {
3781 kv = m_info->libretrokeybinds; // LIBRETRO-WIDE KEYBINDS
3782 savePath = "libretro\\user";
3783 }
3784 else if (type == "core")
3785 {
3786 kv = m_info->corekeybinds; // CORE-SPECIFIC KEYBINDS
3787 savePath = "libretro\\user\\" + prettyCore;
3788 }
3789 else if (type == "game")
3790 {
3791 kv = m_info->gamekeybinds; // GAME-SPECIFIC KEYBINDS
3792 savePath = "libretro\\user\\" + prettyCore + "\\" + prettyGame;
3793 }
3794
3795 // add the info to the KV: PORT/INDEX/TYPE/RETORKEY = STEAMKEY
3796 kv->SetString(VarArgs("port%u/device%u/index%u/key%u", retroport, retrodevice, retroindex, retrokey), steamkey.c_str());
3797
3798 // save the KV out
3799 // (load up a fresh version and write ONLY this value to it to avoid saving other shit that we don't really want to save at this time.)
3800 KeyValues* fresh;
3801 if (type != "libretro")
3802 {
3803 fresh = new KeyValues("keybinds");
3804 fresh->LoadFromFile(g_pFullFileSystem, VarArgs("%s\\keybinds.key", savePath.c_str()), "DEFAULT_WRITE_PATH");
3805 }
3806 else
3807 fresh = kv;
3808
3809 if (steamkey != "default")
3810 fresh->SetString(VarArgs("port%u/device%u/index%u/key%u", retroport, retrodevice, retroindex, retrokey), steamkey.c_str());
3811 else
3812 fresh->SetString(VarArgs("port%u/device%u/index%u/key%u", retroport, retrodevice, retroindex, retrokey), "");
3813
3814 g_pFullFileSystem->CreateDirHierarchy(savePath.c_str(), "DEFAULT_WRITE_PATH");
3815 fresh->SaveToFile(g_pFullFileSystem, VarArgs("%s\\keybinds.key", savePath.c_str()), "DEFAULT_WRITE_PATH");
3816 if (type != "libretro")
3817 fresh->deleteThis();
3818
3819 //g_pFullFileSystem->CreateDirHierarchy(savePath.c_str(), "DEFAULT_WRITE_PATH");
3820 //kv->SaveToFile(g_pFullFileSystem, VarArgs("%s\\keybinds.key", savePath.c_str()), "DEFAULT_WRITE_PATH");
3821
3822 // update the ACTIVE keymap of pointers // OBSOLETE: just check all 3 KV's in hiarchy each poll
3823 //retro_key retrokeyresolved = g_pAnarchyManager->GetLibretroManager()->StringToRetroKeyEnum(retrokey);
3824 //vgui::KeyCode steamkeyresolved = g_pAnarchyManager->GetInputManager()->StringToSteamKeyEnum(steamkey);
3825 //m_info->activekeybinds->SetString(VarArgs("port%u/%s/%s", retroport, retrotype.c_str(), retrokey.c_str()), steamkey.c_str());
3826}
3827
3828void C_LibretroInstance::GetLastMouse(float &fMouseX, float &fMouseY)
3829{
3830 fMouseX = m_fLastMouseX;
3831 fMouseY = m_fLastMouseY;
3832}
3833
3834void C_LibretroInstance::SaveLibretroOption(std::string type, std::string name_internal, std::string value)
3835{
3836 // pretty CORE
3837 std::string prettyCore = m_info->core;
3838 size_t found = prettyCore.find_last_of("/\\");
3839 if (found != std::string::npos)
3840 prettyCore = prettyCore.substr(found + 1);
3841
3842 found = prettyCore.find_last_of(".");
3843 if (found != std::string::npos)
3844 prettyCore = prettyCore.substr(0, found);
3845 prettyCore.erase(std::remove(prettyCore.begin(), prettyCore.end(), '.'), prettyCore.end());
3846
3847 // pretty GAME
3848 std::string prettyGame = m_info->game;
3849 found = prettyGame.find_last_of("/\\");
3850 if (found != std::string::npos)
3851 prettyGame = prettyGame.substr(found + 1);
3852
3853 found = prettyGame.find_last_of(".");
3854 if (found != std::string::npos)
3855 prettyGame = prettyGame.substr(0, found);
3856 prettyGame.erase(std::remove(prettyGame.begin(), prettyGame.end(), '.'), prettyGame.end());
3857
3858 // now do keybind stuff
3859 KeyValues* kv;
3860 std::string savePath;
3861 if (type == "core")
3862 {
3863 kv = m_info->coreCoreOptions; // CORE-SPECIFIC OPTIONS
3864 savePath = "libretro\\user\\" + prettyCore;
3865 }
3866 else if (type == "game")
3867 {
3868 kv = m_info->gameCoreOptions; // GAME-SPECIFIC OPTIONS
3869 savePath = "libretro\\user\\" + prettyCore + "\\" + prettyGame;
3870 }
3871
3872 // add the info to the KV: NAME_INTERNAL = VALUE
3873 kv->SetString(name_internal.c_str(), value.c_str());
3874 m_info->optionshavechanged = true;
3875
3876 // save the KV out
3877 // (load up a fresh version and write ONLY this value to it to avoid saving other shit that we don't really want to save at this time.)
3878 KeyValues* fresh = new KeyValues("options");
3879 fresh->LoadFromFile(g_pFullFileSystem, VarArgs("%s\\options.key", savePath.c_str()), "DEFAULT_WRITE_PATH");
3880 if (value != "default")
3881 fresh->SetString(name_internal.c_str(), value.c_str());
3882 else
3883 fresh->SetString(name_internal.c_str(), "");
3884
3885 g_pFullFileSystem->CreateDirHierarchy(savePath.c_str(), "DEFAULT_WRITE_PATH");
3886 fresh->SaveToFile(g_pFullFileSystem, VarArgs("%s\\options.key", savePath.c_str()), "DEFAULT_WRITE_PATH");
3887 fresh->deleteThis();
3888}
3889
3890void C_LibretroInstance::ResetFastForwardSeconds()
3891{
3892 m_iFastForwardSeconds = 0;
3893
3894 C_AwesomiumBrowserInstance* pNetwork = g_pAnarchyManager->GetAwesomiumBrowserManager()->FindAwesomiumBrowserInstance("network");
3895 if (pNetwork)
3896 pNetwork->GetWebView()->ExecuteJavascript(WSLit(VarArgs("localStorage.setItem(\"libtime%s\", %i)", m_originalGameHash.c_str(), m_iFastForwardSeconds)), WSLit(""));
3897}
3898
3899void C_LibretroInstance::OnSecondsUpdated()
3900{
3901 if (m_info->core.find("ffmpeg") == std::string::npos)
3902 return;
3903
3904 int iSeconds = this->CurrentSeconds();
3905 if (iSeconds >= m_iFastForwardSeconds) //iSeconds >
3906 {
3907 //if (!m_pHudVoid)
3908 // m_pHudVoid = (void*)g_pAnarchyManager->GetAwesomiumBrowserManager()->FindAwesomiumBrowserInstance("hud");
3909 m_iFastForwardSeconds = iSeconds;
3910 C_AwesomiumBrowserInstance* pNetwork = g_pAnarchyManager->GetAwesomiumBrowserManager()->FindAwesomiumBrowserInstance("network");
3911 if (pNetwork)
3912 pNetwork->GetWebView()->ExecuteJavascript(WSLit(VarArgs("localStorage.setItem(\"libtime%s\", %i)", m_originalGameHash.c_str(), iSeconds)), WSLit(""));
3913 }
3914}
3915
3916int C_LibretroInstance::GetLibretroSeconds()
3917{
3918 return this->CurrentSeconds();
3919}
3920
3921int C_LibretroInstance::GetLibretroStartSeconds()
3922{
3923 return this->m_iFastForwardSeconds;
3924}
3925
3926void C_LibretroInstance::SetAdjustedStartTime()
3927{
3928 m_iAdjustedStartTime = static_cast<int>(ceil(engine->Time()));
3929 //DevMsg("Start time: %i (%f)\n", m_iAdjustedStartTime, round(engine->Time()));
3930}
3931
3932void C_LibretroInstance::FastForward(int iAmount, bool bAutoSkip)
3933{
3934 if (m_info->core.find("ffmpeg") == std::string::npos)
3935 return;
3936
3937 m_iAdjustedStartTime -= iAmount;
3938
3939 if (bAutoSkip && m_iFastForwardSeconds <= this->CurrentSeconds() + 10)
3940 m_iLastDelta = 0;
3941 else
3942 m_iLastDelta = iAmount;
3943}
3944
3945int C_LibretroInstance::CurrentSeconds()
3946{
3947 int t = ((static_cast<int>(ceil(engine->Time()))) - m_iAdjustedStartTime);
3948 if (t < 0)
3949 t = 0;
3950
3951 return t;
3952}
3953
3954void C_LibretroInstance::Rewind(int iAmount, bool bAutoSkip)
3955{
3956 if (m_info->core.find("ffmpeg") == std::string::npos)
3957 return;
3958
3959 m_iAdjustedStartTime -= iAmount;
3960 //if (m_iAdjustedStartTime < 0)
3961 // m_iAdjustedStartTime = 0;
3962
3963 m_iLastDelta = iAmount;
3964
3965 if (!bAutoSkip)
3966 {
3967 m_iFastForwardSeconds += iAmount;
3968 if (m_iFastForwardSeconds < 0)
3969 m_iFastForwardSeconds = 0;
3970 }
3971}