mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 23:09:52 +02:00
Merge branch 'master' into 20226
This commit is contained in:
commit
ff6db7a9fa
19 changed files with 82 additions and 170 deletions
|
@ -22,7 +22,7 @@ var velocity = {
|
||||||
y: 0,
|
y: 0,
|
||||||
z: 1 };
|
z: 1 };
|
||||||
|
|
||||||
var damping = 0.1;
|
var damping = 0;
|
||||||
|
|
||||||
var color = {
|
var color = {
|
||||||
red: 255,
|
red: 255,
|
||||||
|
|
|
@ -9,8 +9,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
Script.load("lookWithTouch.js");
|
Script.load("lookWithTouch.js");
|
||||||
Script.load("editVoxels.js");
|
Script.load("editEntities.js");
|
||||||
Script.load("editModels.js");
|
|
||||||
Script.load("selectAudioDevice.js");
|
Script.load("selectAudioDevice.js");
|
||||||
Script.load("hydraMove.js");
|
Script.load("hydraMove.js");
|
||||||
Script.load("headMove.js");
|
Script.load("headMove.js");
|
||||||
|
|
|
@ -13,8 +13,8 @@ Script.include("libraries/globals.js");
|
||||||
|
|
||||||
var panelWall = false;
|
var panelWall = false;
|
||||||
var orbShell = false;
|
var orbShell = false;
|
||||||
var reticle = false;
|
|
||||||
var descriptionText = false;
|
var descriptionText = false;
|
||||||
|
var showText = false;
|
||||||
|
|
||||||
// used for formating the description text, in meters
|
// used for formating the description text, in meters
|
||||||
var textWidth = 4;
|
var textWidth = 4;
|
||||||
|
@ -23,8 +23,6 @@ var numberOfLines = 2;
|
||||||
var textMargin = 0.0625;
|
var textMargin = 0.0625;
|
||||||
var lineHeight = (textHeight - (2 * textMargin)) / numberOfLines;
|
var lineHeight = (textHeight - (2 * textMargin)) / numberOfLines;
|
||||||
|
|
||||||
var lastMouseMove = 0;
|
|
||||||
var IDLE_HOVER_TIME = 2000; // if you haven't moved the mouse in 2 seconds, and in HMD mode, then we use reticle for hover
|
|
||||||
var avatarStickPosition = {};
|
var avatarStickPosition = {};
|
||||||
|
|
||||||
var orbNaturalExtentsMin = { x: -1.230354, y: -1.22077, z: -1.210487 };
|
var orbNaturalExtentsMin = { x: -1.230354, y: -1.22077, z: -1.210487 };
|
||||||
|
@ -57,13 +55,6 @@ var elevatorSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/eleva
|
||||||
var currentMuzakInjector = null;
|
var currentMuzakInjector = null;
|
||||||
var currentSound = null;
|
var currentSound = null;
|
||||||
|
|
||||||
var inOculusMode = false;
|
|
||||||
|
|
||||||
function reticlePosition() {
|
|
||||||
var RETICLE_DISTANCE = 1;
|
|
||||||
return Vec3.sum(Camera.position, Vec3.multiply(Quat.getFront(Camera.orientation), RETICLE_DISTANCE));
|
|
||||||
}
|
|
||||||
|
|
||||||
function textOverlayPosition() {
|
function textOverlayPosition() {
|
||||||
var TEXT_DISTANCE_OUT = 6;
|
var TEXT_DISTANCE_OUT = 6;
|
||||||
var TEXT_DISTANCE_DOWN = -2;
|
var TEXT_DISTANCE_DOWN = -2;
|
||||||
|
@ -124,22 +115,6 @@ function drawLobby() {
|
||||||
panelWall = Overlays.addOverlay("model", panelWallProps);
|
panelWall = Overlays.addOverlay("model", panelWallProps);
|
||||||
orbShell = Overlays.addOverlay("model", orbShellProps);
|
orbShell = Overlays.addOverlay("model", orbShellProps);
|
||||||
descriptionText = Overlays.addOverlay("text3d", descriptionTextProps);
|
descriptionText = Overlays.addOverlay("text3d", descriptionTextProps);
|
||||||
|
|
||||||
inOculusMode = Menu.isOptionChecked("Enable VR Mode");
|
|
||||||
|
|
||||||
// for HMD wearers, create a reticle in center of screen
|
|
||||||
if (inOculusMode) {
|
|
||||||
var CURSOR_SCALE = 0.025;
|
|
||||||
|
|
||||||
reticle = Overlays.addOverlay("billboard", {
|
|
||||||
url: HIFI_PUBLIC_BUCKET + "images/cursor.svg",
|
|
||||||
position: reticlePosition(),
|
|
||||||
ignoreRayIntersection: true,
|
|
||||||
isFacingAvatar: true,
|
|
||||||
alpha: 1.0,
|
|
||||||
scale: CURSOR_SCALE
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// add an attachment on this avatar so other people see them in the lobby
|
// add an attachment on this avatar so other people see them in the lobby
|
||||||
MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15);
|
MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15);
|
||||||
|
@ -227,14 +202,8 @@ function cleanupLobby() {
|
||||||
Overlays.deleteOverlay(orbShell);
|
Overlays.deleteOverlay(orbShell);
|
||||||
Overlays.deleteOverlay(descriptionText);
|
Overlays.deleteOverlay(descriptionText);
|
||||||
|
|
||||||
|
|
||||||
if (reticle) {
|
|
||||||
Overlays.deleteOverlay(reticle);
|
|
||||||
}
|
|
||||||
|
|
||||||
panelWall = false;
|
panelWall = false;
|
||||||
orbShell = false;
|
orbShell = false;
|
||||||
reticle = false;
|
|
||||||
|
|
||||||
Audio.stopInjector(currentDrone);
|
Audio.stopInjector(currentDrone);
|
||||||
currentDrone = null;
|
currentDrone = null;
|
||||||
|
@ -313,7 +282,7 @@ function handleLookAt(pickRay) {
|
||||||
var actionLocation = locations[panelIndex];
|
var actionLocation = locations[panelIndex];
|
||||||
|
|
||||||
if (actionLocation.description == "") {
|
if (actionLocation.description == "") {
|
||||||
Overlays.editOverlay(descriptionText, { text: actionLocation.name, visible: true });
|
Overlays.editOverlay(descriptionText, { text: actionLocation.name, visible: showText });
|
||||||
} else {
|
} else {
|
||||||
// handle line wrapping
|
// handle line wrapping
|
||||||
var allWords = actionLocation.description.split(" ");
|
var allWords = actionLocation.description.split(" ");
|
||||||
|
@ -345,7 +314,7 @@ function handleLookAt(pickRay) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
formatedDescription += currentGoodLine;
|
formatedDescription += currentGoodLine;
|
||||||
Overlays.editOverlay(descriptionText, { text: formatedDescription, visible: true });
|
Overlays.editOverlay(descriptionText, { text: formatedDescription, visible: showText });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Overlays.editOverlay(descriptionText, { text: "", visible: false });
|
Overlays.editOverlay(descriptionText, { text: "", visible: false });
|
||||||
|
@ -358,20 +327,6 @@ function handleLookAt(pickRay) {
|
||||||
function update(deltaTime) {
|
function update(deltaTime) {
|
||||||
maybeCleanupLobby();
|
maybeCleanupLobby();
|
||||||
if (panelWall) {
|
if (panelWall) {
|
||||||
|
|
||||||
if (reticle) {
|
|
||||||
Overlays.editOverlay(reticle, {
|
|
||||||
position: reticlePosition()
|
|
||||||
});
|
|
||||||
|
|
||||||
var nowDate = new Date();
|
|
||||||
var now = nowDate.getTime();
|
|
||||||
if (now - lastMouseMove > IDLE_HOVER_TIME) {
|
|
||||||
var pickRay = Camera.computeViewPickRay(0.5, 0.5);
|
|
||||||
handleLookAt(pickRay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Overlays.editOverlay(descriptionText, { position: textOverlayPosition() });
|
Overlays.editOverlay(descriptionText, { position: textOverlayPosition() });
|
||||||
|
|
||||||
// if the reticle is up then we may need to play the next muzak
|
// if the reticle is up then we may need to play the next muzak
|
||||||
|
@ -383,8 +338,6 @@ function update(deltaTime) {
|
||||||
|
|
||||||
function mouseMoveEvent(event) {
|
function mouseMoveEvent(event) {
|
||||||
if (panelWall) {
|
if (panelWall) {
|
||||||
var nowDate = new Date();
|
|
||||||
lastMouseMove = nowDate.getTime();
|
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
handleLookAt(pickRay);
|
handleLookAt(pickRay);
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,8 +167,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
_raiseMirror(0.0f),
|
_raiseMirror(0.0f),
|
||||||
_lastMouseMove(usecTimestampNow()),
|
_lastMouseMove(usecTimestampNow()),
|
||||||
_lastMouseMoveWasSimulated(false),
|
_lastMouseMoveWasSimulated(false),
|
||||||
_mouseHidden(false),
|
|
||||||
_seenMouseMove(false),
|
|
||||||
_touchAvgX(0.0f),
|
_touchAvgX(0.0f),
|
||||||
_touchAvgY(0.0f),
|
_touchAvgY(0.0f),
|
||||||
_isTouchPressed(false),
|
_isTouchPressed(false),
|
||||||
|
@ -1130,7 +1128,8 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
if (!event->isAutoRepeat()) {
|
if (!event->isAutoRepeat()) {
|
||||||
// this starts an HFActionEvent
|
// this starts an HFActionEvent
|
||||||
HFActionEvent startActionEvent(HFActionEvent::startType(),
|
HFActionEvent startActionEvent(HFActionEvent::startType(),
|
||||||
_myCamera.computeViewPickRay(0.5f, 0.5f));
|
_myCamera.computePickRay(getTrueMouseX(),
|
||||||
|
getTrueMouseY()));
|
||||||
sendEvent(this, &startActionEvent);
|
sendEvent(this, &startActionEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1221,10 +1220,11 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
|
||||||
case Qt::Key_Space: {
|
case Qt::Key_Space: {
|
||||||
if (!event->isAutoRepeat()) {
|
if (!event->isAutoRepeat()) {
|
||||||
// this ends the HFActionEvent
|
// this ends the HFActionEvent
|
||||||
HFActionEvent endActionEvent(HFActionEvent::endType(), _myCamera.computeViewPickRay(0.5f, 0.5f));
|
HFActionEvent endActionEvent(HFActionEvent::endType(),
|
||||||
|
_myCamera.computePickRay(getTrueMouseX(),
|
||||||
|
getTrueMouseY()));
|
||||||
sendEvent(this, &endActionEvent);
|
sendEvent(this, &endActionEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Qt::Key_Escape: {
|
case Qt::Key_Escape: {
|
||||||
|
@ -1233,7 +1233,6 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
|
||||||
HFBackEvent endBackEvent(HFBackEvent::endType());
|
HFBackEvent endBackEvent(HFBackEvent::endType());
|
||||||
sendEvent(this, &endBackEvent);
|
sendEvent(this, &endBackEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -1252,34 +1251,24 @@ void Application::focusOutEvent(QFocusEvent* event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
|
void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
|
||||||
bool showMouse = true;
|
|
||||||
|
|
||||||
// Used by application overlay to determine how to draw cursor(s)
|
// Used by application overlay to determine how to draw cursor(s)
|
||||||
_lastMouseMoveWasSimulated = deviceID > 0;
|
_lastMouseMoveWasSimulated = deviceID > 0;
|
||||||
|
if (!_lastMouseMoveWasSimulated) {
|
||||||
// If this mouse move event is emitted by a controller, dont show the mouse cursor
|
_lastMouseMove = usecTimestampNow();
|
||||||
if (_lastMouseMoveWasSimulated) {
|
|
||||||
showMouse = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_aboutToQuit) {
|
if (_aboutToQuit) {
|
||||||
_entities.mouseMoveEvent(event, deviceID);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_entities.mouseMoveEvent(event, deviceID);
|
||||||
|
|
||||||
_controllerScriptingInterface.emitMouseMoveEvent(event, deviceID); // send events to any registered scripts
|
_controllerScriptingInterface.emitMouseMoveEvent(event, deviceID); // send events to any registered scripts
|
||||||
|
|
||||||
// if one of our scripts have asked to capture this event, then stop processing it
|
// if one of our scripts have asked to capture this event, then stop processing it
|
||||||
if (_controllerScriptingInterface.isMouseCaptured()) {
|
if (_controllerScriptingInterface.isMouseCaptured()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastMouseMove = usecTimestampNow();
|
|
||||||
|
|
||||||
if (_mouseHidden && showMouse && !OculusManager::isConnected() && !TV3DManager::isConnected()) {
|
|
||||||
getGLWidget()->setCursor(Qt::ArrowCursor);
|
|
||||||
_mouseHidden = false;
|
|
||||||
_seenMouseMove = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
|
void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
|
||||||
|
@ -2111,13 +2100,7 @@ void Application::updateMouseRay() {
|
||||||
// make sure the frustum is up-to-date
|
// make sure the frustum is up-to-date
|
||||||
loadViewFrustum(_myCamera, _viewFrustum);
|
loadViewFrustum(_myCamera, _viewFrustum);
|
||||||
|
|
||||||
// if the mouse pointer isn't visible, act like it's at the center of the screen
|
PickRay pickRay = _myCamera.computePickRay(getTrueMouseX(), getTrueMouseY());
|
||||||
float x = 0.5f, y = 0.5f;
|
|
||||||
if (!_mouseHidden) {
|
|
||||||
x = getTrueMouseX() / (float)_glWidget->width();
|
|
||||||
y = getTrueMouseY() / (float)_glWidget->height();
|
|
||||||
}
|
|
||||||
PickRay pickRay = _myCamera.computeViewPickRay(x, y);
|
|
||||||
_mouseRayOrigin = pickRay.origin;
|
_mouseRayOrigin = pickRay.origin;
|
||||||
_mouseRayDirection = pickRay.direction;
|
_mouseRayDirection = pickRay.direction;
|
||||||
|
|
||||||
|
@ -2313,22 +2296,29 @@ void Application::updateCursor(float deltaTime) {
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
PerformanceWarning warn(showWarnings, "Application::updateCursor()");
|
PerformanceWarning warn(showWarnings, "Application::updateCursor()");
|
||||||
|
|
||||||
// watch mouse position, if it hasn't moved, hide the cursor
|
bool hideMouse = false;
|
||||||
bool underMouse = _glWidget->underMouse();
|
bool underMouse = _glWidget->underMouse();
|
||||||
if (!_mouseHidden) {
|
|
||||||
quint64 now = usecTimestampNow();
|
static const int HIDE_CURSOR_TIMEOUT = 3 * USECS_PER_SECOND; // 3 second
|
||||||
int elapsed = now - _lastMouseMove;
|
int elapsed = usecTimestampNow() - _lastMouseMove;
|
||||||
const int HIDE_CURSOR_TIMEOUT = 1 * 1000 * 1000; // 1 second
|
if ((elapsed > HIDE_CURSOR_TIMEOUT && underMouse) ||
|
||||||
if (elapsed > HIDE_CURSOR_TIMEOUT && (underMouse || !_seenMouseMove)) {
|
(OculusManager::isConnected() && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode))) {
|
||||||
getGLWidget()->setCursor(Qt::BlankCursor);
|
hideMouse = true;
|
||||||
_mouseHidden = true;
|
}
|
||||||
|
|
||||||
|
setCursorVisible(!hideMouse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::setCursorVisible(bool visible) {
|
||||||
|
if (visible) {
|
||||||
|
if (overrideCursor() != NULL) {
|
||||||
|
restoreOverrideCursor();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if the mouse is hidden, but we're not inside our window, then consider ourselves to be moving
|
if (overrideCursor() != NULL) {
|
||||||
if (!underMouse && _seenMouseMove) {
|
changeOverrideCursor(Qt::BlankCursor);
|
||||||
_lastMouseMove = usecTimestampNow();
|
} else {
|
||||||
getGLWidget()->setCursor(Qt::ArrowCursor);
|
setOverrideCursor(Qt::BlankCursor);
|
||||||
_mouseHidden = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2350,17 +2340,6 @@ void Application::update(float deltaTime) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QCursor cursor;
|
|
||||||
if (OculusManager::isConnected() &&
|
|
||||||
Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)){
|
|
||||||
if (_window->cursor().shape() != Qt::BlankCursor) {
|
|
||||||
cursor = _window->cursor();
|
|
||||||
_window->setCursor(QCursor(Qt::BlankCursor));
|
|
||||||
}
|
|
||||||
} else if(_window->cursor().shape() == Qt::BlankCursor) {
|
|
||||||
_window->setCursor(cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispatch input events
|
// Dispatch input events
|
||||||
_controllerScriptingInterface.updateInputControllers();
|
_controllerScriptingInterface.updateInputControllers();
|
||||||
|
|
||||||
|
@ -2874,8 +2853,13 @@ void Application::updateShadowMap() {
|
||||||
|
|
||||||
// store view matrix without translation, which we'll use for precision-sensitive objects
|
// store view matrix without translation, which we'll use for precision-sensitive objects
|
||||||
updateUntranslatedViewMatrix();
|
updateUntranslatedViewMatrix();
|
||||||
// TODO: assign an equivalent viewTransform object to the application to match the current path which uses glMatrixStack
|
|
||||||
// setViewTransform(viewTransform);
|
// Equivalent to what is happening with _untranslatedViewMatrix and the _viewMatrixTranslation
|
||||||
|
// the viewTransofmr object is updatded with the correct values and saved,
|
||||||
|
// this is what is used for rendering the Entities and avatars
|
||||||
|
Transform viewTransform;
|
||||||
|
viewTransform.setRotation(rotation);
|
||||||
|
setViewTransform(viewTransform);
|
||||||
|
|
||||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||||
glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt
|
glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt
|
||||||
|
@ -4372,14 +4356,6 @@ void Application::skipVersion(QString latestVersion) {
|
||||||
skipFile.write(latestVersion.toStdString().c_str());
|
skipFile.write(latestVersion.toStdString().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setCursorVisible(bool visible) {
|
|
||||||
if (visible) {
|
|
||||||
restoreOverrideCursor();
|
|
||||||
} else {
|
|
||||||
setOverrideCursor(Qt::BlankCursor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::takeSnapshot() {
|
void Application::takeSnapshot() {
|
||||||
QMediaPlayer* player = new QMediaPlayer();
|
QMediaPlayer* player = new QMediaPlayer();
|
||||||
QFileInfo inf = QFileInfo(Application::resourcesPath() + "sounds/snap.wav");
|
QFileInfo inf = QFileInfo(Application::resourcesPath() + "sounds/snap.wav");
|
||||||
|
|
|
@ -211,7 +211,8 @@ public:
|
||||||
EntityTreeRenderer* getEntityClipboardRenderer() { return &_entityClipboardRenderer; }
|
EntityTreeRenderer* getEntityClipboardRenderer() { return &_entityClipboardRenderer; }
|
||||||
Environment* getEnvironment() { return &_environment; }
|
Environment* getEnvironment() { return &_environment; }
|
||||||
bool isMousePressed() const { return _mousePressed; }
|
bool isMousePressed() const { return _mousePressed; }
|
||||||
bool isMouseHidden() const { return _mouseHidden; }
|
bool isMouseHidden() const { return _glWidget->cursor().shape() == Qt::BlankCursor; }
|
||||||
|
void setCursorVisible(bool visible);
|
||||||
const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }
|
const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }
|
||||||
const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
|
const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
|
||||||
bool mouseOnScreen() const;
|
bool mouseOnScreen() const;
|
||||||
|
@ -309,8 +310,6 @@ public:
|
||||||
|
|
||||||
QStringList getRunningScripts() { return _scriptEnginesHash.keys(); }
|
QStringList getRunningScripts() { return _scriptEnginesHash.keys(); }
|
||||||
ScriptEngine* getScriptEngine(QString scriptHash) { return _scriptEnginesHash.contains(scriptHash) ? _scriptEnginesHash[scriptHash] : NULL; }
|
ScriptEngine* getScriptEngine(QString scriptHash) { return _scriptEnginesHash.contains(scriptHash) ? _scriptEnginesHash[scriptHash] : NULL; }
|
||||||
|
|
||||||
void setCursorVisible(bool visible);
|
|
||||||
|
|
||||||
bool isLookingAtMyAvatar(Avatar* avatar);
|
bool isLookingAtMyAvatar(Avatar* avatar);
|
||||||
|
|
||||||
|
@ -567,8 +566,6 @@ private:
|
||||||
int _mouseDragStartedY;
|
int _mouseDragStartedY;
|
||||||
quint64 _lastMouseMove;
|
quint64 _lastMouseMove;
|
||||||
bool _lastMouseMoveWasSimulated;
|
bool _lastMouseMoveWasSimulated;
|
||||||
bool _mouseHidden;
|
|
||||||
bool _seenMouseMove;
|
|
||||||
|
|
||||||
glm::vec3 _mouseRayOrigin;
|
glm::vec3 _mouseRayOrigin;
|
||||||
glm::vec3 _mouseRayDirection;
|
glm::vec3 _mouseRayDirection;
|
||||||
|
|
|
@ -536,7 +536,7 @@ void ApplicationOverlay::renderPointers() {
|
||||||
glm::vec2 screenPos = sphericalToScreen(glm::vec2(yaw, -pitch));
|
glm::vec2 screenPos = sphericalToScreen(glm::vec2(yaw, -pitch));
|
||||||
|
|
||||||
position = QPoint(screenPos.x, screenPos.y);
|
position = QPoint(screenPos.x, screenPos.y);
|
||||||
QCursor::setPos(application->getGLWidget()->mapToGlobal(position));
|
application->getGLWidget()->cursor().setPos(application->getGLWidget()->mapToGlobal(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
_reticlePosition[MOUSE] = position;
|
_reticlePosition[MOUSE] = position;
|
||||||
|
|
|
@ -122,21 +122,21 @@ void FramelessDialog::mousePressEvent(QMouseEvent* mouseEvent) {
|
||||||
if (hitLeft || hitRight) {
|
if (hitLeft || hitRight) {
|
||||||
_isResizing = true;
|
_isResizing = true;
|
||||||
_resizeInitialWidth = size().width();
|
_resizeInitialWidth = size().width();
|
||||||
QApplication::setOverrideCursor(Qt::SizeHorCursor);
|
setCursor(Qt::SizeHorCursor);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bool hitTop = (_position == POSITION_TOP) && (abs(mouseEvent->pos().y() - size().height()) < RESIZE_HANDLE_WIDTH);
|
bool hitTop = (_position == POSITION_TOP) && (abs(mouseEvent->pos().y() - size().height()) < RESIZE_HANDLE_WIDTH);
|
||||||
if (hitTop) {
|
if (hitTop) {
|
||||||
_isResizing = true;
|
_isResizing = true;
|
||||||
_resizeInitialWidth = size().height();
|
_resizeInitialWidth = size().height();
|
||||||
QApplication::setOverrideCursor(Qt::SizeHorCursor);
|
setCursor(Qt::SizeHorCursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramelessDialog::mouseReleaseEvent(QMouseEvent* mouseEvent) {
|
void FramelessDialog::mouseReleaseEvent(QMouseEvent* mouseEvent) {
|
||||||
QApplication::restoreOverrideCursor();
|
unsetCursor();
|
||||||
_isResizing = false;
|
_isResizing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,12 +170,6 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) {
|
||||||
|
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
|
|
||||||
Collision collision;
|
|
||||||
collision.penetration = penetration;
|
|
||||||
// for now the contactPoint is the average between the the two paricle centers
|
|
||||||
collision.contactPoint = (0.5f * (float)TREE_SCALE) * (entityA->getPosition() + entityB->getPosition());
|
|
||||||
emitGlobalEntityCollisionWithEntity(entityA, entityB, collision);
|
|
||||||
|
|
||||||
glm::vec3 axis = glm::normalize(penetration);
|
glm::vec3 axis = glm::normalize(penetration);
|
||||||
glm::vec3 axialVelocity = glm::dot(relativeVelocity, axis) * axis;
|
glm::vec3 axialVelocity = glm::dot(relativeVelocity, axis) * axis;
|
||||||
|
|
||||||
|
@ -232,7 +226,13 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) {
|
||||||
// thereby waking up static non-moving entities.
|
// thereby waking up static non-moving entities.
|
||||||
_entityTree->updateEntity(entityB, propertiesB);
|
_entityTree->updateEntity(entityB, propertiesB);
|
||||||
_packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idB, propertiesB);
|
_packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idB, propertiesB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: Do this after updating the entities so that the callback can delete the entities if they want to
|
||||||
|
Collision collision;
|
||||||
|
collision.penetration = penetration;
|
||||||
|
collision.contactPoint = (0.5f * (float)TREE_SCALE) * (entityA->getPosition() + entityB->getPosition());
|
||||||
|
emitGlobalEntityCollisionWithEntity(entityA, entityB, collision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,8 +227,6 @@ public:
|
||||||
float getSize() const; /// get maximum dimension in domain scale units (0.0 - 1.0)
|
float getSize() const; /// get maximum dimension in domain scale units (0.0 - 1.0)
|
||||||
AACube getMaximumAACube() const;
|
AACube getMaximumAACube() const;
|
||||||
AACube getMinimumAACube() const;
|
AACube getMinimumAACube() const;
|
||||||
AACube getOldMaximumAACube() const { return _oldMaximumAACube; }
|
|
||||||
void setOldMaximumAACube(const AACube& cube) { _oldMaximumAACube = cube; }
|
|
||||||
AABox getAABox() const; /// axis aligned bounding box in domain scale units (0.0 - 1.0)
|
AABox getAABox() const; /// axis aligned bounding box in domain scale units (0.0 - 1.0)
|
||||||
|
|
||||||
static const QString DEFAULT_SCRIPT;
|
static const QString DEFAULT_SCRIPT;
|
||||||
|
@ -347,7 +345,6 @@ protected:
|
||||||
void setRadius(float value);
|
void setRadius(float value);
|
||||||
|
|
||||||
AACubeShape _collisionShape;
|
AACubeShape _collisionShape;
|
||||||
AACube _oldMaximumAACube; // remember this so we know where the entity used to live in the tree
|
|
||||||
|
|
||||||
// DirtyFlags are set whenever a property changes that the EntitySimulation needs to know about.
|
// DirtyFlags are set whenever a property changes that the EntitySimulation needs to know about.
|
||||||
uint32_t _dirtyFlags; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation
|
uint32_t _dirtyFlags; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation
|
||||||
|
|
|
@ -106,7 +106,6 @@ void EntitySimulation::sortEntitiesThatMoved() {
|
||||||
if (moveOperator.hasMovingEntities()) {
|
if (moveOperator.hasMovingEntities()) {
|
||||||
PerformanceTimer perfTimer("recurseTreeWithOperator");
|
PerformanceTimer perfTimer("recurseTreeWithOperator");
|
||||||
_entityTree->recurseTreeWithOperator(&moveOperator);
|
_entityTree->recurseTreeWithOperator(&moveOperator);
|
||||||
moveOperator.finish();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,6 @@ EntityItem* EntityTree::getOrCreateEntityItem(const EntityItemID& entityID, cons
|
||||||
/// Adds a new entity item to the tree
|
/// Adds a new entity item to the tree
|
||||||
void EntityTree::postAddEntity(EntityItem* entity) {
|
void EntityTree::postAddEntity(EntityItem* entity) {
|
||||||
assert(entity);
|
assert(entity);
|
||||||
entity->setOldMaximumAACube(entity->getMaximumAACube());
|
|
||||||
// check to see if we need to simulate this entity..
|
// check to see if we need to simulate this entity..
|
||||||
if (_simulation) {
|
if (_simulation) {
|
||||||
_simulation->addEntity(entity);
|
_simulation->addEntity(entity);
|
||||||
|
@ -138,7 +137,6 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro
|
||||||
|
|
||||||
UpdateEntityOperator theOperator(this, containingElement, entity, properties);
|
UpdateEntityOperator theOperator(this, containingElement, entity, properties);
|
||||||
recurseTreeWithOperator(&theOperator);
|
recurseTreeWithOperator(&theOperator);
|
||||||
entity->setOldMaximumAACube(entity->getMaximumAACube());
|
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
|
|
||||||
if (_simulation && entity->getDirtyFlags() != 0) {
|
if (_simulation && entity->getDirtyFlags() != 0) {
|
||||||
|
|
|
@ -52,14 +52,10 @@ MovingEntitiesOperator::~MovingEntitiesOperator() {
|
||||||
void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACube& newCube) {
|
void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACube& newCube) {
|
||||||
EntityTreeElement* oldContainingElement = _tree->getContainingElement(entity->getEntityItemID());
|
EntityTreeElement* oldContainingElement = _tree->getContainingElement(entity->getEntityItemID());
|
||||||
AABox newCubeClamped = newCube.clamp(0.0f, 1.0f);
|
AABox newCubeClamped = newCube.clamp(0.0f, 1.0f);
|
||||||
AACube oldCube = entity->getOldMaximumAACube();
|
|
||||||
AABox oldCubeClamped = oldCube.clamp(0.0f, 1.0f);
|
|
||||||
|
|
||||||
if (_wantDebug) {
|
if (_wantDebug) {
|
||||||
qDebug() << "MovingEntitiesOperator::addEntityToMoveList() -----------------------------";
|
qDebug() << "MovingEntitiesOperator::addEntityToMoveList() -----------------------------";
|
||||||
qDebug() << " oldCube:" << oldCube;
|
|
||||||
qDebug() << " newCube:" << newCube;
|
qDebug() << " newCube:" << newCube;
|
||||||
qDebug() << " oldCubeClamped:" << oldCubeClamped;
|
|
||||||
qDebug() << " newCubeClamped:" << newCubeClamped;
|
qDebug() << " newCubeClamped:" << newCubeClamped;
|
||||||
if (oldContainingElement) {
|
if (oldContainingElement) {
|
||||||
qDebug() << " oldContainingElement:" << oldContainingElement->getAACube();
|
qDebug() << " oldContainingElement:" << oldContainingElement->getAACube();
|
||||||
|
@ -86,9 +82,7 @@ void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACub
|
||||||
details.entity = entity;
|
details.entity = entity;
|
||||||
details.oldFound = false;
|
details.oldFound = false;
|
||||||
details.newFound = false;
|
details.newFound = false;
|
||||||
details.oldCube = oldCube;
|
|
||||||
details.newCube = newCube;
|
details.newCube = newCube;
|
||||||
details.oldCubeClamped = oldCubeClamped;
|
|
||||||
details.newCubeClamped = newCubeClamped;
|
details.newCubeClamped = newCubeClamped;
|
||||||
_entitiesToMove << details;
|
_entitiesToMove << details;
|
||||||
_lookingCount++;
|
_lookingCount++;
|
||||||
|
@ -97,7 +91,6 @@ void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACub
|
||||||
qDebug() << "MovingEntitiesOperator::addEntityToMoveList() -----------------------------";
|
qDebug() << "MovingEntitiesOperator::addEntityToMoveList() -----------------------------";
|
||||||
qDebug() << " details.entity:" << details.entity->getEntityItemID();
|
qDebug() << " details.entity:" << details.entity->getEntityItemID();
|
||||||
qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube;
|
qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube;
|
||||||
qDebug() << " details.oldCube:" << details.oldCube;
|
|
||||||
qDebug() << " details.newCube:" << details.newCube;
|
qDebug() << " details.newCube:" << details.newCube;
|
||||||
qDebug() << " details.newCubeClamped:" << details.newCubeClamped;
|
qDebug() << " details.newCubeClamped:" << details.newCubeClamped;
|
||||||
qDebug() << " _lookingCount:" << _lookingCount;
|
qDebug() << " _lookingCount:" << _lookingCount;
|
||||||
|
@ -130,17 +123,14 @@ bool MovingEntitiesOperator::shouldRecurseSubTree(OctreeElement* element) {
|
||||||
qDebug() << " element:" << element->getAACube();
|
qDebug() << " element:" << element->getAACube();
|
||||||
qDebug() << " details.entity:" << details.entity->getEntityItemID();
|
qDebug() << " details.entity:" << details.entity->getEntityItemID();
|
||||||
qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube;
|
qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube;
|
||||||
qDebug() << " details.oldCube:" << details.oldCube;
|
|
||||||
qDebug() << " details.newCube:" << details.newCube;
|
qDebug() << " details.newCube:" << details.newCube;
|
||||||
qDebug() << " details.newCubeClamped:" << details.newCubeClamped;
|
qDebug() << " details.newCubeClamped:" << details.newCubeClamped;
|
||||||
qDebug() << " elementCube.contains(details.oldCube)" << elementCube.contains(details.oldCube);
|
|
||||||
qDebug() << " elementCube.contains(details.newCube)" << elementCube.contains(details.newCube);
|
qDebug() << " elementCube.contains(details.newCube)" << elementCube.contains(details.newCube);
|
||||||
qDebug() << " elementCube.contains(details.oldCubeClamped)" << elementCube.contains(details.oldCubeClamped);
|
|
||||||
qDebug() << " elementCube.contains(details.newCubeClamped)" << elementCube.contains(details.newCubeClamped);
|
qDebug() << " elementCube.contains(details.newCubeClamped)" << elementCube.contains(details.newCubeClamped);
|
||||||
qDebug() << "--------------------------------------------------------------------------";
|
qDebug() << "--------------------------------------------------------------------------";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elementCube.contains(details.oldCubeClamped) || elementCube.contains(details.newCubeClamped)) {
|
if (elementCube.contains(details.oldContainingElementCube) || elementCube.contains(details.newCubeClamped)) {
|
||||||
containsEntity = true;
|
containsEntity = true;
|
||||||
break; // if it contains at least one, we're good to go
|
break; // if it contains at least one, we're good to go
|
||||||
}
|
}
|
||||||
|
@ -179,7 +169,6 @@ bool MovingEntitiesOperator::preRecursion(OctreeElement* element) {
|
||||||
qDebug() << " details.entity:" << details.entity->getEntityItemID();
|
qDebug() << " details.entity:" << details.entity->getEntityItemID();
|
||||||
qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube;
|
qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube;
|
||||||
qDebug() << " entityTreeElement:" << entityTreeElement;
|
qDebug() << " entityTreeElement:" << entityTreeElement;
|
||||||
qDebug() << " details.oldCube:" << details.oldCube;
|
|
||||||
qDebug() << " details.newCube:" << details.newCube;
|
qDebug() << " details.newCube:" << details.newCube;
|
||||||
qDebug() << " details.newCubeClamped:" << details.newCubeClamped;
|
qDebug() << " details.newCubeClamped:" << details.newCubeClamped;
|
||||||
qDebug() << " _lookingCount:" << _lookingCount;
|
qDebug() << " _lookingCount:" << _lookingCount;
|
||||||
|
@ -291,9 +280,3 @@ OctreeElement* MovingEntitiesOperator::possiblyCreateChildAt(OctreeElement* elem
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MovingEntitiesOperator::finish() {
|
|
||||||
foreach(const EntityToMoveDetails& details, _entitiesToMove) {
|
|
||||||
details.entity->setOldMaximumAACube(details.newCube);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ public:
|
||||||
EntityItem* entity;
|
EntityItem* entity;
|
||||||
AACube oldCube;
|
AACube oldCube;
|
||||||
AACube newCube;
|
AACube newCube;
|
||||||
AABox oldCubeClamped;
|
|
||||||
AABox newCubeClamped;
|
AABox newCubeClamped;
|
||||||
EntityTreeElement* oldContainingElement;
|
EntityTreeElement* oldContainingElement;
|
||||||
AACube oldContainingElementCube;
|
AACube oldContainingElementCube;
|
||||||
|
@ -43,7 +42,6 @@ public:
|
||||||
virtual bool postRecursion(OctreeElement* element);
|
virtual bool postRecursion(OctreeElement* element);
|
||||||
virtual OctreeElement* possiblyCreateChildAt(OctreeElement* element, int childIndex);
|
virtual OctreeElement* possiblyCreateChildAt(OctreeElement* element, int childIndex);
|
||||||
bool hasMovingEntities() const { return _entitiesToMove.size() > 0; }
|
bool hasMovingEntities() const { return _entitiesToMove.size() > 0; }
|
||||||
void finish();
|
|
||||||
private:
|
private:
|
||||||
EntityTree* _tree;
|
EntityTree* _tree;
|
||||||
QSet<EntityToMoveDetails> _entitiesToMove;
|
QSet<EntityToMoveDetails> _entitiesToMove;
|
||||||
|
|
|
@ -1520,7 +1520,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::string whatisthat = subobject.name;
|
std::string whatisthat = subobject.name;
|
||||||
if (whatisthat == "WTF") {
|
if (whatisthat == "Shape") {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "MetavoxelMessages.h"
|
#include "MetavoxelMessages.h"
|
||||||
|
|
||||||
// in sequencer parlance, a "packet" may consist of multiple datagrams. clarify when we refer to actual datagrams
|
// in sequencer parlance, a "packet" may consist of multiple datagrams. clarify when we refer to actual datagrams
|
||||||
const int MAX_DATAGRAM_SIZE = 1450;
|
const int MAX_DATAGRAM_SIZE = MAX_PACKET_SIZE;
|
||||||
|
|
||||||
const int DEFAULT_MAX_PACKET_SIZE = 3000;
|
const int DEFAULT_MAX_PACKET_SIZE = 3000;
|
||||||
|
|
||||||
|
@ -45,7 +45,8 @@ DatagramSequencer::DatagramSequencer(const QByteArray& datagramHeader, QObject*
|
||||||
_packetsToWrite(0.0f),
|
_packetsToWrite(0.0f),
|
||||||
_slowStartThreshold(DEFAULT_SLOW_START_THRESHOLD),
|
_slowStartThreshold(DEFAULT_SLOW_START_THRESHOLD),
|
||||||
_packetRateIncreasePacketNumber(0),
|
_packetRateIncreasePacketNumber(0),
|
||||||
_packetRateDecreasePacketNumber(0) {
|
_packetRateDecreasePacketNumber(0),
|
||||||
|
_packetDropCount(0) {
|
||||||
|
|
||||||
_outgoingPacketStream.setByteOrder(QDataStream::LittleEndian);
|
_outgoingPacketStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
_incomingDatagramStream.setByteOrder(QDataStream::LittleEndian);
|
_incomingDatagramStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
@ -348,11 +349,18 @@ void DatagramSequencer::sendRecordLost(const SendRecord& record) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// halve the rate and remember as threshold
|
// if we've lost three in a row, halve the rate and remember as threshold
|
||||||
if (record.packetNumber >= _packetRateDecreasePacketNumber) {
|
if (_packetDropCount == 0 || record.packetNumber == _lastPacketDropped + 1) {
|
||||||
_packetsPerGroup = qMax(_packetsPerGroup * 0.5f, 1.0f);
|
_packetDropCount++;
|
||||||
_slowStartThreshold = _packetsPerGroup;
|
_lastPacketDropped = record.packetNumber;
|
||||||
_packetRateDecreasePacketNumber = _outgoingPacketNumber + 1;
|
const int CONSECUTIVE_DROPS_BEFORE_REDUCTION = 3;
|
||||||
|
if (_packetDropCount >= CONSECUTIVE_DROPS_BEFORE_REDUCTION && record.packetNumber >= _packetRateDecreasePacketNumber) {
|
||||||
|
_packetsPerGroup = qMax(_packetsPerGroup * 0.5f, 1.0f);
|
||||||
|
_slowStartThreshold = _packetsPerGroup;
|
||||||
|
_packetRateDecreasePacketNumber = _outgoingPacketNumber + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_packetDropCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -238,6 +238,8 @@ private:
|
||||||
float _slowStartThreshold;
|
float _slowStartThreshold;
|
||||||
int _packetRateIncreasePacketNumber;
|
int _packetRateIncreasePacketNumber;
|
||||||
int _packetRateDecreasePacketNumber;
|
int _packetRateDecreasePacketNumber;
|
||||||
|
int _packetDropCount;
|
||||||
|
int _lastPacketDropped;
|
||||||
|
|
||||||
QHash<int, ReliableChannel*> _reliableOutputChannels;
|
QHash<int, ReliableChannel*> _reliableOutputChannels;
|
||||||
QHash<int, ReliableChannel*> _reliableInputChannels;
|
QHash<int, ReliableChannel*> _reliableInputChannels;
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
#include "DomainHandler.h"
|
#include "DomainHandler.h"
|
||||||
#include "Node.h"
|
#include "Node.h"
|
||||||
|
|
||||||
const int MAX_PACKET_SIZE = 1500;
|
const int MAX_PACKET_SIZE = 1450;
|
||||||
|
|
||||||
const quint64 NODE_SILENCE_THRESHOLD_MSECS = 2 * 1000;
|
const quint64 NODE_SILENCE_THRESHOLD_MSECS = 2 * 1000;
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,9 @@ bool ReceivedPacketProcessor::process() {
|
||||||
NetworkPacket& packet = _packets.front(); // get the oldest packet
|
NetworkPacket& packet = _packets.front(); // get the oldest packet
|
||||||
NetworkPacket temporary = packet; // make a copy of the packet in case the vector is resized on us
|
NetworkPacket temporary = packet; // make a copy of the packet in case the vector is resized on us
|
||||||
_packets.erase(_packets.begin()); // remove the oldest packet
|
_packets.erase(_packets.begin()); // remove the oldest packet
|
||||||
_nodePacketCounts[temporary.getNode()->getUUID()]--;
|
if (!temporary.getNode().isNull()) {
|
||||||
|
_nodePacketCounts[temporary.getNode()->getUUID()]--;
|
||||||
|
}
|
||||||
unlock(); // let others add to the packets
|
unlock(); // let others add to the packets
|
||||||
processPacket(temporary.getNode(), temporary.getByteArray()); // process our temporary copy
|
processPacket(temporary.getNode(), temporary.getByteArray()); // process our temporary copy
|
||||||
midProcess();
|
midProcess();
|
||||||
|
|
Loading…
Reference in a new issue