cleanup, function extraction and improved mode selection
This commit is contained in:
parent
9e0a76f5a6
commit
b4f95bebd5
323
src/core.c
323
src/core.c
|
|
@ -557,6 +557,13 @@ static void *EventThread(void *arg); // Input device events r
|
||||||
|
|
||||||
static void InitGamepad(void); // Init raw gamepad input
|
static void InitGamepad(void); // Init raw gamepad input
|
||||||
static void *GamepadThread(void *arg); // Mouse reading thread
|
static void *GamepadThread(void *arg); // Mouse reading thread
|
||||||
|
|
||||||
|
#if defined(PLATFORM_DRM)
|
||||||
|
static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode); // Search matching DRM mode in connector's mode list
|
||||||
|
static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search exactly matching DRM connector mode in connector's list
|
||||||
|
static int FindNearestConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search the nearest matching DRM connector mode in connector's list
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // PLATFORM_RPI || PLATFORM_DRM
|
#endif // PLATFORM_RPI || PLATFORM_DRM
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
@ -3140,112 +3147,39 @@ static bool InitGraphicsDevice(int width, int height)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool findExactly = true;
|
|
||||||
bool allowInterlaced = CORE.Window.flags & FLAG_INTERLACED_HINT;
|
|
||||||
const double fps = (CORE.Time.target > 0) ? (1.0 / CORE.Time.target) : 60;
|
|
||||||
#define IS_INTERLACED(mode) (mode.flags & DRM_MODE_FLAG_INTERLACE)
|
|
||||||
#define IS_PROGRESSIVE(mode) (!IS_INTERLACED(mode))
|
|
||||||
find_connector_mode:
|
|
||||||
TRACELOG(LOG_TRACE, "searching connector mode, should find exactly matching: %s, selecting an interlace mode is allowed: %s",
|
|
||||||
findExactly ? "yes" : "no", allowInterlaced ? "yes" : "no");
|
|
||||||
// If InitWindow should use the current mode find it in the connector's mode list
|
// If InitWindow should use the current mode find it in the connector's mode list
|
||||||
if ((CORE.Window.screen.width <= 0) || (CORE.Window.screen.height <= 0))
|
if ((CORE.Window.screen.width <= 0) || (CORE.Window.screen.height <= 0))
|
||||||
{
|
{
|
||||||
#define BINCMP(a, b) memcmp((a), (b), sizeof(a) < sizeof(b) ? sizeof(a) : sizeof(b))
|
TRACELOG(LOG_TRACE, "selecting DRM connector mode for current used mode");
|
||||||
TRACELOG(LOG_TRACE, "selecting for (res 0x0@%f)", fps);
|
|
||||||
for (int i = CORE.Window.connector->count_modes - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_TRACE, "mode %d h=%u v=%u %s refresh=%u", i, CORE.Window.connector->modes[i].hdisplay, CORE.Window.connector->modes[i].vdisplay,
|
|
||||||
IS_INTERLACED(CORE.Window.connector->modes[i]) ? "interlaced" : "progressive", CORE.Window.connector->modes[i].vrefresh);
|
|
||||||
if (IS_INTERLACED(CORE.Window.connector->modes[i]))
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_TRACE, "interlaced mode");
|
|
||||||
if (!allowInterlaced)
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_TRACE, "but shouldn't choose an interlaced mode");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_TRACE, "progressive mode");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 == BINCMP(&CORE.Window.crtc->mode, &CORE.Window.connector->modes[i]))
|
CORE.Window.modeIndex = FindMatchingConnectorMode(CORE.Window.connector, &CORE.Window.crtc->mode);
|
||||||
{
|
|
||||||
TRACELOG(LOG_TRACE, "above mode selected");
|
|
||||||
CORE.Window.screen.width = CORE.Window.connector->modes[i].hdisplay;
|
|
||||||
CORE.Window.screen.height = CORE.Window.connector->modes[i].vdisplay;
|
|
||||||
|
|
||||||
CORE.Window.display.width = CORE.Window.connector->modes[i].hdisplay;
|
|
||||||
CORE.Window.display.height = CORE.Window.connector->modes[i].vdisplay;
|
|
||||||
CORE.Window.modeIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#undef BINCMP
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_TRACE, "selecting for (res %ux%u@%f)", CORE.Window.screen.width, CORE.Window.screen.height, fps);
|
|
||||||
// Get closest video mode to desired CORE.Window.screen.width/CORE.Window.screen.height
|
|
||||||
for (int i = CORE.Window.connector->count_modes - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_TRACE, "mode %d h=%u v=%u %s refresh=%u", i, CORE.Window.connector->modes[i].hdisplay, CORE.Window.connector->modes[i].vdisplay,
|
|
||||||
IS_INTERLACED(CORE.Window.connector->modes[i]) ? "interlaced" : "progressive", CORE.Window.connector->modes[i].vrefresh);
|
|
||||||
if (IS_INTERLACED(CORE.Window.connector->modes[i]))
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_TRACE, "interlaced mode");
|
|
||||||
if (!allowInterlaced)
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_TRACE, "but shouldn't choose an interlaced mode");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_TRACE, "progressive mode");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
if (findExactly) {
|
|
||||||
found = (CORE.Window.connector->modes[i].hdisplay == CORE.Window.screen.width) &&
|
|
||||||
(CORE.Window.connector->modes[i].vdisplay == CORE.Window.screen.height) &&
|
|
||||||
(CORE.Window.connector->modes[i].vrefresh == fps);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
found = (CORE.Window.connector->modes[i].hdisplay >= CORE.Window.screen.width) &&
|
|
||||||
(CORE.Window.connector->modes[i].vdisplay >= CORE.Window.screen.height) &&
|
|
||||||
(CORE.Window.connector->modes[i].vrefresh >= fps);
|
|
||||||
}
|
|
||||||
if (found)
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_TRACE, "above mode selected");
|
|
||||||
CORE.Window.display.width = CORE.Window.connector->modes[i].hdisplay;
|
|
||||||
CORE.Window.display.height = CORE.Window.connector->modes[i].vdisplay;
|
|
||||||
CORE.Window.modeIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (CORE.Window.modeIndex < 0)
|
if (CORE.Window.modeIndex < 0)
|
||||||
{
|
{
|
||||||
if (findExactly)
|
TRACELOG(LOG_WARNING, "no matching DRM connector mode found");
|
||||||
{
|
drmModeFreeEncoder(enc);
|
||||||
findExactly = false;
|
drmModeFreeResources(res);
|
||||||
goto find_connector_mode;
|
return false;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!allowInterlaced)
|
|
||||||
{
|
|
||||||
allowInterlaced = true;
|
|
||||||
findExactly = true;
|
|
||||||
goto find_connector_mode;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CORE.Window.screen.width = CORE.Window.display.width;
|
||||||
|
CORE.Window.screen.height = CORE.Window.display.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool allowInterlaced = CORE.Window.flags & FLAG_INTERLACED_HINT;
|
||||||
|
const int fps = (CORE.Time.target > 0) ? (1.0 / CORE.Time.target) : 60;
|
||||||
|
// try to find an exact matching mode
|
||||||
|
CORE.Window.modeIndex = FindExactConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced);
|
||||||
|
// if nothing found, try to find a nearly matching mode
|
||||||
|
if (CORE.Window.modeIndex < 0)
|
||||||
|
CORE.Window.modeIndex = FindNearestConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced);
|
||||||
|
// if nothing found, try to find an exactly matching mode including interlaced
|
||||||
|
if (CORE.Window.modeIndex < 0)
|
||||||
|
CORE.Window.modeIndex = FindExactConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true);
|
||||||
|
// if nothing found, try to find a nearly matching mode including interlaced
|
||||||
|
if (CORE.Window.modeIndex < 0)
|
||||||
|
CORE.Window.modeIndex = FindNearestConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true);
|
||||||
|
// if nothing found, there is no suitable mode
|
||||||
if (CORE.Window.modeIndex < 0)
|
if (CORE.Window.modeIndex < 0)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "no suitable DRM connector mode found");
|
TRACELOG(LOG_WARNING, "no suitable DRM connector mode found");
|
||||||
|
|
@ -3253,12 +3187,14 @@ find_connector_mode:
|
||||||
drmModeFreeResources(res);
|
drmModeFreeResources(res);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CORE.Window.display.width = CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay;
|
||||||
|
CORE.Window.display.height = CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay;
|
||||||
|
|
||||||
TRACELOG(LOG_INFO, "DRM: choosen mode %s (%ux%u%c@%u)", CORE.Window.connector->modes[CORE.Window.modeIndex].name,
|
TRACELOG(LOG_INFO, "DRM: choosen mode %s (%ux%u%c@%u)", CORE.Window.connector->modes[CORE.Window.modeIndex].name,
|
||||||
CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay,
|
CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay,
|
||||||
IS_INTERLACED(CORE.Window.connector->modes[CORE.Window.modeIndex]) ? 'i' : 'p',
|
(CORE.Window.connector->modes[CORE.Window.modeIndex].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p',
|
||||||
CORE.Window.connector->modes[CORE.Window.modeIndex].vrefresh);
|
CORE.Window.connector->modes[CORE.Window.modeIndex].vrefresh);
|
||||||
#undef IS_PROGRESSIVE
|
|
||||||
#undef IS_INTERLACED
|
|
||||||
|
|
||||||
// Use the width and height of the surface for render
|
// Use the width and height of the surface for render
|
||||||
CORE.Window.render.width = CORE.Window.screen.width;
|
CORE.Window.render.width = CORE.Window.screen.width;
|
||||||
|
|
@ -3544,6 +3480,7 @@ find_connector_mode:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// find the EGL config that matches the previously setup GBM format
|
||||||
int found = 0;
|
int found = 0;
|
||||||
for (EGLint i = 0; i < matchingNumConfigs; ++i) {
|
for (EGLint i = 0; i < matchingNumConfigs; ++i) {
|
||||||
EGLint id = 0;
|
EGLint id = 0;
|
||||||
|
|
@ -5847,3 +5784,189 @@ void SetGraphicDeviceName(const char *name)
|
||||||
if ((name != NULL) && (name[0] != 0)) CORE.Window.card = name;
|
if ((name != NULL) && (name[0] != 0)) CORE.Window.card = name;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(PLATFORM_DRM)
|
||||||
|
|
||||||
|
static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode)
|
||||||
|
{
|
||||||
|
if (NULL == connector) return -1;
|
||||||
|
if (NULL == mode) return -1;
|
||||||
|
|
||||||
|
// safe bitwise comparison of two modes
|
||||||
|
#define BINCMP(a, b) memcmp((a), (b), (sizeof(a) < sizeof(b)) ? sizeof(a) : sizeof(b))
|
||||||
|
|
||||||
|
for (size_t i = 0; i < connector->count_modes; i++)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "mode %d %ux%u@%u %s", i, connector->modes[i].hdisplay, connector->modes[i].vdisplay,
|
||||||
|
connector->modes[i].vrefresh, (connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE) ? "interlaced" : "progressive");
|
||||||
|
|
||||||
|
if (0 == BINCMP(&CORE.Window.crtc->mode, &CORE.Window.connector->modes[i]))
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "above mode selected");
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#undef BINCMP
|
||||||
|
}
|
||||||
|
|
||||||
|
static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced) {
|
||||||
|
TRACELOG(LOG_TRACE, "searching exact connector mode for %ux%u@%u, selecting an interlaced mode is allowed: %s", width, height, fps, allowInterlaced ? "yes" : "no");
|
||||||
|
|
||||||
|
if (NULL == connector) return -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < CORE.Window.connector->count_modes; i++)
|
||||||
|
{
|
||||||
|
const drmModeModeInfo *const mode = &CORE.Window.connector->modes[i];
|
||||||
|
|
||||||
|
TRACELOG(LOG_TRACE, "mode %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh, (mode->flags & DRM_MODE_FLAG_INTERLACE) ? "interlaced" : "progressive");
|
||||||
|
|
||||||
|
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && (!allowInterlaced))
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "but shouldn't choose an interlaced mode");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mode->hdisplay == width) && (mode->vdisplay == height) && (mode->vrefresh == fps))
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "mode selected");
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACELOG(LOG_TRACE, "no exact matching mode found");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int FindNearestConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced) {
|
||||||
|
TRACELOG(LOG_TRACE, "searching nearest connector mode for %ux%u@%u, selecting an interlaced mode is allowed: %s", width, height, fps, allowInterlaced ? "yes" : "no");
|
||||||
|
|
||||||
|
if (NULL == connector) return -1;
|
||||||
|
|
||||||
|
int nearestIndex = -1;
|
||||||
|
for (int i = 0; i < CORE.Window.connector->count_modes; i++)
|
||||||
|
{
|
||||||
|
const drmModeModeInfo *const mode = &CORE.Window.connector->modes[i];
|
||||||
|
|
||||||
|
TRACELOG(LOG_TRACE, "mode %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh,
|
||||||
|
(mode->flags & DRM_MODE_FLAG_INTERLACE) ? "interlaced" : "progressive");
|
||||||
|
|
||||||
|
if ((mode->hdisplay < width) || (mode->vdisplay < height) | (mode->vrefresh < fps))
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "mode is too small");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && (!allowInterlaced))
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "shouldn't choose an interlaced mode");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mode->hdisplay >= width) && (mode->vdisplay >= height) && (mode->vrefresh >= fps))
|
||||||
|
{
|
||||||
|
const int widthDiff = mode->hdisplay - width;
|
||||||
|
const int heightDiff = mode->vdisplay - height;
|
||||||
|
const int fpsDiff = mode->vrefresh - fps;
|
||||||
|
|
||||||
|
if (nearestIndex < 0)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "first suitable mode");
|
||||||
|
nearestIndex = i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int nearestWidthDiff = CORE.Window.connector->modes[nearestIndex].hdisplay - width;
|
||||||
|
const int nearestHeightDiff = CORE.Window.connector->modes[nearestIndex].vdisplay - height;
|
||||||
|
const int nearestFpsDiff = CORE.Window.connector->modes[nearestIndex].vrefresh - fps;
|
||||||
|
|
||||||
|
if ((widthDiff < nearestWidthDiff) || (heightDiff < nearestHeightDiff) || (fpsDiff < nearestFpsDiff))
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "mode is nearer than the previous one");
|
||||||
|
nearestIndex = i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "mode is not nearer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACELOG(LOG_TRACE, "returning nearest mode: %d", nearestIndex);
|
||||||
|
return nearestIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static int FindConnectorMode(bool findExactly, bool allowInterlaced) {
|
||||||
|
TRACELOG(LOG_TRACE, "searching connector mode, should find exactly matching: %s, selecting an interlaced mode is allowed: %s",
|
||||||
|
findExactly ? "yes" : "no", allowInterlaced ? "yes" : "no");
|
||||||
|
|
||||||
|
if (!CORE.Window.connector) return -1;
|
||||||
|
|
||||||
|
// If InitWindow should use the current mode find it in the connector's mode list
|
||||||
|
if ((CORE.Window.screen.width <= 0) || (CORE.Window.screen.height <= 0))
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "selecting DRM connector mode for current used mode");
|
||||||
|
|
||||||
|
// safe bitwise comparison of two modes
|
||||||
|
#define BINCMP(a, b) memcmp((a), (b), (sizeof(a) < sizeof(b)) ? sizeof(a) : sizeof(b))
|
||||||
|
|
||||||
|
for (int i = CORE.Window.connector->count_modes - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "mode %d %ux%u@%u %s", i, CORE.Window.connector->modes[i].hdisplay, CORE.Window.connector->modes[i].vdisplay,
|
||||||
|
CORE.Window.connector->modes[i].vrefresh, (CORE.Window.connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE) ? "interlaced" : "progressive");
|
||||||
|
|
||||||
|
if (0 == BINCMP(&CORE.Window.crtc->mode, &CORE.Window.connector->modes[i]))
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "above mode selected");
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#undef BINCMP
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double fps = (CORE.Time.target > 0) ? (1.0 / CORE.Time.target) : 60;
|
||||||
|
|
||||||
|
TRACELOG(LOG_TRACE, "selecting for %ux%u@%f", CORE.Window.screen.width, CORE.Window.screen.height, fps);
|
||||||
|
|
||||||
|
// Get closest video mode to desired CORE.Window.screen.width/CORE.Window.screen.height
|
||||||
|
for (int i = CORE.Window.connector->count_modes - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "mode %d %ux%u@%u %s", i, CORE.Window.connector->modes[i].hdisplay, CORE.Window.connector->modes[i].vdisplay,
|
||||||
|
CORE.Window.connector->modes[i].vrefresh, (CORE.Window.connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE) ? "interlaced" : "progressive");
|
||||||
|
|
||||||
|
if (CORE.Window.connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "interlaced mode");
|
||||||
|
if (!allowInterlaced)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "but shouldn't choose an interlaced mode");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else TRACELOG(LOG_TRACE, "progressive mode");
|
||||||
|
|
||||||
|
const bool found = (findExactly)
|
||||||
|
? (CORE.Window.connector->modes[i].hdisplay == CORE.Window.screen.width) &&
|
||||||
|
(CORE.Window.connector->modes[i].vdisplay == CORE.Window.screen.height) &&
|
||||||
|
(CORE.Window.connector->modes[i].vrefresh == fps)
|
||||||
|
: (CORE.Window.connector->modes[i].hdisplay >= CORE.Window.screen.width) &&
|
||||||
|
(CORE.Window.connector->modes[i].vdisplay >= CORE.Window.screen.height) &&
|
||||||
|
(CORE.Window.connector->modes[i].vrefresh >= fps);
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_TRACE, "above mode selected");
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user