Init
This commit is contained in:
@ -0,0 +1,577 @@
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved.
|
||||
#include <RendererMemoryMacros.h>
|
||||
#include <linux/LinuxSamplePlatform.h>
|
||||
#include <SampleApplication.h>
|
||||
#include <Cg/cg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Ps.h>
|
||||
#include <PsString.h>
|
||||
//#include <PsFile.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
using namespace SampleFramework;
|
||||
using SampleRenderer::RendererWindow;
|
||||
|
||||
namespace Ps = physx::shdfnd;
|
||||
|
||||
// filters OS key auto repeat, otherwise you get repeatedly key released and pressed events
|
||||
// returns true if the supplied event was a auto repeat one.
|
||||
// XAutoRepeatOff(m_display); does change the behaviour for the entire display.
|
||||
// So you see the effect also in other apps while the samples are running, which is bad.
|
||||
bool LinuxPlatform::filterKeyRepeat(const XEvent& keyReleaseEvent)
|
||||
{
|
||||
if(keyReleaseEvent.type == KeyRelease && XEventsQueued(m_display, QueuedAfterReading))
|
||||
{
|
||||
XEvent nev;
|
||||
XPeekEvent(m_display, &nev);
|
||||
if (nev.type == KeyPress &&
|
||||
nev.xkey.time == keyReleaseEvent.xkey.time &&
|
||||
nev.xkey.keycode == keyReleaseEvent.xkey.keycode)
|
||||
{
|
||||
// Key wasn't actually released, eat event
|
||||
XNextEvent(m_display, &nev);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SamplePlatform* SampleFramework::createPlatform(SampleRenderer::RendererWindow* _app)
|
||||
{
|
||||
printf("Creating linux platform abstraction.\n");
|
||||
SamplePlatform::setPlatform(new LinuxPlatform(_app));
|
||||
return SamplePlatform::platform();
|
||||
}
|
||||
|
||||
void* LinuxPlatform::compileProgram(void * context,
|
||||
const char* assetDir,
|
||||
const char *programPath,
|
||||
physx::PxU64 profile,
|
||||
const char* passString,
|
||||
const char *entry,
|
||||
const char **args)
|
||||
|
||||
{
|
||||
char fullpath[1024];
|
||||
Ps::strlcpy(fullpath, 1024, assetDir);
|
||||
Ps::strlcat(fullpath, 1024, "shaders/");
|
||||
Ps::strlcat(fullpath, 1024, programPath);
|
||||
CGprogram program = cgCreateProgramFromFile(static_cast<CGcontext>(context), CG_SOURCE, fullpath, static_cast<CGprofile>(profile), entry, args);
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
static PxI32 errorHandler(Display* d, XErrorEvent* e)
|
||||
{
|
||||
printf("Xerror!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PxI32 errorHandlerIO(Display* d)
|
||||
{
|
||||
printf("X IO error!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
LinuxPlatform::LinuxPlatform(SampleRenderer::RendererWindow* _app)
|
||||
: SamplePlatform(_app)
|
||||
, m_display(NULL)
|
||||
, m_visualInfo(NULL)
|
||||
, m_hasFocus(false)
|
||||
, m_hasContentFocus(false)
|
||||
, m_isFullScreen(false)
|
||||
, m_screen(0)
|
||||
, m_mouseCursorPos(0)
|
||||
, m_recenterMouseCursor(false)
|
||||
, m_showCursor(true)
|
||||
{
|
||||
XInitThreads();
|
||||
XSetIOErrorHandler(errorHandlerIO);
|
||||
XSetErrorHandler(errorHandler);
|
||||
}
|
||||
|
||||
void LinuxPlatform::setCWDToEXE(void)
|
||||
{
|
||||
char exepath[1024] = {0};
|
||||
if(getcwd(exepath, 1024))
|
||||
{
|
||||
if(chdir(exepath) != 0)
|
||||
{
|
||||
printf("LinuxPlatform::setCWDToEXE chdir failed!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxPlatform::setupRendererDescription(SampleRenderer::RendererDesc& renDesc)
|
||||
{
|
||||
renDesc.driver = SampleRenderer::Renderer::DRIVER_OPENGL;
|
||||
renDesc.windowHandle = 0;
|
||||
}
|
||||
|
||||
void LinuxPlatform::postRendererSetup(SampleRenderer::Renderer* renderer)
|
||||
{
|
||||
if(!renderer)
|
||||
{
|
||||
// quit if no renderer was created. Nothing else to do.
|
||||
// error was output in createRenderer.
|
||||
exit(1);
|
||||
}
|
||||
char windowTitle[1024] = {0};
|
||||
m_app->getTitle(windowTitle, 1024);
|
||||
strcat(windowTitle, " : ");
|
||||
strcat(windowTitle, SampleRenderer::Renderer::getDriverTypeName(renderer->getDriverType()));
|
||||
m_app->setTitle(windowTitle);
|
||||
}
|
||||
|
||||
void LinuxPlatform::setMouseCursorRecentering(bool val)
|
||||
{
|
||||
if (m_recenterMouseCursor != val)
|
||||
{
|
||||
m_recenterMouseCursor = val;
|
||||
if (m_recenterMouseCursor)
|
||||
recenterMouseCursor(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool LinuxPlatform::getMouseCursorRecentering() const
|
||||
{
|
||||
return m_recenterMouseCursor;
|
||||
}
|
||||
|
||||
void LinuxPlatform::recenterMouseCursor(bool generateEvent)
|
||||
{
|
||||
if (m_recenterMouseCursor && m_hasContentFocus)
|
||||
{
|
||||
// returns relative window coordinates, opposed to absolute ones!
|
||||
// different than on other platforms.
|
||||
PxI32 x, y, xtmp, ytmp;
|
||||
PxU32 mtmp;
|
||||
Window root, child;
|
||||
XQueryPointer(m_display, m_window, &root, &child, &xtmp, &ytmp, &x, &y, &mtmp);
|
||||
|
||||
PxVec2 current(static_cast<PxReal>(x), static_cast<PxReal>(m_windowHeight - y));
|
||||
|
||||
PxI32 linuxCenterX = m_windowWidth >> 1;
|
||||
PxI32 linuxCenterY = m_windowHeight >> 1;
|
||||
|
||||
XWarpPointer(m_display, 0, m_window, 0, 0, 0, 0, linuxCenterX, linuxCenterY);
|
||||
// sync here needed, otherwise the deltas will be (almost) zero
|
||||
XSync(m_display, false);
|
||||
|
||||
if (generateEvent)
|
||||
{
|
||||
PxVec2 diff = current - PxVec2(static_cast<PxReal>(linuxCenterX), static_cast<PxReal>(m_windowHeight - linuxCenterY));
|
||||
getLinuxSampleUserInput().doOnMouseMove(linuxCenterX, m_windowHeight - linuxCenterY, diff.x, diff.y, MOUSE_MOVE);
|
||||
}
|
||||
|
||||
m_mouseCursorPos = current;
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxPlatform::showCursorInternal(bool show)
|
||||
{
|
||||
if(show)
|
||||
{
|
||||
XUndefineCursor(m_display, m_window);
|
||||
}
|
||||
else
|
||||
{
|
||||
Pixmap bm_no;
|
||||
Colormap cmap;
|
||||
Cursor no_ptr;
|
||||
XColor black, dummy;
|
||||
static char bm_no_data[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
cmap = DefaultColormap(m_display, DefaultScreen(m_display));
|
||||
XAllocNamedColor(m_display, cmap, "black", &black, &dummy);
|
||||
bm_no = XCreateBitmapFromData(m_display, m_window, bm_no_data, 8, 8);
|
||||
no_ptr = XCreatePixmapCursor(m_display, bm_no, bm_no, &black, &black, 0, 0);
|
||||
|
||||
XDefineCursor(m_display, m_window, no_ptr);
|
||||
XFreeCursor(m_display, no_ptr);
|
||||
if(bm_no != None)
|
||||
XFreePixmap(m_display, bm_no);
|
||||
XFreeColors(m_display, cmap, &black.pixel, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxPlatform::showCursor(bool show)
|
||||
{
|
||||
if(m_showCursor == show)
|
||||
return;
|
||||
|
||||
m_showCursor = show;
|
||||
showCursorInternal(show);
|
||||
}
|
||||
|
||||
void LinuxPlatform::doInput()
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
bool LinuxPlatform::openWindow(physx::PxU32& width, physx::PxU32& height,const char* title, bool fullscreen)
|
||||
{
|
||||
Window rootWindow;
|
||||
GLint attributes[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
|
||||
Colormap colorMap;
|
||||
XSetWindowAttributes setWindowAttributes;
|
||||
XWindowAttributes xWindowAttributes;
|
||||
XEvent xEvent;
|
||||
|
||||
int glxMajor, glxMinor, vmMajor, vmMinor;
|
||||
XF86VidModeModeInfo** modes;
|
||||
int modeNum;
|
||||
int bestMode = 0; // set best mode to current
|
||||
|
||||
m_display = XOpenDisplay(NULL);
|
||||
m_screen = DefaultScreen(m_display);
|
||||
|
||||
if(!m_display)
|
||||
{
|
||||
printf("Cannot connect to X server!\n");
|
||||
closeWindow();
|
||||
return false;
|
||||
}
|
||||
|
||||
XF86VidModeQueryVersion(m_display, &vmMajor, &vmMinor);
|
||||
printf("XF86 VideoMode extension version %d.%d\n", vmMajor, vmMinor);
|
||||
|
||||
glXQueryVersion(m_display, &glxMajor, &glxMinor);
|
||||
printf("GLX-Version %d.%d\n", glxMajor, glxMinor);
|
||||
|
||||
rootWindow = RootWindow(m_display, m_screen);
|
||||
|
||||
m_visualInfo = glXChooseVisual(m_display, m_screen, attributes);
|
||||
if(!m_visualInfo)
|
||||
{
|
||||
printf("no appropriate visual found!\n");
|
||||
closeWindow();
|
||||
return false;
|
||||
}
|
||||
|
||||
colorMap = XCreateColormap(m_display, rootWindow, m_visualInfo->visual, AllocNone);
|
||||
setWindowAttributes.colormap = colorMap;
|
||||
setWindowAttributes.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask;
|
||||
|
||||
m_windowWidth = width;
|
||||
m_windowHeight = height;
|
||||
//fullscreen = true;
|
||||
m_isFullScreen = fullscreen;
|
||||
int windowFlags = CWColormap | CWEventMask;
|
||||
|
||||
if(fullscreen)
|
||||
{
|
||||
XF86VidModeGetAllModeLines(m_display, m_screen, &modeNum, &modes);
|
||||
// save desktop-resolution before switching modes
|
||||
m_desktopMode = *modes[0];
|
||||
|
||||
// look for mode with requested resolution
|
||||
for (PxU32 i = 0; i < modeNum; i++)
|
||||
{
|
||||
if ((modes[i]->hdisplay == width) && (modes[i]->vdisplay == height))
|
||||
bestMode = i;
|
||||
}
|
||||
// switch to fullscreen
|
||||
XF86VidModeSwitchToMode(m_display, m_screen, modes[bestMode]);
|
||||
XF86VidModeSetViewPort(m_display, m_screen, 0, 0);
|
||||
m_windowWidth = modes[bestMode]->hdisplay;
|
||||
m_windowHeight = modes[bestMode]->vdisplay;
|
||||
printf("switched to fullscreen resolution %dx%d\n", m_windowWidth, m_windowHeight);
|
||||
XFree(modes);
|
||||
setWindowAttributes.override_redirect = True;
|
||||
windowFlags |= CWBorderPixel | CWOverrideRedirect;
|
||||
}
|
||||
|
||||
m_window = XCreateWindow(m_display, rootWindow, 0, 0, m_windowWidth, m_windowHeight, 0, m_visualInfo->depth, InputOutput, m_visualInfo->visual, windowFlags, &setWindowAttributes);
|
||||
|
||||
XMapRaised(m_display, m_window);
|
||||
XStoreName(m_display, m_window, title);
|
||||
|
||||
if(fullscreen)
|
||||
{
|
||||
XWarpPointer(m_display, None, m_window, 0, 0, 0, 0, 0, 0);
|
||||
XGrabKeyboard(m_display, m_window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
XGrabPointer(m_display, m_window, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_wmDelete = XInternAtom(m_display, "WM_DELETE_WINDOW", True);
|
||||
XSetWMProtocols(m_display, m_window, &m_wmDelete, 1);
|
||||
XMapWindow(m_display, m_window);
|
||||
}
|
||||
|
||||
m_hasContentFocus = true;
|
||||
m_showCursor = true;
|
||||
recenterMouseCursor(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LinuxPlatform::initializeOGLDisplay(const SampleRenderer::RendererDesc& desc,
|
||||
physx::PxU32& width,
|
||||
physx::PxU32& height)
|
||||
{
|
||||
m_glxContext = glXCreateContext(m_display, m_visualInfo, NULL, GL_TRUE);
|
||||
glXMakeCurrent(m_display, m_window, m_glxContext);
|
||||
getWindowSize(width, height);
|
||||
}
|
||||
|
||||
void LinuxPlatform::postInitializeOGLDisplay()
|
||||
{
|
||||
glewInit();
|
||||
}
|
||||
|
||||
bool LinuxPlatform::closeWindow()
|
||||
{
|
||||
if(m_glxContext)
|
||||
{
|
||||
glXMakeCurrent(m_display, None, NULL);
|
||||
glXDestroyContext(m_display, m_glxContext);
|
||||
m_glxContext = 0;
|
||||
XDestroyWindow(m_display, m_window);
|
||||
if(m_isFullScreen)
|
||||
{
|
||||
XF86VidModeSwitchToMode(m_display, m_screen, &m_desktopMode);
|
||||
XF86VidModeSetViewPort(m_display, m_screen, 0, 0);
|
||||
}
|
||||
|
||||
if(m_visualInfo)
|
||||
XFree(m_visualInfo);
|
||||
m_visualInfo = NULL;
|
||||
|
||||
if(m_display)
|
||||
XCloseDisplay(m_display);
|
||||
m_display = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LinuxPlatform::freeDisplay()
|
||||
{
|
||||
}
|
||||
|
||||
void LinuxPlatform::getWindowSize(PxU32& width, PxU32& height)
|
||||
{
|
||||
if(!m_display)
|
||||
return;
|
||||
XWindowAttributes attr;
|
||||
XGetWindowAttributes(m_display, m_window, &attr);
|
||||
width = attr.width;
|
||||
height = attr.height;
|
||||
}
|
||||
|
||||
void LinuxPlatform::setFocus(bool b)
|
||||
{
|
||||
m_hasFocus = b;
|
||||
}
|
||||
|
||||
bool LinuxPlatform::hasFocus() const
|
||||
{
|
||||
return m_hasContentFocus;
|
||||
}
|
||||
|
||||
void LinuxPlatform::getTitle(char *title, physx::PxU32 maxLength) const
|
||||
{
|
||||
if(!m_display)
|
||||
return;
|
||||
|
||||
char* t;
|
||||
XFetchName(m_display, m_window, &t);
|
||||
strncpy(title, t, maxLength);
|
||||
XFree(t);
|
||||
}
|
||||
|
||||
void LinuxPlatform::setTitle(const char *title)
|
||||
{
|
||||
// unsafe!
|
||||
if(m_display && title)
|
||||
XStoreName(m_display, m_window, title);
|
||||
}
|
||||
|
||||
bool LinuxPlatform::updateWindow()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void LinuxPlatform::handleMouseEvent(const XEvent& event)
|
||||
{
|
||||
PxU32 x = event.xbutton.x;
|
||||
PxU32 y = m_windowHeight - event.xbutton.y;
|
||||
PxVec2 current(static_cast<PxReal>(x), static_cast<PxReal>(y));
|
||||
setMouseCursorPos(current);
|
||||
|
||||
switch (event.type)
|
||||
{
|
||||
case ButtonPress:
|
||||
{
|
||||
m_linuxSampleUserInput.doOnMouseDown(x, y, event.xbutton.button);
|
||||
}
|
||||
break;
|
||||
case ButtonRelease:
|
||||
{
|
||||
m_linuxSampleUserInput.doOnMouseUp(x, y, event.xbutton.button);
|
||||
}
|
||||
break;
|
||||
case MotionNotify:
|
||||
{
|
||||
if (!getMouseCursorRecentering())
|
||||
{
|
||||
PxVec2 diff = current - getMouseCursorPos();
|
||||
m_linuxSampleUserInput.doOnMouseMove(x, y, diff.x, diff.y, MOUSE_MOVE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxPlatform::update()
|
||||
{
|
||||
XEvent event;
|
||||
bool close = false;
|
||||
|
||||
if(!m_display || !m_app || !m_app->isOpen())
|
||||
return;
|
||||
|
||||
// handle the events in the queue
|
||||
while (m_display && !close && m_app->isOpen() && (XPending(m_display) > 0))
|
||||
{
|
||||
XNextEvent(m_display, &event);
|
||||
switch (event.type)
|
||||
{
|
||||
case Expose:
|
||||
if (event.xexpose.count == 0)
|
||||
{
|
||||
PxU32 width, height;
|
||||
getWindowSize(width, height);
|
||||
m_app->onResize(width, height);
|
||||
m_windowWidth = width;
|
||||
m_windowHeight = height;
|
||||
}
|
||||
break;
|
||||
case FocusIn:
|
||||
m_app->setFocus(true);
|
||||
break;
|
||||
case FocusOut:
|
||||
m_app->setFocus(false);
|
||||
m_hasContentFocus = false;
|
||||
break;
|
||||
case ButtonPress:
|
||||
// fixes recentering issue: jumping window with first context switch.
|
||||
if(!m_hasContentFocus)
|
||||
{
|
||||
m_hasContentFocus = true;
|
||||
recenterMouseCursor(false);
|
||||
}
|
||||
else
|
||||
handleMouseEvent(event);
|
||||
break;
|
||||
case ButtonRelease:
|
||||
handleMouseEvent(event);
|
||||
break;
|
||||
case MotionNotify:
|
||||
handleMouseEvent(event);
|
||||
break;
|
||||
case KeyPress:
|
||||
case KeyRelease:
|
||||
{
|
||||
// and now some code to filter out the key releases
|
||||
// which are generated by auto repeat
|
||||
if(filterKeyRepeat(event))
|
||||
break;
|
||||
|
||||
char keyName;
|
||||
KeySym keySym;
|
||||
XLookupString(&event.xkey, &keyName, 1, &keySym, NULL);
|
||||
bool keyDown = (event.type == KeyPress);
|
||||
if(keyDown)
|
||||
m_linuxSampleUserInput.doOnKeyDown(keySym, event.xkey.keycode, keyName);
|
||||
else
|
||||
m_linuxSampleUserInput.doOnKeyUp(keySym, event.xkey.keycode, keyName);
|
||||
}
|
||||
break;
|
||||
case ClientMessage:
|
||||
if((Atom)event.xclient.data.l[0] == m_wmDelete)
|
||||
close = true;
|
||||
break;
|
||||
default:
|
||||
printf("unhandled event type: %d\n", event.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
recenterMouseCursor(true);
|
||||
|
||||
if(close)
|
||||
m_app->close();
|
||||
}
|
||||
|
||||
void LinuxPlatform::swapBuffers()
|
||||
{
|
||||
if(m_display)
|
||||
glXSwapBuffers(m_display, m_window);
|
||||
}
|
||||
|
||||
const char* LinuxPlatform::getPathSeparator()
|
||||
{
|
||||
return "/";
|
||||
}
|
||||
|
||||
static bool doesDirectoryExist(const char* path)
|
||||
{
|
||||
bool exists = false;
|
||||
DIR* dir = NULL;
|
||||
dir = opendir(path);
|
||||
if(dir)
|
||||
{
|
||||
closedir(dir);
|
||||
exists = true;
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
bool LinuxPlatform::makeSureDirectoryPathExists(const char* dirPath)
|
||||
{
|
||||
bool ok = doesDirectoryExist(dirPath);
|
||||
if (!ok)
|
||||
ok = mkdir(dirPath, S_IRWXU|S_IRWXG|S_IRWXO) == 0;
|
||||
return ok;
|
||||
}
|
||||
|
||||
void LinuxPlatform::showMessage(const char* title, const char* message)
|
||||
{
|
||||
printf("%s: %s\n", title, message);
|
||||
}
|
||||
|
||||
@ -0,0 +1,398 @@
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved.
|
||||
|
||||
#include <linux/LinuxSampleUserInput.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static bool gTimeInit=false;
|
||||
|
||||
using namespace SampleFramework;
|
||||
using namespace physx;
|
||||
|
||||
LinuxSampleUserInput::LinuxSampleUserInput()
|
||||
{
|
||||
// register all user inputs for linux platform
|
||||
registerUserInput(LINUXKEY_1,"KEY_1", "1");
|
||||
registerUserInput(LINUXKEY_2,"KEY_2", "2");
|
||||
registerUserInput(LINUXKEY_3,"KEY_3", "3");
|
||||
registerUserInput(LINUXKEY_4,"KEY_4", "4");
|
||||
registerUserInput(LINUXKEY_5,"KEY_5", "5");
|
||||
registerUserInput(LINUXKEY_6,"KEY_6", "6");
|
||||
registerUserInput(LINUXKEY_7,"KEY_7", "7");
|
||||
registerUserInput(LINUXKEY_8,"KEY_8", "8");
|
||||
registerUserInput(LINUXKEY_9,"KEY_9", "9");
|
||||
registerUserInput(LINUXKEY_0,"KEY_0", "0");
|
||||
|
||||
registerUserInput(LINUXKEY_A,"KEY_A", "A");
|
||||
registerUserInput(LINUXKEY_B,"KEY_B", "B");
|
||||
registerUserInput(LINUXKEY_C,"KEY_C", "C");
|
||||
registerUserInput(LINUXKEY_D,"KEY_D", "D");
|
||||
registerUserInput(LINUXKEY_E,"KEY_E", "E");
|
||||
registerUserInput(LINUXKEY_F,"KEY_F", "F");
|
||||
registerUserInput(LINUXKEY_G,"KEY_G", "G");
|
||||
registerUserInput(LINUXKEY_H,"KEY_H", "H");
|
||||
registerUserInput(LINUXKEY_I,"KEY_I", "I");
|
||||
registerUserInput(LINUXKEY_J,"KEY_J", "J");
|
||||
registerUserInput(LINUXKEY_K,"KEY_K", "K");
|
||||
registerUserInput(LINUXKEY_L,"KEY_L", "L");
|
||||
registerUserInput(LINUXKEY_M,"KEY_M", "M");
|
||||
registerUserInput(LINUXKEY_N,"KEY_N", "N");
|
||||
registerUserInput(LINUXKEY_O,"KEY_O", "O");
|
||||
registerUserInput(LINUXKEY_P,"KEY_P", "P");
|
||||
registerUserInput(LINUXKEY_Q,"KEY_Q", "Q");
|
||||
registerUserInput(LINUXKEY_R,"KEY_R", "R");
|
||||
registerUserInput(LINUXKEY_S,"KEY_S", "S");
|
||||
registerUserInput(LINUXKEY_T,"KEY_T", "T");
|
||||
registerUserInput(LINUXKEY_U,"KEY_U", "U");
|
||||
registerUserInput(LINUXKEY_V,"KEY_V", "V");
|
||||
registerUserInput(LINUXKEY_W,"KEY_W", "W");
|
||||
registerUserInput(LINUXKEY_X,"KEY_X", "X");
|
||||
registerUserInput(LINUXKEY_Y,"KEY_Y", "Y");
|
||||
registerUserInput(LINUXKEY_Z,"KEY_Z", "Z");
|
||||
|
||||
registerUserInput(LINUXKEY_SPACE ,"KEY_SPACE","Space");
|
||||
registerUserInput(LINUXKEY_RETURN ,"KEY_RETURN","Enter");
|
||||
registerUserInput(LINUXKEY_SHIFT ,"KEY_SHIFT","Shift");
|
||||
registerUserInput(LINUXKEY_CONTROL ,"KEY_CONTROL","Control");
|
||||
registerUserInput(LINUXKEY_ESCAPE ,"KEY_ESCAPE","Escape");
|
||||
registerUserInput(LINUXKEY_COMMA ,"KEY_COMMA",",");
|
||||
registerUserInput(LINUXKEY_NUMPAD0 ,"KEY_NUMPAD0","Numpad0");
|
||||
registerUserInput(LINUXKEY_NUMPAD1 ,"KEY_NUMPAD1","Numpad1");
|
||||
registerUserInput(LINUXKEY_NUMPAD2 ,"KEY_NUMPAD2","Numpad2");
|
||||
registerUserInput(LINUXKEY_NUMPAD3 ,"KEY_NUMPAD3","Numpad3");
|
||||
registerUserInput(LINUXKEY_NUMPAD4 ,"KEY_NUMPAD4","Numpad4");
|
||||
registerUserInput(LINUXKEY_NUMPAD5 ,"KEY_NUMPAD5","Numpad5");
|
||||
registerUserInput(LINUXKEY_NUMPAD6 ,"KEY_NUMPAD6","Numpad6");
|
||||
registerUserInput(LINUXKEY_NUMPAD7 ,"KEY_NUMPAD7","Numpad7");
|
||||
registerUserInput(LINUXKEY_NUMPAD8 ,"KEY_NUMPAD8","Numpad8");
|
||||
registerUserInput(LINUXKEY_NUMPAD9 ,"KEY_NUMPAD9","Numpad9");
|
||||
registerUserInput(LINUXKEY_ADD ,"KEY_ADD","+");
|
||||
registerUserInput(LINUXKEY_SUBTRACT ,"KEY_SUBTRACT","-");
|
||||
registerUserInput(LINUXKEY_COMMA ,"KEY_COMMM",", on keypad");
|
||||
registerUserInput(LINUXKEY_DIVIDE ,"KEY_DIVIDE","/");
|
||||
|
||||
registerUserInput(LINUXKEY_F1 ,"KEY_F1","F1");
|
||||
registerUserInput(LINUXKEY_F2 ,"KEY_F2","F2");
|
||||
registerUserInput(LINUXKEY_F3 ,"KEY_F3","F3");
|
||||
registerUserInput(LINUXKEY_F4 ,"KEY_F4","F4");
|
||||
registerUserInput(LINUXKEY_F5 ,"KEY_F5","F5");
|
||||
registerUserInput(LINUXKEY_F6 ,"KEY_F6","F6");
|
||||
registerUserInput(LINUXKEY_F7 ,"KEY_F7","F7");
|
||||
registerUserInput(LINUXKEY_F8 ,"KEY_F8","F8");
|
||||
registerUserInput(LINUXKEY_F9 ,"KEY_F9","F9");
|
||||
registerUserInput(LINUXKEY_F10 ,"KEY_F10","F10");
|
||||
registerUserInput(LINUXKEY_F11 ,"KEY_F11","F11");
|
||||
registerUserInput(LINUXKEY_F12 ,"KEY_F12","F12");
|
||||
|
||||
registerUserInput(LINUXKEY_TAB ,"KEY_TAB","Tab");
|
||||
registerUserInput(LINUXKEY_BACKSPACE ,"KEY_BACKSPACE","Backspace");
|
||||
registerUserInput(LINUXKEY_PRIOR ,"KEY_PRIOR","PgUp");
|
||||
registerUserInput(LINUXKEY_NEXT ,"KEY_NEXT","PgDn");
|
||||
registerUserInput(LINUXKEY_UP ,"KEY_UP","Up Arrow");
|
||||
registerUserInput(LINUXKEY_DOWN ,"KEY_DOWN","Down Arrow");
|
||||
registerUserInput(LINUXKEY_LEFT ,"KEY_LEFT","Left Arrow");
|
||||
registerUserInput(LINUXKEY_RIGHT ,"KEY_RIGHT","Right Arrow");
|
||||
|
||||
// mouse
|
||||
registerUserInput(MOUSE_BUTTON_LEFT ,"MOUSE_BUTTON_LEFT","Left Mouse Button");
|
||||
registerUserInput(MOUSE_BUTTON_RIGHT ,"MOUSE_BUTTON_RIGHT","Right Mouse Button");
|
||||
registerUserInput(MOUSE_BUTTON_CENTER ,"MOUSE_BUTTON_CENTER","Middle Mouse Button");
|
||||
registerUserInput(MOUSE_MOVE,"MOUSE_MOVE", "Mouse Move");
|
||||
|
||||
// scan codes
|
||||
registerScanCode(SCAN_CODE_UP, 26, LINUXKEY_E, "SCAN_CODE_E");
|
||||
registerScanCode(SCAN_CODE_DOWN, 54, LINUXKEY_C, "SCAN_CODE_C");
|
||||
registerScanCode(SCAN_CODE_LEFT, 38, LINUXKEY_A, "SCAN_CODE_A");
|
||||
registerScanCode(SCAN_CODE_RIGHT, 40, LINUXKEY_D, "SCAN_CODE_D");
|
||||
registerScanCode(SCAN_CODE_FORWARD, 25, LINUXKEY_W, "SCAN_CODE_W");
|
||||
registerScanCode(SCAN_CODE_BACKWARD, 39, LINUXKEY_S, "SCAN_CODE_S");
|
||||
registerScanCode(SCAN_CODE_L, 46, LINUXKEY_L, "SCAN_CODE_L");
|
||||
registerScanCode(SCAN_CODE_9, 18, LINUXKEY_9, "SCAN_CODE_9");
|
||||
registerScanCode(SCAN_CODE_0, 19, LINUXKEY_0, "SCAN_CODE_0");
|
||||
}
|
||||
|
||||
void LinuxSampleUserInput::registerScanCode(LinuxSampleUserInputIds scanCodeId, physx::PxU16 scanCode, LinuxSampleUserInputIds nameId, const char* name)
|
||||
{
|
||||
const UserInput* ui = getUserInputFromId(nameId);
|
||||
if(ui)
|
||||
{
|
||||
registerUserInput(scanCodeId, name, ui->m_Name);
|
||||
m_ScanCodesMap[scanCode] = scanCodeId;
|
||||
}
|
||||
}
|
||||
|
||||
const UserInput* LinuxSampleUserInput::getUserInputFromId(LinuxSampleUserInputIds id) const
|
||||
{
|
||||
for (size_t i = mUserInputs.size(); i--;)
|
||||
{
|
||||
if(mUserInputs[i].m_Id == id)
|
||||
{
|
||||
return &mUserInputs[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LinuxSampleUserInput::~LinuxSampleUserInput()
|
||||
{
|
||||
m_ScanCodesMap.clear();
|
||||
m_AnalogStates.clear();
|
||||
m_DigitalStates.clear();
|
||||
}
|
||||
|
||||
LinuxSampleUserInputIds LinuxSampleUserInput::getInputIdFromMouseButton(const physx::PxU16 b) const
|
||||
{
|
||||
if (b == Button1) return MOUSE_BUTTON_LEFT;
|
||||
else if (b == Button2) return MOUSE_BUTTON_CENTER;
|
||||
else if (b == Button3) return MOUSE_BUTTON_RIGHT;
|
||||
else return LINUXKEY_UNKNOWN;
|
||||
}
|
||||
|
||||
LinuxSampleUserInputIds LinuxSampleUserInput::getInputIdFromKeySym(const KeySym keySym) const
|
||||
{
|
||||
LinuxSampleUserInputIds id = LINUXKEY_UNKNOWN;
|
||||
|
||||
if(keySym >= XK_A && keySym <= XK_Z) id = (LinuxSampleUserInputIds)((keySym - XK_A)+LINUXKEY_A);
|
||||
else if(keySym >= XK_a && keySym <= XK_z) id = (LinuxSampleUserInputIds)((keySym - XK_a)+LINUXKEY_A);
|
||||
else if(keySym >= XK_0 && keySym <= XK_9) id = (LinuxSampleUserInputIds)((keySym - XK_0)+LINUXKEY_0);
|
||||
else if(keySym >= XK_KP_0 && keySym <= XK_KP_9) id = (LinuxSampleUserInputIds)((keySym - XK_KP_0)+LINUXKEY_NUMPAD0);
|
||||
else if(keySym == XK_Shift_L || keySym == XK_Shift_R) id = LINUXKEY_SHIFT;
|
||||
else if(keySym == XK_Control_L || keySym == XK_Control_R) id = LINUXKEY_CONTROL;
|
||||
else if(keySym == XK_space) id = LINUXKEY_SPACE;
|
||||
else if(keySym == XK_Return) id = LINUXKEY_RETURN;
|
||||
else if(keySym == XK_Escape) id = LINUXKEY_ESCAPE;
|
||||
else if(keySym == XK_KP_Separator) id = LINUXKEY_COMMA;
|
||||
else if(keySym == XK_KP_Divide) id = LINUXKEY_DIVIDE;
|
||||
else if(keySym == XK_KP_Subtract) id = LINUXKEY_SUBTRACT;
|
||||
else if(keySym == XK_KP_Add) id = LINUXKEY_ADD;
|
||||
//
|
||||
else if(keySym == XK_F1) id = LINUXKEY_F1;
|
||||
else if(keySym == XK_F2) id = LINUXKEY_F2;
|
||||
else if(keySym == XK_F3) id = LINUXKEY_F3;
|
||||
else if(keySym == XK_F4) id = LINUXKEY_F4;
|
||||
else if(keySym == XK_F5) id = LINUXKEY_F5;
|
||||
else if(keySym == XK_F6) id = LINUXKEY_F6;
|
||||
else if(keySym == XK_F7) id = LINUXKEY_F7;
|
||||
else if(keySym == XK_F8) id = LINUXKEY_F8;
|
||||
else if(keySym == XK_F9) id = LINUXKEY_F9;
|
||||
else if(keySym == XK_F10) id = LINUXKEY_F10;
|
||||
else if(keySym == XK_F11) id = LINUXKEY_F11;
|
||||
else if(keySym == XK_F12) id = LINUXKEY_F12;
|
||||
//
|
||||
else if(keySym == XK_Tab) id = LINUXKEY_TAB;
|
||||
//
|
||||
else if(keySym == XK_BackSpace) id = LINUXKEY_BACKSPACE;
|
||||
else if(keySym == XK_Prior) id = LINUXKEY_PRIOR;
|
||||
else if(keySym == XK_Next) id = LINUXKEY_NEXT;
|
||||
//
|
||||
else if(keySym == XK_Up) id = LINUXKEY_UP;
|
||||
else if(keySym == XK_Down) id = LINUXKEY_DOWN;
|
||||
else if(keySym == XK_Left) id = LINUXKEY_LEFT;
|
||||
else if(keySym == XK_Right) id = LINUXKEY_RIGHT;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void LinuxSampleUserInput::doOnMouseMove(physx::PxU32 x, physx::PxU32 y, physx::PxReal dx, physx::PxReal dy, physx::PxU16 button)
|
||||
{
|
||||
const std::vector<size_t>* events = getInputEvents(button);
|
||||
|
||||
if(events)
|
||||
{
|
||||
for (size_t i = events->size(); i--;)
|
||||
{
|
||||
const InputEvent& ie = mInputEvents[(*events)[i]];
|
||||
if(getInputEventListener())
|
||||
{
|
||||
getInputEventListener()->onPointerInputEvent(ie, x, y, dx, dy, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void LinuxSampleUserInput::doOnMouseDown(physx::PxU32 x, physx::PxU32 y, physx::PxU16 button)
|
||||
{
|
||||
const std::vector<size_t>* events = getInputEvents(getInputIdFromMouseButton(button));
|
||||
|
||||
if(events)
|
||||
{
|
||||
for (size_t i = events->size(); i--;)
|
||||
{
|
||||
const InputEvent& ie = mInputEvents[(*events)[i]];
|
||||
m_DigitalStates[ie.m_Id] = true;
|
||||
|
||||
if(getInputEventListener())
|
||||
{
|
||||
getInputEventListener()->onPointerInputEvent(ie, x, y, 0, 0, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LinuxSampleUserInput::doOnMouseUp(physx::PxU32 x, physx::PxU32 y, physx::PxU16 button)
|
||||
{
|
||||
const std::vector<size_t>* events = getInputEvents(getInputIdFromMouseButton(button));
|
||||
if(events)
|
||||
{
|
||||
for (size_t i = events->size(); i--;)
|
||||
{
|
||||
const InputEvent& ie = mInputEvents[(*events)[i]];
|
||||
m_DigitalStates[ie.m_Id] = false;
|
||||
|
||||
if(getInputEventListener())
|
||||
{
|
||||
getInputEventListener()->onPointerInputEvent(ie, x, y, 0, 0, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LinuxSampleUserInput::doOnKeyDown(KeySym keySym, physx::PxU16 keyCode, physx::PxU8 ascii)
|
||||
{
|
||||
const std::vector<size_t>* events = NULL;
|
||||
|
||||
if(getInputEventListener())
|
||||
{
|
||||
//raw ASCII printable characters get sent to the console
|
||||
if (ascii >= 'a' && ascii <= 'z')
|
||||
{
|
||||
getInputEventListener()->onKeyDownEx(static_cast<KeyCode>(ascii - 'a' + KEY_A), ascii);
|
||||
}
|
||||
else if (ascii >= 'A' && ascii <= 'Z')
|
||||
{
|
||||
getInputEventListener()->onKeyDownEx(static_cast<KeyCode>(ascii - 'A' + KEY_A), ascii);
|
||||
}
|
||||
else if (ascii >= '0' && ascii <= '9')
|
||||
{
|
||||
getInputEventListener()->onKeyDownEx(static_cast<KeyCode>(ascii - 'A' + KEY_A), ascii);
|
||||
}
|
||||
else if (ascii == ' ')
|
||||
{
|
||||
getInputEventListener()->onKeyDownEx(static_cast<KeyCode>(ascii - ' ' + KEY_SPACE), ascii);
|
||||
}
|
||||
else if (ascii == '.')
|
||||
{
|
||||
getInputEventListener()->onKeyDownEx(static_cast<KeyCode>(ascii - '.' + KEY_DECIMAL), ascii);
|
||||
}
|
||||
|
||||
|
||||
std::map<physx::PxU16, physx::PxU16>::iterator fit = m_ScanCodesMap.find(keyCode);
|
||||
if(fit != m_ScanCodesMap.end())
|
||||
{
|
||||
events = getInputEvents(fit->second);
|
||||
}
|
||||
|
||||
if(!events)
|
||||
{
|
||||
LinuxSampleUserInputIds id = getInputIdFromKeySym(keySym);
|
||||
events = getInputEvents(id);
|
||||
}
|
||||
|
||||
if(!events || !getInputEventListener())
|
||||
return;
|
||||
|
||||
for (size_t i = events->size(); i--;)
|
||||
{
|
||||
const InputEvent& ie = mInputEvents[(*events)[i]];
|
||||
m_DigitalStates[ie.m_Id] = true;
|
||||
getInputEventListener()->onDigitalInputEvent(ie, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxSampleUserInput::doOnKeyUp( KeySym keySym, physx::PxU16 keyCode, physx::PxU8 ascii)
|
||||
{
|
||||
const std::vector<size_t>* events = NULL;
|
||||
std::map<physx::PxU16, physx::PxU16>::iterator fit = m_ScanCodesMap.find(keyCode);
|
||||
if(fit != m_ScanCodesMap.end())
|
||||
{
|
||||
events = getInputEvents(fit->second);
|
||||
}
|
||||
if(!events)
|
||||
{
|
||||
LinuxSampleUserInputIds id = getInputIdFromKeySym(keySym);
|
||||
events = getInputEvents(id);
|
||||
}
|
||||
|
||||
if(!events || !getInputEventListener())
|
||||
return;
|
||||
|
||||
for (size_t i = events->size(); i--;)
|
||||
{
|
||||
const InputEvent& ie = mInputEvents[(*events)[i]];
|
||||
m_DigitalStates[ie.m_Id] = false;
|
||||
getInputEventListener()->onDigitalInputEvent(ie, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool LinuxSampleUserInput::getDigitalInputEventState(physx::PxU16 inputEventId ) const
|
||||
{
|
||||
std::map<physx::PxU16,bool>::const_iterator fit = m_DigitalStates.find(inputEventId);
|
||||
if(fit != m_DigitalStates.end())
|
||||
{
|
||||
return fit->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
float LinuxSampleUserInput::getAnalogInputEventState(physx::PxU16 inputEventId ) const
|
||||
{
|
||||
std::map<physx::PxU16,float>::const_iterator fit = m_AnalogStates.find(inputEventId);
|
||||
if(fit != m_AnalogStates.end())
|
||||
{
|
||||
return fit->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxSampleUserInput::shutdown()
|
||||
{
|
||||
m_AnalogStates.clear();
|
||||
m_DigitalStates.clear();
|
||||
|
||||
SampleUserInput::shutdown();
|
||||
}
|
||||
|
||||
void LinuxSampleUserInput::updateInput()
|
||||
{
|
||||
SampleUserInput::updateInput();
|
||||
|
||||
processGamepads();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user