mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 04:44:11 +02:00
Merge remote-tracking branch 'upstream/master' into oculus_old_renderer
This commit is contained in:
commit
961173ede6
65 changed files with 3676 additions and 755 deletions
|
@ -37,7 +37,7 @@ macro(COPY_DLLS_BESIDE_WINDOWS_EXECUTABLE)
|
|||
add_custom_command(
|
||||
TARGET ${TARGET_NAME}
|
||||
POST_BUILD
|
||||
COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} --no-libraries $<TARGET_FILE:${TARGET_NAME}>"
|
||||
COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} $<TARGET_FILE:${TARGET_NAME}>"
|
||||
)
|
||||
endif ()
|
||||
endmacro()
|
|
@ -48,7 +48,7 @@ var rightHandEntity = false;
|
|||
var newSound = SoundCache.getSound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw");
|
||||
var catchSound = SoundCache.getSound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw");
|
||||
var throwSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Switches%20and%20sliders/slider%20-%20whoosh1.raw");
|
||||
var targetRadius = 1.0;
|
||||
var targetRadius = 0.25;
|
||||
|
||||
|
||||
var wantDebugging = false;
|
||||
|
@ -120,30 +120,33 @@ function checkControllerSide(whichSide) {
|
|||
var closestEntity = Entities.findClosestEntity(palmPosition, targetRadius);
|
||||
|
||||
if (closestEntity.isKnownID) {
|
||||
var foundProperties = Entities.getEntityProperties(closestEntity);
|
||||
if (Vec3.length(foundProperties.velocity) > 0.0) {
|
||||
|
||||
debugPrint(handMessage + " HAND- CAUGHT SOMETHING!!");
|
||||
debugPrint(handMessage + " - Catching a moving object!");
|
||||
|
||||
if (whichSide == LEFT_PALM) {
|
||||
leftBallAlreadyInHand = true;
|
||||
leftHandEntity = closestEntity;
|
||||
} else {
|
||||
rightBallAlreadyInHand = true;
|
||||
rightHandEntity = closestEntity;
|
||||
if (whichSide == LEFT_PALM) {
|
||||
leftBallAlreadyInHand = true;
|
||||
leftHandEntity = closestEntity;
|
||||
} else {
|
||||
rightBallAlreadyInHand = true;
|
||||
rightHandEntity = closestEntity;
|
||||
}
|
||||
var ballPosition = getBallHoldPosition(whichSide);
|
||||
var properties = { position: { x: ballPosition.x,
|
||||
y: ballPosition.y,
|
||||
z: ballPosition.z },
|
||||
rotation: palmRotation,
|
||||
color: HELD_COLOR,
|
||||
velocity : { x: 0, y: 0, z: 0},
|
||||
gravity: { x: 0, y: 0, z: 0}
|
||||
};
|
||||
Entities.editEntity(closestEntity, properties);
|
||||
|
||||
Audio.playSound(catchSound, { position: ballPosition });
|
||||
|
||||
return; // exit early
|
||||
}
|
||||
var ballPosition = getBallHoldPosition(whichSide);
|
||||
var properties = { position: { x: ballPosition.x,
|
||||
y: ballPosition.y,
|
||||
z: ballPosition.z },
|
||||
rotation: palmRotation,
|
||||
color: HELD_COLOR,
|
||||
velocity : { x: 0, y: 0, z: 0},
|
||||
gravity: { x: 0, y: 0, z: 0}
|
||||
};
|
||||
Entities.editEntity(closestEntity, properties);
|
||||
|
||||
Audio.playSound(catchSound, { position: ballPosition });
|
||||
|
||||
return; // exit early
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ keyboard.onKeyRelease = function(event) {
|
|||
|
||||
var textLines = textText.split("\n");
|
||||
var maxLineWidth = Overlays.textSize(textSizeMeasureOverlay, textText).width;
|
||||
var usernameLine = "--" + GlobalServices.myUsername;
|
||||
var usernameLine = "--" + GlobalServices.username;
|
||||
var usernameWidth = Overlays.textSize(textSizeMeasureOverlay, usernameLine).width;
|
||||
if (maxLineWidth < usernameWidth) {
|
||||
maxLineWidth = usernameWidth;
|
||||
|
|
|
@ -699,7 +699,7 @@ function setupModelMenus() {
|
|||
Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" });
|
||||
Menu.addMenuItem({ menuName: "File", menuItemName: "Export Entities", shortcutKey: "CTRL+META+E", afterItem: "Models" });
|
||||
Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities", shortcutKey: "CTRL+META+I", afterItem: "Export Entities" });
|
||||
|
||||
Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities from URL", shortcutKey: "CTRL+META+U", afterItem: "Import Entities" });
|
||||
|
||||
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_AUTO_FOCUS_ON_SELECT, afterItem: MENU_INSPECT_TOOL_ENABLED,
|
||||
isCheckable: true, isChecked: Settings.getValue(SETTING_AUTO_FOCUS_ON_SELECT) == "true" });
|
||||
|
@ -726,6 +726,7 @@ function cleanupModelMenus() {
|
|||
Menu.removeSeparator("File", "Models");
|
||||
Menu.removeMenuItem("File", "Export Entities");
|
||||
Menu.removeMenuItem("File", "Import Entities");
|
||||
Menu.removeMenuItem("File", "Import Entities from URL");
|
||||
|
||||
Menu.removeMenuItem("View", MENU_INSPECT_TOOL_ENABLED);
|
||||
Menu.removeMenuItem("View", MENU_AUTO_FOCUS_ON_SELECT);
|
||||
|
@ -795,10 +796,17 @@ function handeMenuEvent(menuItem) {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (menuItem == "Import Entities") {
|
||||
var filename = Window.browse("Select models to import", "", "*.svo")
|
||||
if (filename) {
|
||||
var success = Clipboard.importEntities(filename);
|
||||
} else if (menuItem == "Import Entities" || menuItem == "Import Entities from URL") {
|
||||
|
||||
var importURL;
|
||||
if (menuItem == "Import Entities") {
|
||||
importURL = Window.browse("Select models to import", "", "*.svo");
|
||||
} else {
|
||||
importURL = Window.prompt("URL of SVO to import", "");
|
||||
}
|
||||
|
||||
if (importURL) {
|
||||
var success = Clipboard.importEntities(importURL);
|
||||
|
||||
if (success) {
|
||||
var distance = cameraManager.enabled ? cameraManager.zoomDistance : DEFAULT_ENTITY_DRAG_DROP_DISTANCE;
|
||||
|
|
|
@ -38,6 +38,13 @@ function touchUpdateEvent(event) {
|
|||
if (wantDebugging) {
|
||||
print("touchUpdateEvent event.x,y=" + event.x + ", " + event.y);
|
||||
}
|
||||
|
||||
if (!startedTouching) {
|
||||
// handle Qt 5.4.x bug where we get touch update without a touch begin event
|
||||
startedTouching = true;
|
||||
lastX = event.x;
|
||||
lastY = event.y;
|
||||
}
|
||||
|
||||
var MOUSE_YAW_SCALE = -0.25;
|
||||
var MOUSE_PITCH_SCALE = -12.5;
|
||||
|
|
|
@ -20,11 +20,11 @@ var trailingLoudness = 0.0;
|
|||
var soundClip = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Tabla+Loops/Tabla1.wav");
|
||||
|
||||
var properties = {
|
||||
type: "Box",
|
||||
position: orbitCenter,
|
||||
dimensions: { x: 0.25, y: 0.25, z: 0.25 },
|
||||
color: { red: 100, green: 0, blue : 0 }
|
||||
};
|
||||
type: "Box",
|
||||
position: orbitCenter,
|
||||
dimensions: { x: 0.25, y: 0.25, z: 0.25 },
|
||||
color: { red: 100, green: 0, blue : 0 }
|
||||
};
|
||||
|
||||
var objectId = Entities.addEntity(properties);
|
||||
var sound = Audio.playSound(soundClip, { position: orbitCenter, loop: true, volume: 0.5 });
|
||||
|
@ -34,7 +34,7 @@ function update(deltaTime) {
|
|||
currentPosition = { x: orbitCenter.x + Math.cos(time * SPEED) * RADIUS, y: orbitCenter.y, z: orbitCenter.z + Math.sin(time * SPEED) * RADIUS };
|
||||
trailingLoudness = 0.9 * trailingLoudness + 0.1 * sound.loudness;
|
||||
Entities.editEntity( objectId, { position: currentPosition, color: { red: Math.min(trailingLoudness * 2000, 255), green: 0, blue: 0 } } );
|
||||
sound.setOptions({ position: currentPosition });
|
||||
sound.options = { position: currentPosition };
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
|
||||
#include "Application.h"
|
||||
#include "AudioClient.h"
|
||||
#include "DiscoverabilityManager.h"
|
||||
#include "InterfaceVersion.h"
|
||||
#include "LODManager.h"
|
||||
#include "Menu.h"
|
||||
|
@ -246,6 +247,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
auto speechRecognizer = DependencyManager::set<SpeechRecognizer>();
|
||||
#endif
|
||||
auto discoverabilityManager = DependencyManager::set<DiscoverabilityManager>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -367,11 +369,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
connect(&domainHandler, &DomainHandler::hostnameChanged,
|
||||
DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
|
||||
|
||||
// update our location every 5 seconds in the data-server, assuming that we are authenticated with one
|
||||
// update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one
|
||||
const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000;
|
||||
|
||||
locationUpdateTimer = new QTimer(this);
|
||||
connect(locationUpdateTimer, &QTimer::timeout, this, &Application::updateLocationInServer);
|
||||
auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>();
|
||||
connect(locationUpdateTimer, &QTimer::timeout, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation);
|
||||
locationUpdateTimer->start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS);
|
||||
|
||||
connect(nodeList.data(), &NodeList::nodeAdded, this, &Application::nodeAdded);
|
||||
|
@ -459,6 +462,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
// enable mouse tracking; otherwise, we only get drag events
|
||||
_glWidget->setMouseTracking(true);
|
||||
|
||||
_fullscreenMenuWidget->setParent(_glWidget);
|
||||
_menuBarHeight = Menu::getInstance()->height();
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) {
|
||||
setFullscreen(true); // Initialize menu bar show/hide
|
||||
}
|
||||
|
||||
_toolWindow = new ToolWindow();
|
||||
_toolWindow->setWindowFlags(_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
_toolWindow->setWindowTitle("Tools");
|
||||
|
@ -599,7 +608,10 @@ Application::~Application() {
|
|||
|
||||
_myAvatar = NULL;
|
||||
|
||||
ModelEntityItem::cleanupLoadedAnimations() ;
|
||||
ModelEntityItem::cleanupLoadedAnimations();
|
||||
|
||||
// stop the glWidget frame timer so it doesn't call paintGL
|
||||
_glWidget->stopFrameTimer();
|
||||
|
||||
DependencyManager::destroy<AnimationCache>();
|
||||
DependencyManager::destroy<TextureCache>();
|
||||
|
@ -611,7 +623,7 @@ Application::~Application() {
|
|||
}
|
||||
|
||||
void Application::initializeGL() {
|
||||
qDebug( "Created Display Window.");
|
||||
qDebug() << "Created Display Window.";
|
||||
|
||||
// initialize glut for shape drawing; Qt apparently initializes it on OS X
|
||||
#ifndef __APPLE__
|
||||
|
@ -1262,6 +1274,18 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)
|
||||
&& !Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
|
||||
// Show/hide menu bar in fullscreen
|
||||
if (event->globalY() > _menuBarHeight) {
|
||||
_fullscreenMenuWidget->setFixedHeight(0);
|
||||
Menu::getInstance()->setFixedHeight(0);
|
||||
} else {
|
||||
_fullscreenMenuWidget->setFixedHeight(_menuBarHeight);
|
||||
Menu::getInstance()->setFixedHeight(_menuBarHeight);
|
||||
}
|
||||
}
|
||||
|
||||
_entities.mouseMoveEvent(event, deviceID);
|
||||
|
||||
_controllerScriptingInterface.emitMouseMoveEvent(event, deviceID); // send events to any registered scripts
|
||||
|
@ -1527,14 +1551,47 @@ void Application::setFullscreen(bool fullscreen) {
|
|||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
|
||||
if (fullscreen) {
|
||||
// Menu show() after hide() doesn't work with Rift VR display so set height instead.
|
||||
// Menu hide() disables menu commands, and show() after hide() doesn't work with Rift VR display.
|
||||
// So set height instead.
|
||||
_window->menuBar()->setMaximumHeight(0);
|
||||
} else {
|
||||
_window->menuBar()->setMaximumHeight(QWIDGETSIZE_MAX);
|
||||
}
|
||||
} else {
|
||||
if (fullscreen) {
|
||||
// Move menu to a QWidget floating above _glWidget so that show/hide doesn't adjust viewport.
|
||||
_menuBarHeight = Menu::getInstance()->height();
|
||||
Menu::getInstance()->setParent(_fullscreenMenuWidget);
|
||||
Menu::getInstance()->setFixedWidth(_window->windowHandle()->screen()->size().width());
|
||||
_fullscreenMenuWidget->show();
|
||||
} else {
|
||||
// Restore menu to being part of MainWindow.
|
||||
_fullscreenMenuWidget->hide();
|
||||
_window->setMenuBar(Menu::getInstance());
|
||||
_window->menuBar()->setMaximumHeight(QWIDGETSIZE_MAX);
|
||||
}
|
||||
}
|
||||
_window->setWindowState(fullscreen ? (_window->windowState() | Qt::WindowFullScreen) :
|
||||
(_window->windowState() & ~Qt::WindowFullScreen));
|
||||
|
||||
// Work around Qt bug that prevents floating menus being shown when in fullscreen mode.
|
||||
// https://bugreports.qt.io/browse/QTBUG-41883
|
||||
// Known issue: Top-level menu items don't highlight when cursor hovers. This is probably a side-effect of the work-around.
|
||||
// TODO: Remove this work-around once the bug has been fixed and restore the following lines.
|
||||
//_window->setWindowState(fullscreen ? (_window->windowState() | Qt::WindowFullScreen) :
|
||||
// (_window->windowState() & ~Qt::WindowFullScreen));
|
||||
_window->hide();
|
||||
if (fullscreen) {
|
||||
_window->setWindowState(_window->windowState() | Qt::WindowFullScreen);
|
||||
// The next line produces the following warning in the log:
|
||||
// [WARNING][03 / 06 12:17 : 58] QWidget::setMinimumSize: (/ MainWindow) Negative sizes
|
||||
// (0, -1) are not possible
|
||||
// This is better than the alternative which is to have the window slightly less than fullscreen with a visible line
|
||||
// of pixels for the remainder of the screen.
|
||||
_window->setContentsMargins(0, 0, 0, -1);
|
||||
} else {
|
||||
_window->setWindowState(_window->windowState() & ~Qt::WindowFullScreen);
|
||||
_window->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
if (!_aboutToQuit) {
|
||||
_window->show();
|
||||
}
|
||||
|
@ -1718,9 +1775,17 @@ void Application::saveSettings() {
|
|||
_myAvatar->saveData();
|
||||
}
|
||||
|
||||
bool Application::importEntities(const QString& filename) {
|
||||
bool Application::importEntities(const QString& urlOrFilename) {
|
||||
_entityClipboard.eraseAllOctreeElements();
|
||||
bool success = _entityClipboard.readFromSVOFile(filename.toLocal8Bit().constData());
|
||||
|
||||
QUrl url(urlOrFilename);
|
||||
|
||||
// if the URL appears to be invalid or relative, then it is probably a local file
|
||||
if (!url.isValid() || url.isRelative()) {
|
||||
url = QUrl::fromLocalFile(urlOrFilename);
|
||||
}
|
||||
|
||||
bool success = _entityClipboard.readFromSVOURL(url.toString());
|
||||
if (success) {
|
||||
_entityClipboard.reaverageOctreeElements();
|
||||
}
|
||||
|
@ -2876,6 +2941,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
|||
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity());
|
||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalAtmosphere(skyStage->getAtmosphere());
|
||||
|
||||
PROFILE_RANGE("DeferredLighting");
|
||||
PerformanceTimer perfTimer("lighting");
|
||||
|
@ -3191,45 +3257,6 @@ void Application::updateWindowTitle(){
|
|||
_window->setWindowTitle(title);
|
||||
}
|
||||
|
||||
void Application::updateLocationInServer() {
|
||||
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
|
||||
if (accountManager.isLoggedIn() && domainHandler.isConnected()
|
||||
&& (!addressManager->getRootPlaceID().isNull() || !domainHandler.getUUID().isNull())) {
|
||||
|
||||
// construct a QJsonObject given the user's current address information
|
||||
QJsonObject rootObject;
|
||||
|
||||
QJsonObject locationObject;
|
||||
|
||||
QString pathString = addressManager->currentPath();
|
||||
|
||||
const QString LOCATION_KEY_IN_ROOT = "location";
|
||||
|
||||
const QString PATH_KEY_IN_LOCATION = "path";
|
||||
locationObject.insert(PATH_KEY_IN_LOCATION, pathString);
|
||||
|
||||
if (!addressManager->getRootPlaceID().isNull()) {
|
||||
const QString PLACE_ID_KEY_IN_LOCATION = "place_id";
|
||||
locationObject.insert(PLACE_ID_KEY_IN_LOCATION,
|
||||
uuidStringWithoutCurlyBraces(addressManager->getRootPlaceID()));
|
||||
|
||||
} else {
|
||||
const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id";
|
||||
locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION,
|
||||
uuidStringWithoutCurlyBraces(domainHandler.getUUID()));
|
||||
}
|
||||
|
||||
rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject);
|
||||
|
||||
accountManager.authenticatedRequest("/api/v1/user/location", QNetworkAccessManager::PutOperation,
|
||||
JSONCallbackParameters(), QJsonDocument(rootObject).toJson());
|
||||
}
|
||||
}
|
||||
|
||||
void Application::clearDomainOctreeDetails() {
|
||||
qDebug() << "Clearing domain octree details...";
|
||||
// reset the environment so that we don't erroneously end up with multiple
|
||||
|
|
|
@ -318,7 +318,6 @@ signals:
|
|||
public slots:
|
||||
void domainChanged(const QString& domainHostname);
|
||||
void updateWindowTitle();
|
||||
void updateLocationInServer();
|
||||
void nodeAdded(SharedNodePointer node);
|
||||
void nodeKilled(SharedNodePointer node);
|
||||
void packetSent(quint64 length);
|
||||
|
@ -326,7 +325,7 @@ public slots:
|
|||
QVector<EntityItemID> pasteEntities(float x, float y, float z);
|
||||
bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs);
|
||||
bool exportEntities(const QString& filename, float x, float y, float z, float scale);
|
||||
bool importEntities(const QString& filename);
|
||||
bool importEntities(const QString& url);
|
||||
|
||||
void setLowVelocityFilter(bool lowVelocityFilter);
|
||||
void loadDialog();
|
||||
|
@ -587,6 +586,9 @@ private:
|
|||
GLCanvas* _glWidget = new GLCanvas(); // our GLCanvas has a couple extra features
|
||||
|
||||
void checkSkeleton();
|
||||
|
||||
QWidget* _fullscreenMenuWidget = new QWidget();
|
||||
int _menuBarHeight;
|
||||
};
|
||||
|
||||
#endif // hifi_Application_h
|
||||
|
|
88
interface/src/DiscoverabilityManager.cpp
Normal file
88
interface/src/DiscoverabilityManager.cpp
Normal file
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// DiscoverabilityManager.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Stephen Birarda on 2015-03-09.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QtCore/QJsonDocument>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
#include <DomainHandler.h>
|
||||
#include <NodeList.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#include "DiscoverabilityManager.h"
|
||||
|
||||
const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::All;
|
||||
|
||||
DiscoverabilityManager::DiscoverabilityManager() :
|
||||
_mode("discoverabilityMode", DEFAULT_DISCOVERABILITY_MODE)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const QString API_USER_LOCATION_PATH = "/api/v1/user/location";
|
||||
|
||||
void DiscoverabilityManager::updateLocation() {
|
||||
if (_mode.get() != Discoverability::None) {
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
|
||||
if (accountManager.isLoggedIn() && domainHandler.isConnected()
|
||||
&& (!addressManager->getRootPlaceID().isNull() || !domainHandler.getUUID().isNull())) {
|
||||
|
||||
// construct a QJsonObject given the user's current address information
|
||||
QJsonObject rootObject;
|
||||
|
||||
QJsonObject locationObject;
|
||||
|
||||
QString pathString = addressManager->currentPath();
|
||||
|
||||
const QString LOCATION_KEY_IN_ROOT = "location";
|
||||
|
||||
const QString PATH_KEY_IN_LOCATION = "path";
|
||||
locationObject.insert(PATH_KEY_IN_LOCATION, pathString);
|
||||
|
||||
if (!addressManager->getRootPlaceID().isNull()) {
|
||||
const QString PLACE_ID_KEY_IN_LOCATION = "place_id";
|
||||
locationObject.insert(PLACE_ID_KEY_IN_LOCATION,
|
||||
uuidStringWithoutCurlyBraces(addressManager->getRootPlaceID()));
|
||||
|
||||
} else {
|
||||
const QString DOMAIN_ID_KEY_IN_LOCATION = "domain_id";
|
||||
locationObject.insert(DOMAIN_ID_KEY_IN_LOCATION,
|
||||
uuidStringWithoutCurlyBraces(domainHandler.getUUID()));
|
||||
}
|
||||
|
||||
rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject);
|
||||
|
||||
accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::PutOperation,
|
||||
JSONCallbackParameters(), QJsonDocument(rootObject).toJson());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DiscoverabilityManager::removeLocation() {
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::DeleteOperation);
|
||||
}
|
||||
|
||||
void DiscoverabilityManager::setDiscoverabilityMode(Discoverability::Mode discoverabilityMode) {
|
||||
if (static_cast<Discoverability::Mode>(_mode.get()) != discoverabilityMode) {
|
||||
|
||||
// update the setting to the new value
|
||||
_mode.set(static_cast<int>(discoverabilityMode));
|
||||
|
||||
if (static_cast<int>(_mode.get()) == Discoverability::None) {
|
||||
// if we just got set to no discoverability, make sure that we delete our location in DB
|
||||
removeLocation();
|
||||
}
|
||||
}
|
||||
}
|
45
interface/src/DiscoverabilityManager.h
Normal file
45
interface/src/DiscoverabilityManager.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// DiscoverabilityManager.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Stephen Birarda on 2015-03-09.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_DiscoverabilityManager_h
|
||||
#define hifi_DiscoverabilityManager_h
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <SettingHandle.h>
|
||||
|
||||
namespace Discoverability {
|
||||
enum Mode {
|
||||
None,
|
||||
Friends,
|
||||
All
|
||||
};
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(Discoverability::Mode);
|
||||
|
||||
class DiscoverabilityManager : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public slots:
|
||||
void updateLocation();
|
||||
void removeLocation();
|
||||
|
||||
Discoverability::Mode getDiscoverabilityMode() { return static_cast<Discoverability::Mode>(_mode.get()); }
|
||||
void setDiscoverabilityMode(Discoverability::Mode discoverabilityMode);
|
||||
|
||||
private:
|
||||
DiscoverabilityManager();
|
||||
|
||||
Setting::Handle<int> _mode;
|
||||
};
|
||||
|
||||
#endif // hifi_DiscoverabilityManager_h
|
|
@ -31,6 +31,10 @@ GLCanvas::GLCanvas() : QGLWidget(QGL::NoDepthBuffer | QGL::NoStencilBuffer),
|
|||
#endif
|
||||
}
|
||||
|
||||
void GLCanvas::stopFrameTimer() {
|
||||
_frameTimer.stop();
|
||||
}
|
||||
|
||||
bool GLCanvas::isThrottleRendering() const {
|
||||
return _throttleRendering || Application::getInstance()->getWindow()->isMinimized();
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ class GLCanvas : public QGLWidget {
|
|||
|
||||
public:
|
||||
GLCanvas();
|
||||
|
||||
void stopFrameTimer();
|
||||
|
||||
bool isThrottleRendering() const;
|
||||
|
||||
|
|
|
@ -338,9 +338,6 @@ void ModelUploader::populateBasicMapping(QVariantHash& mapping, QString filename
|
|||
geometry.blendshapeChannelNames.contains("Blink_Right") &&
|
||||
geometry.blendshapeChannelNames.contains("Squint_Right"));
|
||||
|
||||
qDebug() << "likelyMixamoFile:" << likelyMixamoFile;
|
||||
qDebug() << "geometry.blendshapeChannelNames:" << geometry.blendshapeChannelNames;
|
||||
|
||||
if (!mapping.contains(BLENDSHAPE_FIELD) && likelyMixamoFile) {
|
||||
QVariantHash blendshapes;
|
||||
blendshapes.insertMulti("BrowsD_L", QVariantList() << "BrowsDown_Left" << 1.0);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "AccountManager.h"
|
||||
#include "Application.h"
|
||||
#include "DiscoverabilityManager.h"
|
||||
#include "ResourceCache.h"
|
||||
|
||||
#include "GlobalServicesScriptingInterface.h"
|
||||
|
@ -36,7 +37,7 @@ GlobalServicesScriptingInterface* GlobalServicesScriptingInterface::getInstance(
|
|||
return &sharedInstance;
|
||||
}
|
||||
|
||||
QString GlobalServicesScriptingInterface::getMyUsername() {
|
||||
const QString& GlobalServicesScriptingInterface::getUsername() const {
|
||||
return AccountManager::getInstance().getAccountInfo().getUsername();
|
||||
}
|
||||
|
||||
|
@ -44,6 +45,32 @@ void GlobalServicesScriptingInterface::loggedOut() {
|
|||
emit GlobalServicesScriptingInterface::disconnected(QString("logout"));
|
||||
}
|
||||
|
||||
QString GlobalServicesScriptingInterface::getFindableBy() const {
|
||||
auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>();
|
||||
|
||||
if (discoverabilityManager->getDiscoverabilityMode() == Discoverability::None) {
|
||||
return "none";
|
||||
} else if (discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends) {
|
||||
return "friends";
|
||||
} else {
|
||||
return "all";
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalServicesScriptingInterface::setFindableBy(const QString& discoverabilityMode) {
|
||||
auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>();
|
||||
|
||||
if (discoverabilityMode.toLower() == "none") {
|
||||
discoverabilityManager->setDiscoverabilityMode(Discoverability::None);
|
||||
} else if (discoverabilityMode.toLower() == "friends") {
|
||||
discoverabilityManager->setDiscoverabilityMode(Discoverability::Friends);
|
||||
} else if (discoverabilityMode.toLower() == "all") {
|
||||
discoverabilityManager->setDiscoverabilityMode(Discoverability::All);
|
||||
} else {
|
||||
qDebug() << "GlobalServices setFindableBy called with an unrecognized value. Did not change discoverability.";
|
||||
}
|
||||
}
|
||||
|
||||
DownloadInfoResult::DownloadInfoResult() :
|
||||
downloading(QList<float>()),
|
||||
pending(0.0f)
|
||||
|
|
|
@ -31,16 +31,16 @@ Q_DECLARE_METATYPE(DownloadInfoResult)
|
|||
QScriptValue DownloadInfoResultToScriptValue(QScriptEngine* engine, const DownloadInfoResult& result);
|
||||
void DownloadInfoResultFromScriptValue(const QScriptValue& object, DownloadInfoResult& result);
|
||||
|
||||
|
||||
class GlobalServicesScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString myUsername READ getMyUsername)
|
||||
GlobalServicesScriptingInterface();
|
||||
~GlobalServicesScriptingInterface();
|
||||
|
||||
Q_PROPERTY(QString username READ getUsername)
|
||||
Q_PROPERTY(QString findableBy READ getFindableBy WRITE setFindableBy)
|
||||
|
||||
public:
|
||||
static GlobalServicesScriptingInterface* getInstance();
|
||||
|
||||
QString getMyUsername();
|
||||
const QString& getUsername() const;
|
||||
|
||||
public slots:
|
||||
DownloadInfoResult getDownloadInfo();
|
||||
|
@ -49,16 +49,20 @@ public slots:
|
|||
private slots:
|
||||
void loggedOut();
|
||||
void checkDownloadInfo();
|
||||
|
||||
QString getFindableBy() const;
|
||||
void setFindableBy(const QString& discoverabilityMode);
|
||||
|
||||
signals:
|
||||
void connected();
|
||||
void disconnected(const QString& reason);
|
||||
void incomingMessage(const QString& username, const QString& message);
|
||||
void onlineUsersChanged(const QStringList& usernames);
|
||||
void myUsernameChanged(const QString& username);
|
||||
void downloadInfoChanged(DownloadInfoResult info);
|
||||
|
||||
private:
|
||||
GlobalServicesScriptingInterface();
|
||||
~GlobalServicesScriptingInterface();
|
||||
|
||||
bool _downloading;
|
||||
};
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ void LoginDialog::reset() {
|
|||
_ui->emailLineEdit->setFocus();
|
||||
_ui->logoLabel->setPixmap(QPixmap(PathUtils::resourcesPath() + "images/hifi-logo.svg"));
|
||||
_ui->loginButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/login.svg"));
|
||||
_ui->closeButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/close.svg"));
|
||||
_ui->infoLabel->setVisible(false);
|
||||
_ui->errorLabel->setVisible(false);
|
||||
|
||||
|
|
|
@ -320,6 +320,7 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
|
|||
#ifdef Q_OS_ANDROID
|
||||
adjustedAudioFormat.setSampleRate(FORTY_FOUR);
|
||||
#else
|
||||
|
||||
const int HALF_FORTY_FOUR = FORTY_FOUR / 2;
|
||||
|
||||
if (audioDevice.supportedSampleRates().contains(AudioConstants::SAMPLE_RATE * 2)) {
|
||||
|
@ -397,18 +398,24 @@ soxr_error_t possibleResampling(soxr_t resampler,
|
|||
numSourceSamples,
|
||||
sourceAudioFormat, destinationAudioFormat);
|
||||
|
||||
qDebug() << "resample from" << sourceAudioFormat << "to" << destinationAudioFormat
|
||||
<< "from" << numChannelCoversionSamples << "to" << numDestinationSamples;
|
||||
|
||||
resampleError = soxr_process(resampler,
|
||||
channelConversionSamples, numChannelCoversionSamples, NULL,
|
||||
destinationSamples, numDestinationSamples, NULL);
|
||||
|
||||
delete[] channelConversionSamples;
|
||||
} else {
|
||||
|
||||
unsigned int numAdjustedSourceSamples = numSourceSamples;
|
||||
unsigned int numAdjustedDestinationSamples = numDestinationSamples;
|
||||
|
||||
if (sourceAudioFormat.channelCount() == 2 && destinationAudioFormat.channelCount() == 2) {
|
||||
numAdjustedSourceSamples /= 2;
|
||||
numAdjustedDestinationSamples /= 2;
|
||||
}
|
||||
|
||||
resampleError = soxr_process(resampler,
|
||||
sourceSamples, numSourceSamples, NULL,
|
||||
destinationSamples, numDestinationSamples, NULL);
|
||||
sourceSamples, numAdjustedSourceSamples, NULL,
|
||||
destinationSamples, numAdjustedDestinationSamples, NULL);
|
||||
}
|
||||
|
||||
return resampleError;
|
||||
|
@ -429,9 +436,12 @@ soxr_t soxrResamplerFromInputFormatToOutputFormat(const QAudioFormat& sourceAudi
|
|||
// setup soxr_quality_spec_t for quality options
|
||||
soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0);
|
||||
|
||||
int channelCount = (sourceAudioFormat.channelCount() == 2 && destinationAudioFormat.channelCount() == 2)
|
||||
? 2 : 1;
|
||||
|
||||
soxr_t newResampler = soxr_create(sourceAudioFormat.sampleRate(),
|
||||
destinationAudioFormat.sampleRate(),
|
||||
1,
|
||||
channelCount,
|
||||
&soxrError, &inputToNetworkSpec, &qualitySpec, 0);
|
||||
|
||||
if (soxrError) {
|
||||
|
@ -1136,7 +1146,7 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice
|
|||
if (!outputDeviceInfo.isNull()) {
|
||||
qDebug() << "The audio output device " << outputDeviceInfo.deviceName() << "is available.";
|
||||
_outputAudioDeviceName = outputDeviceInfo.deviceName().trimmed();
|
||||
|
||||
|
||||
if (adjustedFormatForAudioDevice(outputDeviceInfo, _desiredOutputFormat, _outputFormat)) {
|
||||
qDebug() << "The format to be used for audio output is" << _outputFormat;
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ class AbstractAudioInterface;
|
|||
|
||||
class AudioInjector : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(AudioInjectorOptions options WRITE setOptions READ getOptions)
|
||||
public:
|
||||
AudioInjector(QObject* parent);
|
||||
AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions);
|
||||
|
@ -51,7 +53,9 @@ public slots:
|
|||
void triggerDeleteAfterFinish() { _shouldDeleteAfterFinish = true; }
|
||||
void stopAndDeleteLater();
|
||||
|
||||
void setOptions(AudioInjectorOptions& options) { _options = options; }
|
||||
const AudioInjectorOptions& getOptions() const { return _options; }
|
||||
void setOptions(const AudioInjectorOptions& options) { _options = options; }
|
||||
|
||||
void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; }
|
||||
float getLoudness() const { return _loudness; }
|
||||
bool isPlaying() const { return !_isFinished; }
|
||||
|
|
|
@ -94,30 +94,41 @@ void Sound::downloadFinished(QNetworkReply* reply) {
|
|||
|
||||
void Sound::downSample(const QByteArray& rawAudioByteArray) {
|
||||
// assume that this was a RAW file and is now an array of samples that are
|
||||
// signed, 16-bit, 48Khz, mono
|
||||
// signed, 16-bit, 48Khz
|
||||
|
||||
// we want to convert it to the format that the audio-mixer wants
|
||||
// which is signed, 16-bit, 24Khz, mono
|
||||
|
||||
_byteArray.resize(rawAudioByteArray.size() / 2);
|
||||
|
||||
// which is signed, 16-bit, 24Khz
|
||||
|
||||
int numSourceSamples = rawAudioByteArray.size() / sizeof(int16_t);
|
||||
|
||||
int numDestinationBytes = rawAudioByteArray.size() / 2;
|
||||
if (_isStereo && numSourceSamples % 4 != 0) {
|
||||
numDestinationBytes += 1;
|
||||
}
|
||||
|
||||
_byteArray.resize(numDestinationBytes);
|
||||
|
||||
|
||||
int16_t* sourceSamples = (int16_t*) rawAudioByteArray.data();
|
||||
int16_t* destinationSamples = (int16_t*) _byteArray.data();
|
||||
|
||||
|
||||
if (_isStereo) {
|
||||
for (int i = 0; i < numSourceSamples; i += 4) {
|
||||
destinationSamples[i / 2] = (sourceSamples[i] / 2) + (sourceSamples[i + 2] / 2);
|
||||
destinationSamples[(i / 2) + 1] = (sourceSamples[i + 1] / 2) + (sourceSamples[i + 3] / 2);
|
||||
if (i + 2 >= numSourceSamples) {
|
||||
destinationSamples[i / 2] = sourceSamples[i];
|
||||
destinationSamples[(i / 2) + 1] = sourceSamples[i + 1];
|
||||
} else {
|
||||
destinationSamples[i / 2] = (sourceSamples[i] + sourceSamples[i + 2]) / 2;
|
||||
destinationSamples[(i / 2) + 1] = (sourceSamples[i + 1] + sourceSamples[i + 3]) / 2;
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
for (int i = 1; i < numSourceSamples; i += 2) {
|
||||
if (i + 1 >= numSourceSamples) {
|
||||
destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] / 2) + (sourceSamples[i] / 2);
|
||||
destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] + sourceSamples[i]) / 2;
|
||||
} else {
|
||||
destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] / 4) + (sourceSamples[i] / 2)
|
||||
+ (sourceSamples[i + 1] / 4);
|
||||
destinationSamples[(i - 1) / 2] = ((sourceSamples[i - 1] + sourceSamples[i + 1]) / 4) + (sourceSamples[i] / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,10 +99,11 @@ void EntitySimulation::sortEntitiesThatMoved() {
|
|||
_mortalEntities.remove(entity);
|
||||
_updateableEntities.remove(entity);
|
||||
removeEntityInternal(entity);
|
||||
itemItr = _entitiesToBeSorted.erase(itemItr);
|
||||
} else {
|
||||
moveOperator.addEntityToMoveList(entity, newCube);
|
||||
++itemItr;
|
||||
}
|
||||
++itemItr;
|
||||
}
|
||||
if (moveOperator.hasMovingEntities()) {
|
||||
PerformanceTimer perfTimer("recurseTreeWithOperator");
|
||||
|
|
|
@ -25,7 +25,8 @@ Batch::Batch() :
|
|||
_buffers(),
|
||||
_textures(),
|
||||
_streamFormats(),
|
||||
_transforms()
|
||||
_transforms(),
|
||||
_pipelines()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -42,6 +43,7 @@ void Batch::clear() {
|
|||
_textures.clear();
|
||||
_streamFormats.clear();
|
||||
_transforms.clear();
|
||||
_pipelines.clear();
|
||||
}
|
||||
|
||||
uint32 Batch::cacheResource(Resource* res) {
|
||||
|
@ -159,6 +161,12 @@ void Batch::setProjectionTransform(const Mat4& proj) {
|
|||
_params.push_back(cacheData(sizeof(Mat4), &proj));
|
||||
}
|
||||
|
||||
void Batch::setPipeline(const PipelinePointer& pipeline) {
|
||||
ADD_COMMAND(setPipeline);
|
||||
|
||||
_params.push_back(_pipelines.cache(pipeline));
|
||||
}
|
||||
|
||||
void Batch::setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size) {
|
||||
ADD_COMMAND(setUniformBuffer);
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "Stream.h"
|
||||
#include "Texture.h"
|
||||
|
||||
#include "Pipeline.h"
|
||||
|
||||
#if defined(NSIGHT_FOUND)
|
||||
#include "nvToolsExt.h"
|
||||
class ProfileRange {
|
||||
|
@ -96,7 +98,9 @@ public:
|
|||
void setViewTransform(const Transform& view);
|
||||
void setProjectionTransform(const Mat4& proj);
|
||||
|
||||
// Shader Stage
|
||||
// Pipeline Stage
|
||||
void setPipeline(const PipelinePointer& pipeline);
|
||||
|
||||
void setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size);
|
||||
void setUniformBuffer(uint32 slot, const BufferView& view); // not a command, just a shortcut from a BufferView
|
||||
|
||||
|
@ -164,6 +168,7 @@ public:
|
|||
COMMAND_setViewTransform,
|
||||
COMMAND_setProjectionTransform,
|
||||
|
||||
COMMAND_setPipeline,
|
||||
COMMAND_setUniformBuffer,
|
||||
COMMAND_setUniformTexture,
|
||||
|
||||
|
@ -281,6 +286,7 @@ public:
|
|||
typedef Cache<TexturePointer>::Vector TextureCaches;
|
||||
typedef Cache<Stream::FormatPointer>::Vector StreamFormatCaches;
|
||||
typedef Cache<Transform>::Vector TransformCaches;
|
||||
typedef Cache<PipelinePointer>::Vector PipelineCaches;
|
||||
|
||||
typedef unsigned char Byte;
|
||||
typedef std::vector<Byte> Bytes;
|
||||
|
@ -320,6 +326,7 @@ public:
|
|||
TextureCaches _textures;
|
||||
StreamFormatCaches _streamFormats;
|
||||
TransformCaches _transforms;
|
||||
PipelineCaches _pipelines;
|
||||
|
||||
protected:
|
||||
};
|
||||
|
|
|
@ -10,3 +10,14 @@
|
|||
//
|
||||
#include "Context.h"
|
||||
|
||||
// this include should disappear! as soon as the gpu::Context is in place
|
||||
#include "GLBackend.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
|
||||
if (shader.isProgram()) {
|
||||
return GLBackend::makeProgram(shader, bindings);
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include "Resource.h"
|
||||
#include "Texture.h"
|
||||
#include "Shader.h"
|
||||
#include "Pipeline.h"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
|
@ -46,25 +48,39 @@ public:
|
|||
|
||||
template< typename T >
|
||||
static void setGPUObject(const Buffer& buffer, T* bo) {
|
||||
buffer.setGPUObject(reinterpret_cast<GPUObject*>(bo));
|
||||
buffer.setGPUObject(bo);
|
||||
}
|
||||
template< typename T >
|
||||
static T* getGPUObject(const Buffer& buffer) {
|
||||
return reinterpret_cast<T*>(buffer.getGPUObject());
|
||||
}
|
||||
|
||||
void syncGPUObject(const Buffer& buffer);
|
||||
|
||||
template< typename T >
|
||||
static void setGPUObject(const Texture& texture, T* to) {
|
||||
texture.setGPUObject(reinterpret_cast<GPUObject*>(to));
|
||||
texture.setGPUObject(to);
|
||||
}
|
||||
template< typename T >
|
||||
static T* getGPUObject(const Texture& texture) {
|
||||
return reinterpret_cast<T*>(texture.getGPUObject());
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
static void setGPUObject(const Shader& shader, T* so) {
|
||||
shader.setGPUObject(so);
|
||||
}
|
||||
template< typename T >
|
||||
static T* getGPUObject(const Shader& shader) {
|
||||
return reinterpret_cast<T*>(shader.getGPUObject());
|
||||
}
|
||||
|
||||
void syncGPUObject(const Texture& texture);
|
||||
template< typename T >
|
||||
static void setGPUObject(const Pipeline& pipeline, T* po) {
|
||||
pipeline.setGPUObject(po);
|
||||
}
|
||||
template< typename T >
|
||||
static T* getGPUObject(const Pipeline& pipeline) {
|
||||
return reinterpret_cast<T*>(pipeline.getGPUObject());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -78,8 +94,17 @@ public:
|
|||
|
||||
void enqueueBatch(Batch& batch);
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// This function can only be called by "static Shader::makeProgram()"
|
||||
// makeProgramShader(...) make a program shader ready to be used in a Batch.
|
||||
// It compiles the sub shaders, link them and defines the Slots and their bindings.
|
||||
// If the shader passed is not a program, nothing happens.
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet());
|
||||
|
||||
friend class Shader;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ enum Type {
|
|||
NUINT8,
|
||||
|
||||
NUM_TYPES,
|
||||
|
||||
BOOL = UINT8,
|
||||
};
|
||||
// Array providing the size in bytes for a given scalar type
|
||||
static const int TYPE_SIZE[NUM_TYPES] = {
|
||||
|
@ -81,9 +83,9 @@ enum Dimension {
|
|||
VEC2,
|
||||
VEC3,
|
||||
VEC4,
|
||||
MAT2,
|
||||
MAT3,
|
||||
MAT4,
|
||||
|
||||
NUM_DIMENSIONS,
|
||||
};
|
||||
// Count (of scalars) in an Element for a given Dimension
|
||||
|
@ -92,8 +94,9 @@ static const int DIMENSION_COUNT[NUM_DIMENSIONS] = {
|
|||
2,
|
||||
3,
|
||||
4,
|
||||
4,
|
||||
9,
|
||||
16
|
||||
16,
|
||||
};
|
||||
|
||||
// Semantic of an Element
|
||||
|
@ -118,6 +121,13 @@ enum Semantic {
|
|||
SRGBA,
|
||||
SBGRA,
|
||||
|
||||
UNIFORM,
|
||||
UNIFORM_BUFFER,
|
||||
SAMPLER,
|
||||
SAMPLER_MULTISAMPLE,
|
||||
SAMPLER_SHADOW,
|
||||
|
||||
|
||||
NUM_SEMANTICS,
|
||||
};
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
(&::gpu::GLBackend::do_setViewTransform),
|
||||
(&::gpu::GLBackend::do_setProjectionTransform),
|
||||
|
||||
(&::gpu::GLBackend::do_setPipeline),
|
||||
(&::gpu::GLBackend::do_setUniformBuffer),
|
||||
(&::gpu::GLBackend::do_setUniformTexture),
|
||||
|
||||
|
@ -71,7 +72,8 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
|
||||
GLBackend::GLBackend() :
|
||||
_input(),
|
||||
_transform()
|
||||
_transform(),
|
||||
_pipeline()
|
||||
{
|
||||
initTransform();
|
||||
}
|
||||
|
@ -134,6 +136,7 @@ void GLBackend::checkGLError() {
|
|||
void GLBackend::do_draw(Batch& batch, uint32 paramOffset) {
|
||||
updateInput();
|
||||
updateTransform();
|
||||
updatePipeline();
|
||||
|
||||
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
|
||||
GLenum mode = _primitiveToGLmode[primitiveType];
|
||||
|
@ -147,6 +150,7 @@ void GLBackend::do_draw(Batch& batch, uint32 paramOffset) {
|
|||
void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) {
|
||||
updateInput();
|
||||
updateTransform();
|
||||
updatePipeline();
|
||||
|
||||
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
|
||||
GLenum mode = _primitiveToGLmode[primitiveType];
|
||||
|
@ -167,389 +171,6 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) {
|
|||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_setInputFormat(Batch& batch, uint32 paramOffset) {
|
||||
Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint);
|
||||
|
||||
if (format != _input._format) {
|
||||
_input._format = format;
|
||||
_input._invalidFormat = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setInputBuffer(Batch& batch, uint32 paramOffset) {
|
||||
Offset stride = batch._params[paramOffset + 0]._uint;
|
||||
Offset offset = batch._params[paramOffset + 1]._uint;
|
||||
BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
||||
uint32 channel = batch._params[paramOffset + 3]._uint;
|
||||
|
||||
if (channel < getNumInputBuffers()) {
|
||||
_input._buffers[channel] = buffer;
|
||||
_input._bufferOffsets[channel] = offset;
|
||||
_input._bufferStrides[channel] = stride;
|
||||
_input._buffersState.set(channel);
|
||||
}
|
||||
}
|
||||
|
||||
#define SUPPORT_LEGACY_OPENGL
|
||||
#if defined(SUPPORT_LEGACY_OPENGL)
|
||||
static const int NUM_CLASSIC_ATTRIBS = Stream::TANGENT;
|
||||
static const GLenum attributeSlotToClassicAttribName[NUM_CLASSIC_ATTRIBS] = {
|
||||
GL_VERTEX_ARRAY,
|
||||
GL_NORMAL_ARRAY,
|
||||
GL_COLOR_ARRAY,
|
||||
GL_TEXTURE_COORD_ARRAY
|
||||
};
|
||||
#endif
|
||||
|
||||
void GLBackend::updateInput() {
|
||||
if (_input._invalidFormat || _input._buffersState.any()) {
|
||||
|
||||
if (_input._invalidFormat) {
|
||||
InputStageState::ActivationCache newActivation;
|
||||
|
||||
// Check expected activation
|
||||
if (_input._format) {
|
||||
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
|
||||
for (Stream::Format::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) {
|
||||
const Stream::Attribute& attrib = (*it).second;
|
||||
newActivation.set(attrib._slot);
|
||||
}
|
||||
}
|
||||
|
||||
// Manage Activation what was and what is expected now
|
||||
for (unsigned int i = 0; i < newActivation.size(); i++) {
|
||||
bool newState = newActivation[i];
|
||||
if (newState != _input._attributeActivation[i]) {
|
||||
#if defined(SUPPORT_LEGACY_OPENGL)
|
||||
if (i < NUM_CLASSIC_ATTRIBS) {
|
||||
if (newState) {
|
||||
glEnableClientState(attributeSlotToClassicAttribName[i]);
|
||||
}
|
||||
else {
|
||||
glDisableClientState(attributeSlotToClassicAttribName[i]);
|
||||
}
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
if (newState) {
|
||||
glEnableVertexAttribArray(i);
|
||||
} else {
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
_input._attributeActivation.flip(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now we need to bind the buffers and assign the attrib pointers
|
||||
if (_input._format) {
|
||||
const Buffers& buffers = _input._buffers;
|
||||
const Offsets& offsets = _input._bufferOffsets;
|
||||
const Offsets& strides = _input._bufferStrides;
|
||||
|
||||
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
|
||||
|
||||
for (Stream::Format::ChannelMap::const_iterator channelIt = _input._format->getChannels().begin();
|
||||
channelIt != _input._format->getChannels().end();
|
||||
channelIt++) {
|
||||
const Stream::Format::ChannelMap::value_type::second_type& channel = (*channelIt).second;
|
||||
if ((*channelIt).first < buffers.size()) {
|
||||
int bufferNum = (*channelIt).first;
|
||||
|
||||
if (_input._buffersState.test(bufferNum) || _input._invalidFormat) {
|
||||
GLuint vbo = gpu::GLBackend::getBufferID((*buffers[bufferNum]));
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
CHECK_GL_ERROR();
|
||||
_input._buffersState[bufferNum] = false;
|
||||
|
||||
for (unsigned int i = 0; i < channel._slots.size(); i++) {
|
||||
const Stream::Attribute& attrib = attributes.at(channel._slots[i]);
|
||||
GLuint slot = attrib._slot;
|
||||
GLuint count = attrib._element.getDimensionCount();
|
||||
GLenum type = _elementTypeToGLType[attrib._element.getType()];
|
||||
GLuint stride = strides[bufferNum];
|
||||
GLuint pointer = attrib._offset + offsets[bufferNum];
|
||||
#if defined(SUPPORT_LEGACY_OPENGL)
|
||||
if (slot < NUM_CLASSIC_ATTRIBS) {
|
||||
switch (slot) {
|
||||
case Stream::POSITION:
|
||||
glVertexPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
case Stream::NORMAL:
|
||||
glNormalPointer(type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
case Stream::COLOR:
|
||||
glColorPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
case Stream::TEXCOORD:
|
||||
glTexCoordPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
};
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
GLboolean isNormalized = attrib._element.isNormalized();
|
||||
glVertexAttribPointer(slot, count, type, isNormalized, stride,
|
||||
reinterpret_cast<GLvoid*>(pointer));
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// everything format related should be in sync now
|
||||
_input._invalidFormat = false;
|
||||
}
|
||||
|
||||
/* TODO: Fancy version GL4.4
|
||||
if (_needInputFormatUpdate) {
|
||||
|
||||
InputActivationCache newActivation;
|
||||
|
||||
// Assign the vertex format required
|
||||
if (_inputFormat) {
|
||||
const StreamFormat::AttributeMap& attributes = _inputFormat->getAttributes();
|
||||
for (StreamFormat::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) {
|
||||
const StreamFormat::Attribute& attrib = (*it).second;
|
||||
newActivation.set(attrib._slot);
|
||||
glVertexAttribFormat(
|
||||
attrib._slot,
|
||||
attrib._element.getDimensionCount(),
|
||||
_elementTypeToGLType[attrib._element.getType()],
|
||||
attrib._element.isNormalized(),
|
||||
attrib._stride);
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
// Manage Activation what was and what is expected now
|
||||
for (int i = 0; i < newActivation.size(); i++) {
|
||||
bool newState = newActivation[i];
|
||||
if (newState != _inputAttributeActivation[i]) {
|
||||
if (newState) {
|
||||
glEnableVertexAttribArray(i);
|
||||
} else {
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
_inputAttributeActivation.flip(i);
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
_needInputFormatUpdate = false;
|
||||
}
|
||||
|
||||
if (_needInputStreamUpdate) {
|
||||
if (_inputStream) {
|
||||
const Stream::Buffers& buffers = _inputStream->getBuffers();
|
||||
const Stream::Offsets& offsets = _inputStream->getOffsets();
|
||||
const Stream::Strides& strides = _inputStream->getStrides();
|
||||
|
||||
for (int i = 0; i < buffers.size(); i++) {
|
||||
GLuint vbo = gpu::GLBackend::getBufferID((*buffers[i]));
|
||||
glBindVertexBuffer(i, vbo, offsets[i], strides[i]);
|
||||
}
|
||||
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
_needInputStreamUpdate = false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) {
|
||||
_input._indexBufferType = (Type) batch._params[paramOffset + 2]._uint;
|
||||
BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint);
|
||||
_input._indexBufferOffset = batch._params[paramOffset + 0]._uint;
|
||||
_input._indexBuffer = indexBuffer;
|
||||
if (indexBuffer) {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*indexBuffer));
|
||||
} else {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
// Transform Stage
|
||||
|
||||
void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) {
|
||||
_transform._model = batch._transforms.get(batch._params[paramOffset]._uint);
|
||||
_transform._invalidModel = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) {
|
||||
_transform._view = batch._transforms.get(batch._params[paramOffset]._uint);
|
||||
_transform._invalidView = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) {
|
||||
memcpy(&_transform._projection, batch.editData(batch._params[paramOffset]._uint), sizeof(Mat4));
|
||||
_transform._invalidProj = true;
|
||||
}
|
||||
|
||||
void GLBackend::initTransform() {
|
||||
#if defined(Q_OS_WIN)
|
||||
glGenBuffers(1, &_transform._transformObjectBuffer);
|
||||
glGenBuffers(1, &_transform._transformCameraBuffer);
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformObjectBuffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformCameraBuffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW);
|
||||
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLBackend::killTransform() {
|
||||
#if defined(Q_OS_WIN)
|
||||
glDeleteBuffers(1, &_transform._transformObjectBuffer);
|
||||
glDeleteBuffers(1, &_transform._transformCameraBuffer);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
void GLBackend::updateTransform() {
|
||||
// Check all the dirty flags and update the state accordingly
|
||||
if (_transform._invalidProj) {
|
||||
_transform._transformCamera._projection = _transform._projection;
|
||||
}
|
||||
|
||||
if (_transform._invalidView) {
|
||||
_transform._view.getInverseMatrix(_transform._transformCamera._view);
|
||||
_transform._view.getMatrix(_transform._transformCamera._viewInverse);
|
||||
}
|
||||
|
||||
if (_transform._invalidModel) {
|
||||
_transform._model.getMatrix(_transform._transformObject._model);
|
||||
_transform._model.getInverseMatrix(_transform._transformObject._modelInverse);
|
||||
}
|
||||
|
||||
if (_transform._invalidView || _transform._invalidProj) {
|
||||
Mat4 viewUntranslated = _transform._transformCamera._view;
|
||||
viewUntranslated[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
_transform._transformCamera._projectionViewUntranslated = _transform._transformCamera._projection * viewUntranslated;
|
||||
}
|
||||
|
||||
if (_transform._invalidView || _transform._invalidProj) {
|
||||
#if defined(Q_OS_WIN)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _transform._transformCameraBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
CHECK_GL_ERROR();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_transform._invalidModel) {
|
||||
#if defined(Q_OS_WIN)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _transform._transformObjectBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
CHECK_GL_ERROR();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._transformObjectBuffer);
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, _transform._transformCameraBuffer);
|
||||
CHECK_GL_ERROR();
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
|
||||
// Do it again for fixed pipeline until we can get rid of it
|
||||
if (_transform._invalidProj) {
|
||||
if (_transform._lastMode != GL_PROJECTION) {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
_transform._lastMode = GL_PROJECTION;
|
||||
}
|
||||
glLoadMatrixf(reinterpret_cast< const GLfloat* >(&_transform._projection));
|
||||
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
if (_transform._invalidModel || _transform._invalidView) {
|
||||
if (!_transform._model.isIdentity()) {
|
||||
if (_transform._lastMode != GL_MODELVIEW) {
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
_transform._lastMode = GL_MODELVIEW;
|
||||
}
|
||||
Transform::Mat4 modelView;
|
||||
if (!_transform._view.isIdentity()) {
|
||||
Transform mvx;
|
||||
Transform::inverseMult(mvx, _transform._view, _transform._model);
|
||||
mvx.getMatrix(modelView);
|
||||
} else {
|
||||
_transform._model.getMatrix(modelView);
|
||||
}
|
||||
glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));
|
||||
} else {
|
||||
if (!_transform._view.isIdentity()) {
|
||||
if (_transform._lastMode != GL_MODELVIEW) {
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
_transform._lastMode = GL_MODELVIEW;
|
||||
}
|
||||
Transform::Mat4 modelView;
|
||||
_transform._view.getInverseMatrix(modelView);
|
||||
glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));
|
||||
} else {
|
||||
// TODO: eventually do something about the matrix when neither view nor model is specified?
|
||||
// glLoadIdentity();
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Flags are clean
|
||||
_transform._invalidView = _transform._invalidProj = _transform._invalidModel = false;
|
||||
}
|
||||
|
||||
void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) {
|
||||
GLuint slot = batch._params[paramOffset + 3]._uint;
|
||||
BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
||||
GLintptr rangeStart = batch._params[paramOffset + 1]._uint;
|
||||
GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint;
|
||||
#if defined(Q_OS_MAC)
|
||||
GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart);
|
||||
glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data);
|
||||
|
||||
// NOT working so we ll stick to the uniform float array until we move to core profile
|
||||
// GLuint bo = getBufferID(*uniformBuffer);
|
||||
//glUniformBufferEXT(_shader._program, slot, bo);
|
||||
#elif defined(Q_OS_WIN)
|
||||
GLuint bo = getBufferID(*uniformBuffer);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, slot, bo, rangeStart, rangeSize);
|
||||
#else
|
||||
GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart);
|
||||
glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data);
|
||||
#endif
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_setUniformTexture(Batch& batch, uint32 paramOffset) {
|
||||
GLuint slot = batch._params[paramOffset + 1]._uint;
|
||||
TexturePointer uniformTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
|
||||
|
||||
GLuint to = getTextureID(uniformTexture);
|
||||
glActiveTexture(GL_TEXTURE0 + slot);
|
||||
glBindTexture(GL_TEXTURE_2D, to);
|
||||
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
||||
// TODO: As long as we have gl calls explicitely issued from interface
|
||||
// code, we need to be able to record and batch these calls. THe long
|
||||
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
|
||||
|
@ -740,8 +361,10 @@ void Batch::_glUseProgram(GLuint program) {
|
|||
}
|
||||
void GLBackend::do_glUseProgram(Batch& batch, uint32 paramOffset) {
|
||||
|
||||
_shader._program = batch._params[paramOffset]._uint;
|
||||
glUseProgram(_shader._program);
|
||||
_pipeline._program = batch._params[paramOffset]._uint;
|
||||
// for this call we still want to execute the glUseProgram in the order of the glCOmmand to avoid any issue
|
||||
_pipeline._invalidProgram = false;
|
||||
glUseProgram(_pipeline._program);
|
||||
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
@ -998,49 +621,3 @@ void GLBackend::do_glColor4f(Batch& batch, uint32 paramOffset) {
|
|||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
GLBackend::GLBuffer::GLBuffer() :
|
||||
_stamp(0),
|
||||
_buffer(0),
|
||||
_size(0)
|
||||
{}
|
||||
|
||||
GLBackend::GLBuffer::~GLBuffer() {
|
||||
if (_buffer != 0) {
|
||||
glDeleteBuffers(1, &_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::syncGPUObject(const Buffer& buffer) {
|
||||
GLBuffer* object = Backend::getGPUObject<GLBackend::GLBuffer>(buffer);
|
||||
|
||||
if (object && (object->_stamp == buffer.getSysmem().getStamp())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// need to have a gpu object?
|
||||
if (!object) {
|
||||
object = new GLBuffer();
|
||||
glGenBuffers(1, &object->_buffer);
|
||||
CHECK_GL_ERROR();
|
||||
Backend::setGPUObject(buffer, object);
|
||||
}
|
||||
|
||||
// Now let's update the content of the bo with the sysmem version
|
||||
// TODO: in the future, be smarter about when to actually upload the glBO version based on the data that did change
|
||||
//if () {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, object->_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, buffer.getSysmem().getSize(), buffer.getSysmem().readData(), GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
object->_stamp = buffer.getSysmem().getStamp();
|
||||
object->_size = buffer.getSysmem().getSize();
|
||||
//}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
||||
|
||||
GLuint GLBackend::getBufferID(const Buffer& buffer) {
|
||||
GLBackend::syncGPUObject(buffer);
|
||||
return Backend::getGPUObject<GLBackend::GLBuffer>(buffer)->_buffer;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ public:
|
|||
|
||||
static void checkGLError();
|
||||
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet());
|
||||
|
||||
|
||||
class GLBuffer : public GPUObject {
|
||||
|
@ -44,7 +45,7 @@ public:
|
|||
GLBuffer();
|
||||
~GLBuffer();
|
||||
};
|
||||
static void syncGPUObject(const Buffer& buffer);
|
||||
static GLBuffer* syncGPUObject(const Buffer& buffer);
|
||||
static GLuint getBufferID(const Buffer& buffer);
|
||||
|
||||
class GLTexture : public GPUObject {
|
||||
|
@ -57,9 +58,33 @@ public:
|
|||
GLTexture();
|
||||
~GLTexture();
|
||||
};
|
||||
static void syncGPUObject(const Texture& texture);
|
||||
static GLTexture* syncGPUObject(const Texture& texture);
|
||||
static GLuint getTextureID(const TexturePointer& texture);
|
||||
|
||||
class GLShader : public GPUObject {
|
||||
public:
|
||||
GLuint _shader;
|
||||
GLuint _program;
|
||||
|
||||
GLuint _transformCameraSlot = -1;
|
||||
GLuint _transformObjectSlot = -1;
|
||||
|
||||
GLShader();
|
||||
~GLShader();
|
||||
};
|
||||
static GLShader* syncGPUObject(const Shader& shader);
|
||||
static GLuint getShaderID(const ShaderPointer& shader);
|
||||
|
||||
|
||||
class GLPipeline : public GPUObject {
|
||||
public:
|
||||
GLShader* _program;
|
||||
|
||||
GLPipeline();
|
||||
~GLPipeline();
|
||||
};
|
||||
static GLPipeline* syncGPUObject(const Pipeline& pipeline);
|
||||
|
||||
static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS;
|
||||
static const int MAX_NUM_INPUT_BUFFERS = 16;
|
||||
|
||||
|
@ -145,18 +170,24 @@ protected:
|
|||
_lastMode(GL_TEXTURE) {}
|
||||
} _transform;
|
||||
|
||||
// Shader Stage
|
||||
// Pipeline Stage
|
||||
void do_setPipeline(Batch& batch, uint32 paramOffset);
|
||||
void do_setUniformBuffer(Batch& batch, uint32 paramOffset);
|
||||
void do_setUniformTexture(Batch& batch, uint32 paramOffset);
|
||||
|
||||
void updateShader();
|
||||
struct ShaderStageState {
|
||||
void updatePipeline();
|
||||
struct PipelineStageState {
|
||||
|
||||
PipelinePointer _pipeline;
|
||||
GLuint _program;
|
||||
bool _invalidProgram;
|
||||
|
||||
ShaderStageState() :
|
||||
_program(0) {}
|
||||
} _shader;
|
||||
PipelineStageState() :
|
||||
_pipeline(),
|
||||
_program(0),
|
||||
_invalidProgram(false)
|
||||
{}
|
||||
} _pipeline;
|
||||
|
||||
|
||||
// TODO: As long as we have gl calls explicitely issued from interface
|
||||
|
|
66
libraries/gpu/src/gpu/GLBackendBuffer.cpp
Executable file
66
libraries/gpu/src/gpu/GLBackendBuffer.cpp
Executable file
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// GLBackendBuffer.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLBackendShared.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
GLBackend::GLBuffer::GLBuffer() :
|
||||
_stamp(0),
|
||||
_buffer(0),
|
||||
_size(0)
|
||||
{}
|
||||
|
||||
GLBackend::GLBuffer::~GLBuffer() {
|
||||
if (_buffer != 0) {
|
||||
glDeleteBuffers(1, &_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) {
|
||||
GLBuffer* object = Backend::getGPUObject<GLBackend::GLBuffer>(buffer);
|
||||
|
||||
if (object && (object->_stamp == buffer.getSysmem().getStamp())) {
|
||||
return object;
|
||||
}
|
||||
|
||||
// need to have a gpu object?
|
||||
if (!object) {
|
||||
object = new GLBuffer();
|
||||
glGenBuffers(1, &object->_buffer);
|
||||
CHECK_GL_ERROR();
|
||||
Backend::setGPUObject(buffer, object);
|
||||
}
|
||||
|
||||
// Now let's update the content of the bo with the sysmem version
|
||||
// TODO: in the future, be smarter about when to actually upload the glBO version based on the data that did change
|
||||
//if () {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, object->_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, buffer.getSysmem().getSize(), buffer.getSysmem().readData(), GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
object->_stamp = buffer.getSysmem().getStamp();
|
||||
object->_size = buffer.getSysmem().getSize();
|
||||
//}
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GLuint GLBackend::getBufferID(const Buffer& buffer) {
|
||||
GLBuffer* bo = GLBackend::syncGPUObject(buffer);
|
||||
if (bo) {
|
||||
return bo->_buffer;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
223
libraries/gpu/src/gpu/GLBackendInput.cpp
Executable file
223
libraries/gpu/src/gpu/GLBackendInput.cpp
Executable file
|
@ -0,0 +1,223 @@
|
|||
//
|
||||
// GLBackendInput.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLBackendShared.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
void GLBackend::do_setInputFormat(Batch& batch, uint32 paramOffset) {
|
||||
Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint);
|
||||
|
||||
if (format != _input._format) {
|
||||
_input._format = format;
|
||||
_input._invalidFormat = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setInputBuffer(Batch& batch, uint32 paramOffset) {
|
||||
Offset stride = batch._params[paramOffset + 0]._uint;
|
||||
Offset offset = batch._params[paramOffset + 1]._uint;
|
||||
BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
||||
uint32 channel = batch._params[paramOffset + 3]._uint;
|
||||
|
||||
if (channel < getNumInputBuffers()) {
|
||||
_input._buffers[channel] = buffer;
|
||||
_input._bufferOffsets[channel] = offset;
|
||||
_input._bufferStrides[channel] = stride;
|
||||
_input._buffersState.set(channel);
|
||||
}
|
||||
}
|
||||
|
||||
#define SUPPORT_LEGACY_OPENGL
|
||||
#if defined(SUPPORT_LEGACY_OPENGL)
|
||||
static const int NUM_CLASSIC_ATTRIBS = Stream::TANGENT;
|
||||
static const GLenum attributeSlotToClassicAttribName[NUM_CLASSIC_ATTRIBS] = {
|
||||
GL_VERTEX_ARRAY,
|
||||
GL_NORMAL_ARRAY,
|
||||
GL_COLOR_ARRAY,
|
||||
GL_TEXTURE_COORD_ARRAY
|
||||
};
|
||||
#endif
|
||||
|
||||
void GLBackend::updateInput() {
|
||||
if (_input._invalidFormat || _input._buffersState.any()) {
|
||||
|
||||
if (_input._invalidFormat) {
|
||||
InputStageState::ActivationCache newActivation;
|
||||
|
||||
// Check expected activation
|
||||
if (_input._format) {
|
||||
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
|
||||
for (Stream::Format::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) {
|
||||
const Stream::Attribute& attrib = (*it).second;
|
||||
newActivation.set(attrib._slot);
|
||||
}
|
||||
}
|
||||
|
||||
// Manage Activation what was and what is expected now
|
||||
for (unsigned int i = 0; i < newActivation.size(); i++) {
|
||||
bool newState = newActivation[i];
|
||||
if (newState != _input._attributeActivation[i]) {
|
||||
#if defined(SUPPORT_LEGACY_OPENGL)
|
||||
if (i < NUM_CLASSIC_ATTRIBS) {
|
||||
if (newState) {
|
||||
glEnableClientState(attributeSlotToClassicAttribName[i]);
|
||||
}
|
||||
else {
|
||||
glDisableClientState(attributeSlotToClassicAttribName[i]);
|
||||
}
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
if (newState) {
|
||||
glEnableVertexAttribArray(i);
|
||||
} else {
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
_input._attributeActivation.flip(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now we need to bind the buffers and assign the attrib pointers
|
||||
if (_input._format) {
|
||||
const Buffers& buffers = _input._buffers;
|
||||
const Offsets& offsets = _input._bufferOffsets;
|
||||
const Offsets& strides = _input._bufferStrides;
|
||||
|
||||
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
|
||||
|
||||
for (Stream::Format::ChannelMap::const_iterator channelIt = _input._format->getChannels().begin();
|
||||
channelIt != _input._format->getChannels().end();
|
||||
channelIt++) {
|
||||
const Stream::Format::ChannelMap::value_type::second_type& channel = (*channelIt).second;
|
||||
if ((*channelIt).first < buffers.size()) {
|
||||
int bufferNum = (*channelIt).first;
|
||||
|
||||
if (_input._buffersState.test(bufferNum) || _input._invalidFormat) {
|
||||
GLuint vbo = gpu::GLBackend::getBufferID((*buffers[bufferNum]));
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
CHECK_GL_ERROR();
|
||||
_input._buffersState[bufferNum] = false;
|
||||
|
||||
for (unsigned int i = 0; i < channel._slots.size(); i++) {
|
||||
const Stream::Attribute& attrib = attributes.at(channel._slots[i]);
|
||||
GLuint slot = attrib._slot;
|
||||
GLuint count = attrib._element.getDimensionCount();
|
||||
GLenum type = _elementTypeToGLType[attrib._element.getType()];
|
||||
GLuint stride = strides[bufferNum];
|
||||
GLuint pointer = attrib._offset + offsets[bufferNum];
|
||||
#if defined(SUPPORT_LEGACY_OPENGL)
|
||||
if (slot < NUM_CLASSIC_ATTRIBS) {
|
||||
switch (slot) {
|
||||
case Stream::POSITION:
|
||||
glVertexPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
case Stream::NORMAL:
|
||||
glNormalPointer(type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
case Stream::COLOR:
|
||||
glColorPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
case Stream::TEXCOORD:
|
||||
glTexCoordPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer));
|
||||
break;
|
||||
};
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
GLboolean isNormalized = attrib._element.isNormalized();
|
||||
glVertexAttribPointer(slot, count, type, isNormalized, stride,
|
||||
reinterpret_cast<GLvoid*>(pointer));
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// everything format related should be in sync now
|
||||
_input._invalidFormat = false;
|
||||
}
|
||||
|
||||
/* TODO: Fancy version GL4.4
|
||||
if (_needInputFormatUpdate) {
|
||||
|
||||
InputActivationCache newActivation;
|
||||
|
||||
// Assign the vertex format required
|
||||
if (_inputFormat) {
|
||||
const StreamFormat::AttributeMap& attributes = _inputFormat->getAttributes();
|
||||
for (StreamFormat::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) {
|
||||
const StreamFormat::Attribute& attrib = (*it).second;
|
||||
newActivation.set(attrib._slot);
|
||||
glVertexAttribFormat(
|
||||
attrib._slot,
|
||||
attrib._element.getDimensionCount(),
|
||||
_elementTypeToGLType[attrib._element.getType()],
|
||||
attrib._element.isNormalized(),
|
||||
attrib._stride);
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
// Manage Activation what was and what is expected now
|
||||
for (int i = 0; i < newActivation.size(); i++) {
|
||||
bool newState = newActivation[i];
|
||||
if (newState != _inputAttributeActivation[i]) {
|
||||
if (newState) {
|
||||
glEnableVertexAttribArray(i);
|
||||
} else {
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
_inputAttributeActivation.flip(i);
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
_needInputFormatUpdate = false;
|
||||
}
|
||||
|
||||
if (_needInputStreamUpdate) {
|
||||
if (_inputStream) {
|
||||
const Stream::Buffers& buffers = _inputStream->getBuffers();
|
||||
const Stream::Offsets& offsets = _inputStream->getOffsets();
|
||||
const Stream::Strides& strides = _inputStream->getStrides();
|
||||
|
||||
for (int i = 0; i < buffers.size(); i++) {
|
||||
GLuint vbo = gpu::GLBackend::getBufferID((*buffers[i]));
|
||||
glBindVertexBuffer(i, vbo, offsets[i], strides[i]);
|
||||
}
|
||||
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
_needInputStreamUpdate = false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) {
|
||||
_input._indexBufferType = (Type) batch._params[paramOffset + 2]._uint;
|
||||
BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint);
|
||||
_input._indexBufferOffset = batch._params[paramOffset + 0]._uint;
|
||||
_input._indexBuffer = indexBuffer;
|
||||
if (indexBuffer) {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*indexBuffer));
|
||||
} else {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
95
libraries/gpu/src/gpu/GLBackendPipeline.cpp
Executable file
95
libraries/gpu/src/gpu/GLBackendPipeline.cpp
Executable file
|
@ -0,0 +1,95 @@
|
|||
//
|
||||
// GLBackendPipeline.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLBackendShared.h"
|
||||
|
||||
#include "Format.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
GLBackend::GLPipeline::GLPipeline() :
|
||||
_program(nullptr)
|
||||
{}
|
||||
|
||||
GLBackend::GLPipeline::~GLPipeline() {
|
||||
_program = nullptr;
|
||||
}
|
||||
|
||||
GLBackend::GLPipeline* GLBackend::syncGPUObject(const Pipeline& pipeline) {
|
||||
GLPipeline* object = Backend::getGPUObject<GLBackend::GLPipeline>(pipeline);
|
||||
|
||||
// If GPU object already created then good
|
||||
if (object) {
|
||||
return object;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) {
|
||||
PipelinePointer pipeline = batch._pipelines.get(batch._params[paramOffset + 0]._uint);
|
||||
|
||||
if (pipeline == _pipeline._pipeline) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto pipelineObject = syncGPUObject((*pipeline));
|
||||
if (!pipelineObject) {
|
||||
return;
|
||||
}
|
||||
|
||||
_pipeline._pipeline = pipeline;
|
||||
_pipeline._program = pipelineObject->_program->_program;
|
||||
_pipeline._invalidProgram = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) {
|
||||
GLuint slot = batch._params[paramOffset + 3]._uint;
|
||||
BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
||||
GLintptr rangeStart = batch._params[paramOffset + 1]._uint;
|
||||
GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint;
|
||||
#if defined(Q_OS_MAC)
|
||||
GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart);
|
||||
glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data);
|
||||
|
||||
// NOT working so we ll stick to the uniform float array until we move to core profile
|
||||
// GLuint bo = getBufferID(*uniformBuffer);
|
||||
//glUniformBufferEXT(_shader._program, slot, bo);
|
||||
#elif defined(Q_OS_WIN)
|
||||
GLuint bo = getBufferID(*uniformBuffer);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, slot, bo, rangeStart, rangeSize);
|
||||
#else
|
||||
GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart);
|
||||
glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data);
|
||||
#endif
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_setUniformTexture(Batch& batch, uint32 paramOffset) {
|
||||
GLuint slot = batch._params[paramOffset + 1]._uint;
|
||||
TexturePointer uniformTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
|
||||
|
||||
GLuint to = getTextureID(uniformTexture);
|
||||
glActiveTexture(GL_TEXTURE0 + slot);
|
||||
glBindTexture(GL_TEXTURE_2D, to);
|
||||
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::updatePipeline() {
|
||||
if (_pipeline._invalidProgram) {
|
||||
glUseProgram(_pipeline._program);
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._invalidProgram = true;
|
||||
}
|
||||
}
|
||||
|
685
libraries/gpu/src/gpu/GLBackendShader.cpp
Executable file
685
libraries/gpu/src/gpu/GLBackendShader.cpp
Executable file
|
@ -0,0 +1,685 @@
|
|||
//
|
||||
// GLBackendShader.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 2/28/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLBackendShared.h"
|
||||
|
||||
#include "Format.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
GLBackend::GLShader::GLShader() :
|
||||
_shader(0),
|
||||
_program(0)
|
||||
{}
|
||||
|
||||
GLBackend::GLShader::~GLShader() {
|
||||
if (_shader != 0) {
|
||||
glDeleteShader(_shader);
|
||||
}
|
||||
if (_program != 0) {
|
||||
glDeleteProgram(_program);
|
||||
}
|
||||
}
|
||||
|
||||
void makeBindings(GLBackend::GLShader* shader) {
|
||||
if(!shader || !shader->_program) {
|
||||
return;
|
||||
}
|
||||
GLuint glprogram = shader->_program;
|
||||
GLint loc = -1;
|
||||
|
||||
//Check for gpu specific attribute slotBindings
|
||||
loc = glGetAttribLocation(glprogram, "position");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::POSITION, "position");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "normal");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "normal");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "color");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::COLOR, "color");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "texcoord");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "texcoord");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "tangent");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "tangent");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "texcoord1");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD1, "texcoord1");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "clusterIndices");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_INDEX, "clusterIndices");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "clusterWeights");
|
||||
if (loc >= 0) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "clusterWeights");
|
||||
}
|
||||
|
||||
// Link again to take into account the assigned attrib location
|
||||
glLinkProgram(glprogram);
|
||||
|
||||
GLint linked = 0;
|
||||
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
||||
if (!linked) {
|
||||
qDebug() << "GLShader::makeBindings - failed to link after assigning slotBindings?";
|
||||
}
|
||||
|
||||
// now assign the ubo binding, then DON't relink!
|
||||
|
||||
//Check for gpu specific uniform slotBindings
|
||||
#if defined(Q_OS_WIN)
|
||||
loc = glGetUniformBlockIndex(glprogram, "transformObjectBuffer");
|
||||
if (loc >= 0) {
|
||||
glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT);
|
||||
shader->_transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT;
|
||||
}
|
||||
|
||||
loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer");
|
||||
if (loc >= 0) {
|
||||
glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT);
|
||||
shader->_transformCameraSlot = gpu::TRANSFORM_OBJECT_SLOT;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
GLBackend::GLShader* compileShader(const Shader& shader) {
|
||||
// Any GLSLprogram ? normally yes...
|
||||
const std::string& shaderSource = shader.getSource().getCode();
|
||||
if (shaderSource.empty()) {
|
||||
qDebug() << "GLShader::compileShader - no GLSL shader source code ? so failed to create";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Shader domain
|
||||
const GLenum SHADER_DOMAINS[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER };
|
||||
GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
|
||||
|
||||
// Create the shader object
|
||||
GLuint glshader = glCreateShader(shaderDomain);
|
||||
if (!glshader) {
|
||||
qDebug() << "GLShader::compileShader - failed to create the gl shader object";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Assign the source
|
||||
const GLchar* srcstr = shaderSource.c_str();
|
||||
glShaderSource(glshader, 1, &srcstr, NULL);
|
||||
|
||||
// Compile !
|
||||
glCompileShader(glshader);
|
||||
|
||||
// check if shader compiled
|
||||
GLint compiled = 0;
|
||||
glGetShaderiv(glshader, GL_COMPILE_STATUS, &compiled);
|
||||
|
||||
// if compilation fails
|
||||
if (!compiled) {
|
||||
// save the source code to a temp file so we can debug easily
|
||||
/* std::ofstream filestream;
|
||||
filestream.open("debugshader.glsl");
|
||||
if (filestream.is_open()) {
|
||||
filestream << shaderSource->source;
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
|
||||
GLint infoLength = 0;
|
||||
glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength);
|
||||
|
||||
char* temp = new char[infoLength] ;
|
||||
glGetShaderInfoLog(glshader, infoLength, NULL, temp);
|
||||
|
||||
qDebug() << "GLShader::compileShader - failed to compile the gl shader object:";
|
||||
qDebug() << temp;
|
||||
|
||||
/*
|
||||
filestream.open("debugshader.glsl.info.txt");
|
||||
if (filestream.is_open()) {
|
||||
filestream << std::string(temp);
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
delete[] temp;
|
||||
|
||||
glDeleteShader(glshader);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GLuint glprogram = 0;
|
||||
#ifdef SEPARATE_PROGRAM
|
||||
// so far so good, program is almost done, need to link:
|
||||
GLuint glprogram = glCreateProgram();
|
||||
if (!glprogram) {
|
||||
qDebug() << "GLShader::compileShader - failed to create the gl shader & gl program object";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
glProgramParameteri(glprogram, GL_PROGRAM_SEPARABLE, GL_TRUE);
|
||||
glAttachShader(glprogram, glshader);
|
||||
glLinkProgram(glprogram);
|
||||
|
||||
GLint linked = 0;
|
||||
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
||||
|
||||
if (!linked) {
|
||||
/*
|
||||
// save the source code to a temp file so we can debug easily
|
||||
std::ofstream filestream;
|
||||
filestream.open("debugshader.glsl");
|
||||
if (filestream.is_open()) {
|
||||
filestream << shaderSource->source;
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
|
||||
GLint infoLength = 0;
|
||||
glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
|
||||
|
||||
char* temp = new char[infoLength] ;
|
||||
glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
|
||||
|
||||
qDebug() << "GLShader::compileShader - failed to LINK the gl program object :";
|
||||
qDebug() << temp;
|
||||
|
||||
/*
|
||||
filestream.open("debugshader.glsl.info.txt");
|
||||
if (filestream.is_open()) {
|
||||
filestream << String(temp);
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
delete[] temp;
|
||||
|
||||
glDeleteShader(glshader);
|
||||
glDeleteProgram(glprogram);
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// So far so good, the shader is created successfully
|
||||
GLBackend::GLShader* object = new GLBackend::GLShader();
|
||||
object->_shader = glshader;
|
||||
object->_program = glprogram;
|
||||
|
||||
makeBindings(object);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
GLBackend::GLShader* compileProgram(const Shader& program) {
|
||||
if(!program.isProgram()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Let's go through every shaders and make sure they are ready to go
|
||||
std::vector< GLuint > shaderObjects;
|
||||
for (auto subShader : program.getShaders()) {
|
||||
GLuint so = GLBackend::getShaderID(subShader);
|
||||
if (!so) {
|
||||
qDebug() << "GLShader::compileProgram - One of the shaders of the program is not compiled?";
|
||||
return nullptr;
|
||||
}
|
||||
shaderObjects.push_back(so);
|
||||
}
|
||||
|
||||
// so far so good, program is almost done, need to link:
|
||||
GLuint glprogram = glCreateProgram();
|
||||
if (!glprogram) {
|
||||
qDebug() << "GLShader::compileProgram - failed to create the gl program object";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// glProgramParameteri(glprogram, GL_PROGRAM_, GL_TRUE);
|
||||
// Create the program from the sub shaders
|
||||
for (auto so : shaderObjects) {
|
||||
glAttachShader(glprogram, so);
|
||||
}
|
||||
|
||||
// Link!
|
||||
glLinkProgram(glprogram);
|
||||
|
||||
GLint linked = 0;
|
||||
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
||||
|
||||
if (!linked) {
|
||||
/*
|
||||
// save the source code to a temp file so we can debug easily
|
||||
std::ofstream filestream;
|
||||
filestream.open("debugshader.glsl");
|
||||
if (filestream.is_open()) {
|
||||
filestream << shaderSource->source;
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
|
||||
GLint infoLength = 0;
|
||||
glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
|
||||
|
||||
char* temp = new char[infoLength] ;
|
||||
glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
|
||||
|
||||
qDebug() << "GLShader::compileProgram - failed to LINK the gl program object :";
|
||||
qDebug() << temp;
|
||||
|
||||
/*
|
||||
filestream.open("debugshader.glsl.info.txt");
|
||||
if (filestream.is_open()) {
|
||||
filestream << std::string(temp);
|
||||
filestream.close();
|
||||
}
|
||||
*/
|
||||
delete[] temp;
|
||||
|
||||
glDeleteProgram(glprogram);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// So far so good, the program is created successfully
|
||||
GLBackend::GLShader* object = new GLBackend::GLShader();
|
||||
object->_shader = 0;
|
||||
object->_program = glprogram;
|
||||
|
||||
makeBindings(object);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
GLBackend::GLShader* GLBackend::syncGPUObject(const Shader& shader) {
|
||||
GLShader* object = Backend::getGPUObject<GLBackend::GLShader>(shader);
|
||||
|
||||
// If GPU object already created then good
|
||||
if (object) {
|
||||
return object;
|
||||
}
|
||||
// need to have a gpu object?
|
||||
if (shader.isProgram()) {
|
||||
GLShader* tempObject = compileProgram(shader);
|
||||
if (tempObject) {
|
||||
object = tempObject;
|
||||
Backend::setGPUObject(shader, object);
|
||||
}
|
||||
} else if (shader.isDomain()) {
|
||||
GLShader* tempObject = compileShader(shader);
|
||||
if (tempObject) {
|
||||
object = tempObject;
|
||||
Backend::setGPUObject(shader, object);
|
||||
}
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
GLuint GLBackend::getShaderID(const ShaderPointer& shader) {
|
||||
if (!shader) {
|
||||
return 0;
|
||||
}
|
||||
GLShader* object = GLBackend::syncGPUObject(*shader);
|
||||
if (object) {
|
||||
if (shader->isProgram()) {
|
||||
return object->_program;
|
||||
} else {
|
||||
return object->_shader;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class ElementResource {
|
||||
public:
|
||||
gpu::Element _element;
|
||||
uint16 _resource;
|
||||
|
||||
ElementResource(Element&& elem, uint16 resource) : _element(elem), _resource(resource) {}
|
||||
};
|
||||
|
||||
ElementResource getFormatFromGLUniform(GLenum gltype) {
|
||||
switch (gltype) {
|
||||
case GL_FLOAT: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
/*
|
||||
case GL_DOUBLE: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_DOUBLE_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_DOUBLE_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_DOUBLE_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
*/
|
||||
case GL_INT: return ElementResource(Element(SCALAR, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC2: return ElementResource(Element(VEC2, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC3: return ElementResource(Element(VEC3, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC4: return ElementResource(Element(VEC4, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
|
||||
case GL_UNSIGNED_INT: return ElementResource(Element(SCALAR, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
#if defined(Q_OS_WIN)
|
||||
case GL_UNSIGNED_INT_VEC2: return ElementResource(Element(VEC2, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_UNSIGNED_INT_VEC3: return ElementResource(Element(VEC3, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_UNSIGNED_INT_VEC4: return ElementResource(Element(VEC4, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
#endif
|
||||
|
||||
case GL_BOOL: return ElementResource(Element(SCALAR, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC2: return ElementResource(Element(VEC2, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC3: return ElementResource(Element(VEC3, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC4: return ElementResource(Element(VEC4, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
|
||||
|
||||
case GL_FLOAT_MAT2: return ElementResource(Element(gpu::MAT2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_MAT3: return ElementResource(Element(MAT3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_MAT4: return ElementResource(Element(MAT4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
|
||||
/* {GL_FLOAT_MAT2x3 mat2x3},
|
||||
{GL_FLOAT_MAT2x4 mat2x4},
|
||||
{GL_FLOAT_MAT3x2 mat3x2},
|
||||
{GL_FLOAT_MAT3x4 mat3x4},
|
||||
{GL_FLOAT_MAT4x2 mat4x2},
|
||||
{GL_FLOAT_MAT4x3 mat4x3},
|
||||
{GL_DOUBLE_MAT2 dmat2},
|
||||
{GL_DOUBLE_MAT3 dmat3},
|
||||
{GL_DOUBLE_MAT4 dmat4},
|
||||
{GL_DOUBLE_MAT2x3 dmat2x3},
|
||||
{GL_DOUBLE_MAT2x4 dmat2x4},
|
||||
{GL_DOUBLE_MAT3x2 dmat3x2},
|
||||
{GL_DOUBLE_MAT3x4 dmat3x4},
|
||||
{GL_DOUBLE_MAT4x2 dmat4x2},
|
||||
{GL_DOUBLE_MAT4x3 dmat4x3},
|
||||
*/
|
||||
|
||||
case GL_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D);
|
||||
|
||||
case GL_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
case GL_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
case GL_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
#endif
|
||||
|
||||
case GL_SAMPLER_2D_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D);
|
||||
#if defined(Q_OS_WIN)
|
||||
case GL_SAMPLER_CUBE_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_CUBE);
|
||||
|
||||
case GL_SAMPLER_2D_ARRAY_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D_ARRAY);
|
||||
#endif
|
||||
|
||||
// {GL_SAMPLER_1D_SHADOW sampler1DShadow},
|
||||
// {GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow},
|
||||
|
||||
// {GL_SAMPLER_BUFFER samplerBuffer},
|
||||
// {GL_SAMPLER_2D_RECT sampler2DRect},
|
||||
// {GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow},
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
case GL_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D);
|
||||
case GL_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
|
||||
case GL_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
case GL_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
|
||||
// {GL_INT_SAMPLER_BUFFER isamplerBuffer},
|
||||
// {GL_INT_SAMPLER_2D_RECT isampler2DRect},
|
||||
|
||||
case GL_UNSIGNED_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
|
||||
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
#endif
|
||||
// {GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer},
|
||||
// {GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect},
|
||||
/*
|
||||
{GL_IMAGE_1D image1D},
|
||||
{GL_IMAGE_2D image2D},
|
||||
{GL_IMAGE_3D image3D},
|
||||
{GL_IMAGE_2D_RECT image2DRect},
|
||||
{GL_IMAGE_CUBE imageCube},
|
||||
{GL_IMAGE_BUFFER imageBuffer},
|
||||
{GL_IMAGE_1D_ARRAY image1DArray},
|
||||
{GL_IMAGE_2D_ARRAY image2DArray},
|
||||
{GL_IMAGE_2D_MULTISAMPLE image2DMS},
|
||||
{GL_IMAGE_2D_MULTISAMPLE_ARRAY image2DMSArray},
|
||||
{GL_INT_IMAGE_1D iimage1D},
|
||||
{GL_INT_IMAGE_2D iimage2D},
|
||||
{GL_INT_IMAGE_3D iimage3D},
|
||||
{GL_INT_IMAGE_2D_RECT iimage2DRect},
|
||||
{GL_INT_IMAGE_CUBE iimageCube},
|
||||
{GL_INT_IMAGE_BUFFER iimageBuffer},
|
||||
{GL_INT_IMAGE_1D_ARRAY iimage1DArray},
|
||||
{GL_INT_IMAGE_2D_ARRAY iimage2DArray},
|
||||
{GL_INT_IMAGE_2D_MULTISAMPLE iimage2DMS},
|
||||
{GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY iimage2DMSArray},
|
||||
{GL_UNSIGNED_INT_IMAGE_1D uimage1D},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D uimage2D},
|
||||
{GL_UNSIGNED_INT_IMAGE_3D uimage3D},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D_RECT uimage2DRect},
|
||||
{GL_UNSIGNED_INT_IMAGE_CUBE uimageCube},+ [0] {_name="fInnerRadius" _location=0 _element={_semantic=15 '\xf' _dimension=0 '\0' _type=0 '\0' } } gpu::Shader::Slot
|
||||
|
||||
{GL_UNSIGNED_INT_IMAGE_BUFFER uimageBuffer},
|
||||
{GL_UNSIGNED_INT_IMAGE_1D_ARRAY uimage1DArray},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D_ARRAY uimage2DArray},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE uimage2DMS},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY uimage2DMSArray},
|
||||
{GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint}
|
||||
*/
|
||||
default:
|
||||
return ElementResource(Element(), Resource::BUFFER);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) {
|
||||
GLint uniformsCount = 0;
|
||||
|
||||
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount);
|
||||
|
||||
for (int i = 0; i < uniformsCount; i++) {
|
||||
const GLint NAME_LENGTH = 256;
|
||||
GLchar name[NAME_LENGTH];
|
||||
GLint length = 0;
|
||||
GLint size = 0;
|
||||
GLenum type = 0;
|
||||
glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
||||
GLint location = glGetUniformLocation(glprogram, name);
|
||||
const GLint INVALID_UNIFORM_LOCATION = -1;
|
||||
|
||||
// Try to make sense of the gltype
|
||||
auto elementResource = getFormatFromGLUniform(type);
|
||||
|
||||
// The uniform as a standard var type
|
||||
if (location != INVALID_UNIFORM_LOCATION) {
|
||||
if (elementResource._resource == Resource::BUFFER) {
|
||||
uniforms.insert(Shader::Slot(name, location, elementResource._element, elementResource._resource));
|
||||
} else {
|
||||
// For texture/Sampler, the location is the actual binding value
|
||||
GLint binding = -1;
|
||||
glGetUniformiv(glprogram, location, &binding);
|
||||
|
||||
auto requestedBinding = slotBindings.find(std::string(name));
|
||||
if (requestedBinding != slotBindings.end()) {
|
||||
if (binding != (*requestedBinding)._location) {
|
||||
binding = (*requestedBinding)._location;
|
||||
glUniform1i(location, binding);
|
||||
}
|
||||
}
|
||||
|
||||
textures.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource));
|
||||
samplers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return uniformsCount;
|
||||
}
|
||||
|
||||
const GLint UNUSED_SLOT = -1;
|
||||
bool isUnusedSlot(GLint binding) {
|
||||
return (binding == UNUSED_SLOT);
|
||||
}
|
||||
|
||||
int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) {
|
||||
GLint buffersCount = 0;
|
||||
#if defined(Q_OS_WIN)
|
||||
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount);
|
||||
|
||||
// fast exit
|
||||
if (buffersCount == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLint maxNumUniformBufferSlots = 0;
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxNumUniformBufferSlots);
|
||||
std::vector<GLint> uniformBufferSlotMap(maxNumUniformBufferSlots, -1);
|
||||
|
||||
for (int i = 0; i < buffersCount; i++) {
|
||||
const GLint NAME_LENGTH = 256;
|
||||
GLchar name[NAME_LENGTH];
|
||||
GLint length = 0;
|
||||
GLint size = 0;
|
||||
GLenum type = 0;
|
||||
GLint binding = -1;
|
||||
|
||||
glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length);
|
||||
glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, name);
|
||||
glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_BINDING, &binding);
|
||||
glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_DATA_SIZE, &size);
|
||||
|
||||
GLuint blockIndex = glGetUniformBlockIndex(glprogram, name);
|
||||
|
||||
// CHeck if there is a requested binding for this block
|
||||
auto requestedBinding = slotBindings.find(std::string(name));
|
||||
if (requestedBinding != slotBindings.end()) {
|
||||
// If yes force it
|
||||
if (binding != (*requestedBinding)._location) {
|
||||
binding = (*requestedBinding)._location;
|
||||
glUniformBlockBinding(glprogram, blockIndex, binding);
|
||||
}
|
||||
} else if (binding == 0) {
|
||||
// If no binding was assigned then just do it finding a free slot
|
||||
auto slotIt = std::find_if(uniformBufferSlotMap.begin(), uniformBufferSlotMap.end(), isUnusedSlot);
|
||||
if (slotIt != uniformBufferSlotMap.end()) {
|
||||
binding = slotIt - uniformBufferSlotMap.begin();
|
||||
glUniformBlockBinding(glprogram, blockIndex, binding);
|
||||
} else {
|
||||
// This should neve happen, an active ubo cannot find an available slot among the max available?!
|
||||
binding = -1;
|
||||
}
|
||||
}
|
||||
// If binding is valid record it
|
||||
if (binding >= 0) {
|
||||
uniformBufferSlotMap[binding] = blockIndex;
|
||||
}
|
||||
|
||||
Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER);
|
||||
buffers.insert(Shader::Slot(name, binding, element, Resource::BUFFER));
|
||||
}
|
||||
#endif
|
||||
return buffersCount;
|
||||
}
|
||||
|
||||
int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs) {
|
||||
GLint inputsCount = 0;
|
||||
|
||||
glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &inputsCount);
|
||||
|
||||
for (int i = 0; i < inputsCount; i++) {
|
||||
const GLint NAME_LENGTH = 256;
|
||||
GLchar name[NAME_LENGTH];
|
||||
GLint length = 0;
|
||||
GLint size = 0;
|
||||
GLenum type = 0;
|
||||
glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
||||
|
||||
GLint binding = glGetAttribLocation(glprogram, name);
|
||||
|
||||
auto elementResource = getFormatFromGLUniform(type);
|
||||
inputs.insert(Shader::Slot(name, binding, elementResource._element, -1));
|
||||
}
|
||||
|
||||
return inputsCount;
|
||||
}
|
||||
|
||||
int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs) {
|
||||
/* GLint outputsCount = 0;
|
||||
|
||||
glGetProgramiv(glprogram, GL_ACTIVE_, &outputsCount);
|
||||
|
||||
for (int i = 0; i < inputsCount; i++) {
|
||||
const GLint NAME_LENGTH = 256;
|
||||
GLchar name[NAME_LENGTH];
|
||||
GLint length = 0;
|
||||
GLint size = 0;
|
||||
GLenum type = 0;
|
||||
glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
||||
|
||||
auto element = getFormatFromGLUniform(type);
|
||||
outputs.insert(Shader::Slot(name, i, element));
|
||||
}
|
||||
*/
|
||||
return 0; //inputsCount;
|
||||
}
|
||||
|
||||
bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) {
|
||||
|
||||
// First make sure the Shader has been compiled
|
||||
GLShader* object = GLBackend::syncGPUObject(shader);
|
||||
if (!object) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (object->_program) {
|
||||
Shader::SlotSet buffers;
|
||||
makeUniformBlockSlots(object->_program, slotBindings, buffers);
|
||||
|
||||
Shader::SlotSet uniforms;
|
||||
Shader::SlotSet textures;
|
||||
Shader::SlotSet samplers;
|
||||
makeUniformSlots(object->_program, slotBindings, uniforms, textures, samplers);
|
||||
|
||||
Shader::SlotSet inputs;
|
||||
makeInputSlots(object->_program, slotBindings, inputs);
|
||||
|
||||
Shader::SlotSet outputs;
|
||||
makeOutputSlots(object->_program, slotBindings, outputs);
|
||||
|
||||
shader.defineSlots(uniforms, buffers, textures, samplers, inputs, outputs);
|
||||
|
||||
} else if (object->_shader) {
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -223,7 +223,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
void GLBackend::syncGPUObject(const Texture& texture) {
|
||||
GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) {
|
||||
GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(texture);
|
||||
|
||||
// If GPU object already created and in sync
|
||||
|
@ -232,14 +232,14 @@ void GLBackend::syncGPUObject(const Texture& texture) {
|
|||
// If gpu object info is in sync with sysmem version
|
||||
if (object->_contentStamp >= texture.getDataStamp()) {
|
||||
// Then all good, GPU object is ready to be used
|
||||
return;
|
||||
return object;
|
||||
} else {
|
||||
// Need to update the content of the GPU object from the source sysmem of the texture
|
||||
needUpdate = true;
|
||||
}
|
||||
} else if (!texture.isDefined()) {
|
||||
// NO texture definition yet so let's avoid thinking
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// need to have a gpu object?
|
||||
|
@ -320,6 +320,8 @@ void GLBackend::syncGPUObject(const Texture& texture) {
|
|||
qDebug() << "GLBackend::syncGPUObject(const Texture&) case for Texture Type " << texture.getType() << " not supported";
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
|
@ -328,8 +330,7 @@ GLuint GLBackend::getTextureID(const TexturePointer& texture) {
|
|||
if (!texture) {
|
||||
return 0;
|
||||
}
|
||||
GLBackend::syncGPUObject(*texture);
|
||||
GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texture);
|
||||
GLTexture* object = GLBackend::syncGPUObject(*texture);
|
||||
if (object) {
|
||||
return object->_texture;
|
||||
} else {
|
||||
|
|
156
libraries/gpu/src/gpu/GLBackendTransform.cpp
Executable file
156
libraries/gpu/src/gpu/GLBackendTransform.cpp
Executable file
|
@ -0,0 +1,156 @@
|
|||
//
|
||||
// GLBackendTransform.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLBackendShared.h"
|
||||
|
||||
#include "Format.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
// Transform Stage
|
||||
|
||||
void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) {
|
||||
_transform._model = batch._transforms.get(batch._params[paramOffset]._uint);
|
||||
_transform._invalidModel = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) {
|
||||
_transform._view = batch._transforms.get(batch._params[paramOffset]._uint);
|
||||
_transform._invalidView = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) {
|
||||
memcpy(&_transform._projection, batch.editData(batch._params[paramOffset]._uint), sizeof(Mat4));
|
||||
_transform._invalidProj = true;
|
||||
}
|
||||
|
||||
void GLBackend::initTransform() {
|
||||
#if defined(Q_OS_WIN)
|
||||
glGenBuffers(1, &_transform._transformObjectBuffer);
|
||||
glGenBuffers(1, &_transform._transformCameraBuffer);
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformObjectBuffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, _transform._transformCameraBuffer);
|
||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW);
|
||||
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLBackend::killTransform() {
|
||||
#if defined(Q_OS_WIN)
|
||||
glDeleteBuffers(1, &_transform._transformObjectBuffer);
|
||||
glDeleteBuffers(1, &_transform._transformCameraBuffer);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
void GLBackend::updateTransform() {
|
||||
// Check all the dirty flags and update the state accordingly
|
||||
if (_transform._invalidProj) {
|
||||
_transform._transformCamera._projection = _transform._projection;
|
||||
}
|
||||
|
||||
if (_transform._invalidView) {
|
||||
_transform._view.getInverseMatrix(_transform._transformCamera._view);
|
||||
_transform._view.getMatrix(_transform._transformCamera._viewInverse);
|
||||
}
|
||||
|
||||
if (_transform._invalidModel) {
|
||||
_transform._model.getMatrix(_transform._transformObject._model);
|
||||
_transform._model.getInverseMatrix(_transform._transformObject._modelInverse);
|
||||
}
|
||||
|
||||
if (_transform._invalidView || _transform._invalidProj) {
|
||||
Mat4 viewUntranslated = _transform._transformCamera._view;
|
||||
viewUntranslated[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
_transform._transformCamera._projectionViewUntranslated = _transform._transformCamera._projection * viewUntranslated;
|
||||
}
|
||||
|
||||
if (_transform._invalidView || _transform._invalidProj) {
|
||||
#if defined(Q_OS_WIN)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _transform._transformCameraBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
CHECK_GL_ERROR();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_transform._invalidModel) {
|
||||
#if defined(Q_OS_WIN)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _transform._transformObjectBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
CHECK_GL_ERROR();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._transformObjectBuffer);
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, _transform._transformCameraBuffer);
|
||||
CHECK_GL_ERROR();
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
|
||||
// Do it again for fixed pipeline until we can get rid of it
|
||||
if (_transform._invalidProj) {
|
||||
if (_transform._lastMode != GL_PROJECTION) {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
_transform._lastMode = GL_PROJECTION;
|
||||
}
|
||||
glLoadMatrixf(reinterpret_cast< const GLfloat* >(&_transform._projection));
|
||||
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
if (_transform._invalidModel || _transform._invalidView) {
|
||||
if (!_transform._model.isIdentity()) {
|
||||
if (_transform._lastMode != GL_MODELVIEW) {
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
_transform._lastMode = GL_MODELVIEW;
|
||||
}
|
||||
Transform::Mat4 modelView;
|
||||
if (!_transform._view.isIdentity()) {
|
||||
Transform mvx;
|
||||
Transform::inverseMult(mvx, _transform._view, _transform._model);
|
||||
mvx.getMatrix(modelView);
|
||||
} else {
|
||||
_transform._model.getMatrix(modelView);
|
||||
}
|
||||
glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));
|
||||
} else {
|
||||
if (!_transform._view.isIdentity()) {
|
||||
if (_transform._lastMode != GL_MODELVIEW) {
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
_transform._lastMode = GL_MODELVIEW;
|
||||
}
|
||||
Transform::Mat4 modelView;
|
||||
_transform._view.getInverseMatrix(modelView);
|
||||
glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView));
|
||||
} else {
|
||||
// TODO: eventually do something about the matrix when neither view nor model is specified?
|
||||
// glLoadIdentity();
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Flags are clean
|
||||
_transform._invalidView = _transform._invalidProj = _transform._invalidModel = false;
|
||||
}
|
||||
|
||||
|
34
libraries/gpu/src/gpu/Pipeline.cpp
Executable file
34
libraries/gpu/src/gpu/Pipeline.cpp
Executable file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// Pipeline.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Pipeline.h"
|
||||
#include <math.h>
|
||||
#include <QDebug>
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
Pipeline::Pipeline():
|
||||
_program(),
|
||||
_states()
|
||||
{
|
||||
}
|
||||
|
||||
Pipeline::~Pipeline()
|
||||
{
|
||||
}
|
||||
|
||||
Pipeline* Pipeline::create(const ShaderPointer& program, const States& states) {
|
||||
Pipeline* pipeline = new Pipeline();
|
||||
pipeline->_program = program;
|
||||
pipeline->_states = states;
|
||||
|
||||
return pipeline;
|
||||
}
|
53
libraries/gpu/src/gpu/Pipeline.h
Executable file
53
libraries/gpu/src/gpu/Pipeline.h
Executable file
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// Pipeline.h
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_gpu_Pipeline_h
|
||||
#define hifi_gpu_Pipeline_h
|
||||
|
||||
#include "Resource.h"
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include "Shader.h"
|
||||
#include "State.h"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
class Pipeline {
|
||||
public:
|
||||
static Pipeline* create(const ShaderPointer& program, const States& states);
|
||||
~Pipeline();
|
||||
|
||||
const ShaderPointer& getProgram() const { return _program; }
|
||||
|
||||
const States& getStates() const { return _states; }
|
||||
|
||||
protected:
|
||||
ShaderPointer _program;
|
||||
States _states;
|
||||
|
||||
Pipeline();
|
||||
Pipeline(const Pipeline& pipeline); // deep copy of the sysmem shader
|
||||
Pipeline& operator=(const Pipeline& pipeline); // deep copy of the sysmem texture
|
||||
|
||||
// This shouldn't be used by anything else than the Backend class with the proper casting.
|
||||
mutable GPUObject* _gpuObject = NULL;
|
||||
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
|
||||
GPUObject* getGPUObject() const { return _gpuObject; }
|
||||
friend class Backend;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr< Pipeline > PipelinePointer;
|
||||
typedef std::vector< PipelinePointer > Pipelines;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -38,6 +38,18 @@ public:
|
|||
// The size in bytes of data stored in the resource
|
||||
virtual Size getSize() const = 0;
|
||||
|
||||
enum Type {
|
||||
BUFFER = 0,
|
||||
TEXTURE_1D,
|
||||
TEXTURE_2D,
|
||||
TEXTURE_3D,
|
||||
TEXTURE_CUBE,
|
||||
TEXTURE_1D_ARRAY,
|
||||
TEXTURE_2D_ARRAY,
|
||||
TEXTURE_3D_ARRAY,
|
||||
TEXTURE_CUBE_ARRAY,
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
Resource() {}
|
||||
|
@ -140,12 +152,11 @@ protected:
|
|||
|
||||
Sysmem* _sysmem = NULL;
|
||||
|
||||
mutable GPUObject* _gpuObject = NULL;
|
||||
|
||||
// This shouldn't be used by anything else than the Backend class with the proper casting.
|
||||
mutable GPUObject* _gpuObject = NULL;
|
||||
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
|
||||
GPUObject* getGPUObject() const { return _gpuObject; }
|
||||
|
||||
friend class Backend;
|
||||
};
|
||||
|
||||
|
|
73
libraries/gpu/src/gpu/Shader.cpp
Executable file
73
libraries/gpu/src/gpu/Shader.cpp
Executable file
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// Shader.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 2/27/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Shader.h"
|
||||
#include <math.h>
|
||||
#include <QDebug>
|
||||
|
||||
#include "Context.h"
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
Shader::Shader(Type type, const Source& source):
|
||||
_source(source),
|
||||
_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
Shader::Shader(Type type, Pointer& vertex, Pointer& pixel):
|
||||
_type(type)
|
||||
{
|
||||
_shaders.resize(2);
|
||||
_shaders[VERTEX] = vertex;
|
||||
_shaders[PIXEL] = pixel;
|
||||
}
|
||||
|
||||
|
||||
Shader::~Shader()
|
||||
{
|
||||
}
|
||||
|
||||
Shader* Shader::createVertex(const Source& source) {
|
||||
Shader* shader = new Shader(VERTEX, source);
|
||||
return shader;
|
||||
}
|
||||
|
||||
Shader* Shader::createPixel(const Source& source) {
|
||||
Shader* shader = new Shader(PIXEL, source);
|
||||
return shader;
|
||||
}
|
||||
|
||||
Shader* Shader::createProgram(Pointer& vertexShader, Pointer& pixelShader) {
|
||||
if (vertexShader && vertexShader->getType() == VERTEX) {
|
||||
if (pixelShader && pixelShader->getType() == PIXEL) {
|
||||
Shader* shader = new Shader(PROGRAM, vertexShader, pixelShader);
|
||||
return shader;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& buffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) {
|
||||
_uniforms = uniforms;
|
||||
_buffers = buffers;
|
||||
_textures = textures;
|
||||
_samplers = samplers;
|
||||
_inputs = inputs;
|
||||
_outputs = outputs;
|
||||
}
|
||||
|
||||
bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
|
||||
if (shader.isProgram()) {
|
||||
return Context::makeProgram(shader, bindings);
|
||||
}
|
||||
return false;
|
||||
}
|
165
libraries/gpu/src/gpu/Shader.h
Executable file
165
libraries/gpu/src/gpu/Shader.h
Executable file
|
@ -0,0 +1,165 @@
|
|||
//
|
||||
// Shader.h
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 2/27/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_gpu_Shader_h
|
||||
#define hifi_gpu_Shader_h
|
||||
|
||||
#include "Resource.h"
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
namespace gpu {
|
||||
|
||||
class Shader {
|
||||
public:
|
||||
|
||||
typedef QSharedPointer< Shader > Pointer;
|
||||
typedef std::vector< Pointer > Shaders;
|
||||
|
||||
class Source {
|
||||
public:
|
||||
enum Language {
|
||||
GLSL = 0,
|
||||
};
|
||||
|
||||
Source() {}
|
||||
Source(const std::string& code, Language lang = GLSL) : _code(code), _lang(lang) {}
|
||||
Source(const Source& source) : _code(source._code), _lang(source._lang) {}
|
||||
virtual ~Source() {}
|
||||
|
||||
virtual const std::string& getCode() const { return _code; }
|
||||
|
||||
protected:
|
||||
std::string _code;
|
||||
Language _lang = GLSL;
|
||||
};
|
||||
|
||||
class Slot {
|
||||
public:
|
||||
|
||||
std::string _name;
|
||||
uint32 _location;
|
||||
Element _element;
|
||||
uint16 _resourceType;
|
||||
|
||||
Slot(const std::string& name, uint16 location, const Element& element, uint16 resourceType = Resource::BUFFER) :
|
||||
_name(name), _location(location), _element(element), _resourceType(resourceType) {}
|
||||
|
||||
};
|
||||
|
||||
class Binding {
|
||||
public:
|
||||
std::string _name;
|
||||
uint32 _location;
|
||||
Binding(const std::string&& name, uint32 loc = 0) : _name(name), _location(loc) {}
|
||||
};
|
||||
|
||||
template <typename T> class Less {
|
||||
public:
|
||||
bool operator() (const T& x, const T& y) const { return x._name < y._name; }
|
||||
};
|
||||
typedef std::set<Slot, Less<Slot>> SlotSet;
|
||||
typedef std::set<Binding, Less<Binding>> BindingSet;
|
||||
|
||||
|
||||
enum Type {
|
||||
VERTEX = 0,
|
||||
PIXEL,
|
||||
GEOMETRY,
|
||||
NUM_DOMAINS,
|
||||
|
||||
PROGRAM,
|
||||
};
|
||||
|
||||
static Shader* createVertex(const Source& source);
|
||||
static Shader* createPixel(const Source& source);
|
||||
|
||||
static Shader* createProgram(Pointer& vertexShader, Pointer& pixelShader);
|
||||
|
||||
|
||||
~Shader();
|
||||
|
||||
Type getType() const { return _type; }
|
||||
bool isProgram() const { return getType() > NUM_DOMAINS; }
|
||||
bool isDomain() const { return getType() < NUM_DOMAINS; }
|
||||
|
||||
const Source& getSource() const { return _source; }
|
||||
|
||||
const Shaders& getShaders() const { return _shaders; }
|
||||
|
||||
// Access the exposed uniform, input and output slot
|
||||
const SlotSet& getUniforms() const { return _uniforms; }
|
||||
const SlotSet& getBuffers() const { return _buffers; }
|
||||
const SlotSet& getTextures() const { return _textures; }
|
||||
const SlotSet& getSamplers() const { return _samplers; }
|
||||
|
||||
const SlotSet& getInputs() const { return _inputs; }
|
||||
const SlotSet& getOutputs() const { return _outputs; }
|
||||
|
||||
// Define the list of uniforms, inputs and outputs for the shader
|
||||
// This call is intendend to build the list of exposed slots in order
|
||||
// to correctly bind resource to the shader.
|
||||
// These can be build "manually" from knowledge of the atual shader code
|
||||
// or automatically by calling "makeShader()", this is the preferred way
|
||||
void defineSlots(const SlotSet& uniforms, const SlotSet& buffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs);
|
||||
|
||||
// makeProgram(...) make a program shader ready to be used in a Batch.
|
||||
// It compiles the sub shaders, link them and defines the Slots and their bindings.
|
||||
// If the shader passed is not a program, nothing happens.
|
||||
//
|
||||
// It is possible to provide a set of slot bindings (from the name of the slot to a unit number) allowing
|
||||
// to make sure slots with the same semantics can be always bound on the same location from shader to shader.
|
||||
// For example, the "diffuseMap" can always be bound to texture unit #1 for different shaders by specifying a Binding("diffuseMap", 1)
|
||||
//
|
||||
// As of now (03/2015), the call to makeProgram is in fact calling gpu::Context::makeProgram and does rely
|
||||
// on the underneath gpu::Context::Backend available. Since we only support glsl, this means that it relies
|
||||
// on a glContext and the driver to compile the glsl shader.
|
||||
// Hoppefully in a few years the shader compilation will be completely abstracted in a separate shader compiler library
|
||||
// independant of the graphics api in use underneath (looking at you opengl & vulkan).
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet());
|
||||
|
||||
protected:
|
||||
Shader(Type type, const Source& source);
|
||||
Shader(Type type, Pointer& vertex, Pointer& pixel);
|
||||
|
||||
Shader(const Shader& shader); // deep copy of the sysmem shader
|
||||
Shader& operator=(const Shader& shader); // deep copy of the sysmem texture
|
||||
|
||||
// Source contains the actual source code or nothing if the shader is a program
|
||||
Source _source;
|
||||
|
||||
// if shader is composed of sub shaders, here they are
|
||||
Shaders _shaders;
|
||||
|
||||
// List of exposed uniform, input and output slots
|
||||
SlotSet _uniforms;
|
||||
SlotSet _buffers;
|
||||
SlotSet _textures;
|
||||
SlotSet _samplers;
|
||||
SlotSet _inputs;
|
||||
SlotSet _outputs;
|
||||
|
||||
// The type of the shader, the master key
|
||||
Type _type;
|
||||
|
||||
// This shouldn't be used by anything else than the Backend class with the proper casting.
|
||||
mutable GPUObject* _gpuObject = NULL;
|
||||
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
|
||||
GPUObject* getGPUObject() const { return _gpuObject; }
|
||||
friend class Backend;
|
||||
};
|
||||
|
||||
typedef Shader::Pointer ShaderPointer;
|
||||
typedef std::vector< ShaderPointer > Shaders;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
20
libraries/gpu/src/gpu/State.cpp
Executable file
20
libraries/gpu/src/gpu/State.cpp
Executable file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// State.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "State.h"
|
||||
#include <QDebug>
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
|
||||
State::~State()
|
||||
{
|
||||
}
|
88
libraries/gpu/src/gpu/State.h
Executable file
88
libraries/gpu/src/gpu/State.h
Executable file
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// Pipeline.h
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_gpu_State_h
|
||||
#define hifi_gpu_State_h
|
||||
|
||||
#include "Format.h"
|
||||
#include <vector>
|
||||
#include <QSharedPointer>
|
||||
|
||||
|
||||
namespace gpu {
|
||||
|
||||
class GPUObject;
|
||||
|
||||
class State {
|
||||
public:
|
||||
State() {}
|
||||
virtual ~State();
|
||||
|
||||
// Work in progress, not used
|
||||
/*
|
||||
enum Field {
|
||||
FILL_MODE,
|
||||
CULL_MODE,
|
||||
DEPTH_BIAS,
|
||||
DEPTH_BIAS_CLAMP,
|
||||
DEPTH_BIASSLOPE_SCALE,
|
||||
|
||||
FRONT_CLOCKWISE,
|
||||
DEPTH_CLIP_ENABLE,
|
||||
SCISSR_ENABLE,
|
||||
MULTISAMPLE_ENABLE,
|
||||
ANTIALISED_LINE_ENABLE,
|
||||
|
||||
DEPTH_ENABLE,
|
||||
DEPTH_WRITE_MASK,
|
||||
DEPTH_FUNCTION,
|
||||
|
||||
STENCIL_ENABLE,
|
||||
STENCIL_READ_MASK,
|
||||
STENCIL_WRITE_MASK,
|
||||
STENCIL_FUNCTION_FRONT,
|
||||
STENCIL_FUNCTION_BACK,
|
||||
STENCIL_REFERENCE,
|
||||
|
||||
BLEND_INDEPENDANT_ENABLE,
|
||||
BLEND_ENABLE,
|
||||
BLEND_SOURCE,
|
||||
BLEND_DESTINATION,
|
||||
BLEND_OPERATION,
|
||||
BLEND_SOURCE_ALPHA,
|
||||
BLEND_DESTINATION_ALPHA,
|
||||
BLEND_OPERATION_ALPHA,
|
||||
BLEND_WRITE_MASK,
|
||||
BLEND_FACTOR,
|
||||
|
||||
SAMPLE_MASK,
|
||||
|
||||
ALPHA_TO_COVERAGE_ENABLE,
|
||||
};
|
||||
*/
|
||||
|
||||
protected:
|
||||
State(const State& state);
|
||||
State& operator=(const State& state);
|
||||
|
||||
// This shouldn't be used by anything else than the Backend class with the proper casting.
|
||||
mutable GPUObject* _gpuObject = NULL;
|
||||
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
|
||||
GPUObject* getGPUObject() const { return _gpuObject; }
|
||||
friend class Backend;
|
||||
};
|
||||
|
||||
typedef QSharedPointer< State > StatePointer;
|
||||
typedef std::vector< StatePointer > States;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -207,12 +207,10 @@ protected:
|
|||
|
||||
Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices);
|
||||
|
||||
mutable GPUObject* _gpuObject = NULL;
|
||||
|
||||
// This shouldn't be used by anything else than the Backend class with the proper casting.
|
||||
mutable GPUObject* _gpuObject = NULL;
|
||||
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
|
||||
GPUObject* getGPUObject() const { return _gpuObject; }
|
||||
|
||||
friend class Backend;
|
||||
};
|
||||
|
||||
|
|
245
libraries/model/src/model/Atmosphere.slh
Executable file
245
libraries/model/src/model/Atmosphere.slh
Executable file
|
@ -0,0 +1,245 @@
|
|||
<!
|
||||
// Atmospheric.slh
|
||||
//
|
||||
// Created by Sam Gateau on 3/9/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
!>
|
||||
<@if not MODEL_ATMOSPHERE_SLH@>
|
||||
<@def MODEL_ATMOSPHERE_SLH@>
|
||||
|
||||
<!
|
||||
// Code is a modified version of:
|
||||
// http://http.developer.nvidia.com/GPUGems/gpugems_app01.html
|
||||
// Atmospheric scattering fragment shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
!>
|
||||
|
||||
struct Atmosphere {
|
||||
vec4 _invWaveLength;
|
||||
vec4 _radiuses;
|
||||
vec4 _scales;
|
||||
vec4 _scatterings;
|
||||
vec4 _control;
|
||||
};
|
||||
|
||||
const int numSamples = 2;
|
||||
|
||||
vec3 getAtmosphereInvWaveLength(Atmosphere a) { return a._invWaveLength.xyz; } // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
|
||||
float getAtmosphereInnerRadius(Atmosphere a) { return a._radiuses.x; } // The inner (planetary) radius
|
||||
float getAtmosphereOuterRadius(Atmosphere a) { return a._radiuses.y; } // The outer (atmosphere) radius
|
||||
|
||||
float getAtmosphereScale(Atmosphere a) { return a._scales.x; } // 1 / (outerRadius - innerRadius)
|
||||
float getAtmosphereScaleDepth(Atmosphere a) { return a._scales.y; } // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
|
||||
float getAtmosphereScaleOverScaleDepth(Atmosphere a) { return a._scales.z; } // scale / scaleDepth
|
||||
|
||||
vec4 getAtmosphereScattering(Atmosphere a) { return a._scatterings; } // The full Mie and Rayleigh scattering coefficients
|
||||
float getAtmosphereKrESun(Atmosphere a) { return a._scatterings.x; } // Kr * ESun
|
||||
float getAtmosphereKmESun(Atmosphere a) { return a._scatterings.y; } // Km * ESun
|
||||
float getAtmosphereKr4PI(Atmosphere a) { return a._scatterings.z; } // Kr * 4 * PI
|
||||
float getAtmosphereKm4PI(Atmosphere a) { return a._scatterings.w; } // Km * 4 * PI
|
||||
|
||||
float getAtmosphereNumSamples(Atmosphere a) { return a._control.x; } // numSamples
|
||||
vec2 getAtmosphereGAndG2(Atmosphere a) { return a._control.yz; } // g and g2
|
||||
|
||||
float atmosphereScale(float scaleDepth, float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return scaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
vec4 evalAtmosphereContribution(Atmosphere atmospheric, vec3 position, vec3 cameraPos, vec3 lightPos) {
|
||||
float fInnerRadius = getAtmosphereInnerRadius(atmospheric);
|
||||
float fSamples = getAtmosphereNumSamples(atmospheric);
|
||||
|
||||
vec3 v3InvWavelength = getAtmosphereInvWaveLength(atmospheric);
|
||||
vec4 scatteringCoefs = getAtmosphereScattering(atmospheric);
|
||||
float fKrESun = scatteringCoefs.x;
|
||||
float fKmESun = scatteringCoefs.y;
|
||||
float fKr4PI = scatteringCoefs.z;
|
||||
float fKm4PI = scatteringCoefs.w;
|
||||
|
||||
vec2 gAndg2 = getAtmosphereGAndG2(atmospheric);
|
||||
float g = gAndg2.x;
|
||||
float g2 = gAndg2.y;
|
||||
|
||||
float fScale = getAtmosphereScale(atmospheric);
|
||||
float fScaleDepth = getAtmosphereScaleDepth(atmospheric);
|
||||
float fScaleOverScaleDepth = getAtmosphereScaleOverScaleDepth(atmospheric);
|
||||
|
||||
// Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere)
|
||||
vec3 v3Pos = position;
|
||||
vec3 v3Ray = v3Pos - cameraPos;
|
||||
float fFar = length(v3Ray);
|
||||
v3Ray /= fFar;
|
||||
|
||||
// Calculate the ray's starting position, then calculate its scattering offset
|
||||
vec3 v3Start = cameraPos;
|
||||
float fHeight = length(v3Start);
|
||||
float fDepthStart = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fStartAngle = dot(v3Ray, v3Start) / fHeight;
|
||||
float fStartOffset = fDepthStart * atmosphereScale(fScaleDepth, fStartAngle);
|
||||
|
||||
// Initialize the scattering loop variables
|
||||
//gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
float fSampleLength = fFar / fSamples;
|
||||
float fScaledLength = fSampleLength * fScale;
|
||||
|
||||
vec3 v3SampleRay = v3Ray * fSampleLength;
|
||||
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
|
||||
|
||||
// Now loop through the sample rays
|
||||
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
|
||||
// int nSamples = numSamples;
|
||||
int nSamples = int(fSamples);
|
||||
for(int i=0; i<nSamples; i++)
|
||||
{
|
||||
float fHeight = length(v3SamplePoint);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fLightAngle = dot(lightPos, v3SamplePoint) / fHeight;
|
||||
float fCameraAngle = dot((v3Ray), v3SamplePoint) / fHeight * 0.99;
|
||||
float fScatter = (fStartOffset + fDepth * (atmosphereScale(fScaleDepth, fLightAngle) - atmosphereScale(fScaleDepth, fCameraAngle)));
|
||||
vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
|
||||
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
|
||||
v3SamplePoint += v3SampleRay;
|
||||
}
|
||||
|
||||
// Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
|
||||
vec3 secondaryFrontColor = v3FrontColor * fKmESun;
|
||||
vec3 frontColor = v3FrontColor * (v3InvWavelength * fKrESun);
|
||||
vec3 v3Direction = cameraPos - v3Pos;
|
||||
|
||||
float fCos = dot(lightPos, v3Direction) / length(v3Direction);
|
||||
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
|
||||
vec4 finalColor;
|
||||
|
||||
finalColor.rgb = frontColor.rgb + fMiePhase * secondaryFrontColor.rgb;
|
||||
finalColor.a = finalColor.b;
|
||||
finalColor.rgb = pow(finalColor.rgb, vec3(1.0/2.2));
|
||||
|
||||
return finalColor;
|
||||
}
|
||||
|
||||
|
||||
<@if GLPROFILE == PC_GL@>
|
||||
uniform atmosphereBuffer {
|
||||
Atmosphere _atmosphere;
|
||||
};
|
||||
Atmosphere getAtmosphere() {
|
||||
return _atmosphere;
|
||||
}
|
||||
<@else@>
|
||||
uniform vec4 atmosphereBuffer[9];
|
||||
Atmosphere getAtmosphere() {
|
||||
Atmosphere atmosphere;
|
||||
atmosphere._invWaveLength = atmosphereBuffer[0];
|
||||
atmosphere._radiuses = atmosphereBuffer[1];
|
||||
atmosphere._scales = atmosphereBuffer[2];
|
||||
atmosphere._scatterings = atmosphereBuffer[3];
|
||||
atmosphere._control = atmosphereBuffer[4];
|
||||
|
||||
return atmosphere;
|
||||
}
|
||||
<@endif@>
|
||||
|
||||
<!
|
||||
/*
|
||||
// uniform vec3 v3CameraPos; // The camera's current position
|
||||
|
||||
|
||||
const int nSamples = 2;
|
||||
const float fSamples = 2.0;
|
||||
|
||||
uniform vec3 v3LightPos;
|
||||
uniform float g;
|
||||
uniform float g2;
|
||||
|
||||
varying vec3 position;
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
void main (void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere)
|
||||
vec3 v3Pos = position;
|
||||
vec3 v3Ray = v3Pos - v3CameraPos;
|
||||
float fFar = length(v3Ray);
|
||||
v3Ray /= fFar;
|
||||
|
||||
// Calculate the ray's starting position, then calculate its scattering offset
|
||||
vec3 v3Start = v3CameraPos;
|
||||
float fHeight = length(v3Start);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fStartAngle = dot(v3Ray, v3Start) / fHeight;
|
||||
float fStartOffset = fDepth * scale(fStartAngle);
|
||||
|
||||
// Initialize the scattering loop variables
|
||||
//gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
float fSampleLength = fFar / fSamples;
|
||||
float fScaledLength = fSampleLength * fScale;
|
||||
vec3 v3SampleRay = v3Ray * fSampleLength;
|
||||
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
|
||||
|
||||
// Now loop through the sample rays
|
||||
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
|
||||
for(int i=0; i<nSamples; i++)
|
||||
{
|
||||
float fHeight = length(v3SamplePoint);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight;
|
||||
float fCameraAngle = dot((v3Ray), v3SamplePoint) / fHeight * 0.99;
|
||||
float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle)));
|
||||
vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
|
||||
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
|
||||
v3SamplePoint += v3SampleRay;
|
||||
}
|
||||
|
||||
// Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
|
||||
vec3 secondaryFrontColor = v3FrontColor * fKmESun;
|
||||
vec3 frontColor = v3FrontColor * (v3InvWavelength * fKrESun);
|
||||
vec3 v3Direction = v3CameraPos - v3Pos;
|
||||
|
||||
float fCos = dot(v3LightPos, v3Direction) / length(v3Direction);
|
||||
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
|
||||
gl_FragColor.rgb = frontColor.rgb + fMiePhase * secondaryFrontColor.rgb;
|
||||
gl_FragColor.a = gl_FragColor.b;
|
||||
gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0/2.2));
|
||||
}
|
||||
*/
|
||||
!>
|
||||
|
||||
<@endif@>
|
108
libraries/model/src/model/SkyFromAtmosphere.slf
Executable file
108
libraries/model/src/model/SkyFromAtmosphere.slf
Executable file
|
@ -0,0 +1,108 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
|
||||
//
|
||||
// Atmospheric scattering fragment shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
uniform vec3 v3CameraPos; // The camera's current position
|
||||
uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
uniform float fInnerRadius; // The inner (planetary) radius
|
||||
uniform float fKrESun; // Kr * ESun
|
||||
uniform float fKmESun; // Km * ESun
|
||||
uniform float fKr4PI; // Kr * 4 * PI
|
||||
uniform float fKm4PI; // Km * 4 * PI
|
||||
uniform float fScale; // 1 / (fOuterRadius - fInnerRadius)
|
||||
uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
|
||||
uniform float fScaleOverScaleDepth; // fScale / fScaleDepth
|
||||
|
||||
const int nSamples = 2;
|
||||
const float fSamples = 2.0;
|
||||
|
||||
uniform vec3 v3LightPos;
|
||||
uniform float g;
|
||||
uniform float g2;
|
||||
|
||||
varying vec3 position;
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
void main (void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere)
|
||||
vec3 v3Pos = position;
|
||||
vec3 v3Ray = v3Pos - v3CameraPos;
|
||||
float fFar = length(v3Ray);
|
||||
v3Ray /= fFar;
|
||||
|
||||
// Calculate the ray's starting position, then calculate its scattering offset
|
||||
vec3 v3Start = v3CameraPos;
|
||||
float fHeight = length(v3Start);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fStartAngle = dot(v3Ray, v3Start) / fHeight;
|
||||
float fStartOffset = fDepth * scale(fStartAngle);
|
||||
|
||||
// Initialize the scattering loop variables
|
||||
//gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
float fSampleLength = fFar / fSamples;
|
||||
float fScaledLength = fSampleLength * fScale;
|
||||
vec3 v3SampleRay = v3Ray * fSampleLength;
|
||||
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
|
||||
|
||||
// Now loop through the sample rays
|
||||
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
|
||||
for(int i=0; i<nSamples; i++)
|
||||
{
|
||||
float fHeight = length(v3SamplePoint);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight;
|
||||
float fCameraAngle = dot((v3Ray), v3SamplePoint) / fHeight * 0.99;
|
||||
float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle)));
|
||||
vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
|
||||
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
|
||||
v3SamplePoint += v3SampleRay;
|
||||
}
|
||||
|
||||
// Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
|
||||
vec3 secondaryFrontColor = v3FrontColor * fKmESun;
|
||||
vec3 frontColor = v3FrontColor * (v3InvWavelength * fKrESun);
|
||||
vec3 v3Direction = v3CameraPos - v3Pos;
|
||||
|
||||
float fCos = dot(v3LightPos, v3Direction) / length(v3Direction);
|
||||
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
|
||||
gl_FragColor.rgb = frontColor.rgb + fMiePhase * secondaryFrontColor.rgb;
|
||||
gl_FragColor.a = gl_FragColor.b;
|
||||
gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0/2.2));
|
||||
}
|
68
libraries/model/src/model/SkyFromAtmosphere.slv
Executable file
68
libraries/model/src/model/SkyFromAtmosphere.slv
Executable file
|
@ -0,0 +1,68 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
|
||||
//
|
||||
// Atmospheric scattering vertex shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
uniform vec3 v3CameraPos; // The camera's current position
|
||||
uniform vec3 v3LightPos; // The direction vector to the light source
|
||||
uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
uniform float fOuterRadius; // The outer (atmosphere) radius
|
||||
uniform float fInnerRadius; // The inner (planetary) radius
|
||||
uniform float fKrESun; // Kr * ESun
|
||||
uniform float fKmESun; // Km * ESun
|
||||
uniform float fKr4PI; // Kr * 4 * PI
|
||||
uniform float fKm4PI; // Km * 4 * PI
|
||||
uniform float fScale; // 1 / (fOuterRadius - fInnerRadius)
|
||||
uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
|
||||
uniform float fScaleOverScaleDepth; // fScale / fScaleDepth
|
||||
|
||||
|
||||
const int nSamples = 2;
|
||||
const float fSamples = 2.0;
|
||||
|
||||
varying vec3 position;
|
||||
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere)
|
||||
position = gl_Vertex.xyz * fOuterRadius;
|
||||
|
||||
gl_Position = gl_ModelViewProjectionMatrix * vec4(position, 1.0);
|
||||
}
|
114
libraries/model/src/model/SkyFromSpace.slf
Executable file
114
libraries/model/src/model/SkyFromSpace.slf
Executable file
|
@ -0,0 +1,114 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
|
||||
//
|
||||
// Atmospheric scattering fragment shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
uniform vec3 v3CameraPos; // The camera's current position
|
||||
uniform vec3 v3LightPos; // The direction vector to the light source
|
||||
uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels
|
||||
uniform float fCameraHeight2; // fCameraHeight^2
|
||||
uniform float fOuterRadius; // The outer (atmosphere) radius
|
||||
uniform float fOuterRadius2; // fOuterRadius^2
|
||||
uniform float fInnerRadius; // The inner (planetary) radius
|
||||
uniform float fKrESun; // Kr * ESun
|
||||
uniform float fKmESun; // Km * ESun
|
||||
uniform float fKr4PI; // Kr * 4 * PI
|
||||
uniform float fKm4PI; // Km * 4 * PI
|
||||
uniform float fScale; // 1 / (fOuterRadius - fInnerRadius)
|
||||
uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
|
||||
uniform float fScaleOverScaleDepth; // fScale / fScaleDepth
|
||||
|
||||
uniform float g;
|
||||
uniform float g2;
|
||||
|
||||
const int nSamples = 2;
|
||||
const float fSamples = 2.0;
|
||||
|
||||
varying vec3 position;
|
||||
|
||||
float scale(float fCos)
|
||||
{
|
||||
float x = 1.0 - fCos;
|
||||
return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
|
||||
}
|
||||
|
||||
|
||||
void main (void)
|
||||
{
|
||||
// Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere)
|
||||
vec3 v3Pos = position;
|
||||
vec3 v3Ray = v3Pos - v3CameraPos;
|
||||
float fFar = length(v3Ray);
|
||||
v3Ray /= fFar;
|
||||
|
||||
// Calculate the closest intersection of the ray with the outer atmosphere (which is the near point of the ray passing through the atmosphere)
|
||||
float B = 2.0 * dot(v3CameraPos, v3Ray);
|
||||
float C = fCameraHeight2 - fOuterRadius2;
|
||||
float fDet = max(0.0, B*B - 4.0 * C);
|
||||
float fNear = 0.5 * (-B - sqrt(fDet));
|
||||
|
||||
// Calculate the ray's starting position, then calculate its scattering offset
|
||||
vec3 v3Start = v3CameraPos + v3Ray * fNear;
|
||||
fFar -= fNear;
|
||||
float fStartAngle = dot(v3Ray, v3Start) / fOuterRadius;
|
||||
float fStartDepth = exp(-1.0 / fScaleDepth);
|
||||
float fStartOffset = fStartDepth * scale(fStartAngle);
|
||||
|
||||
// Initialize the scattering loop variables
|
||||
//gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
float fSampleLength = fFar / fSamples;
|
||||
float fScaledLength = fSampleLength * fScale;
|
||||
vec3 v3SampleRay = v3Ray * fSampleLength;
|
||||
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
|
||||
|
||||
// Now loop through the sample rays
|
||||
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
|
||||
for(int i=0; i<nSamples; i++)
|
||||
{
|
||||
float fHeight = length(v3SamplePoint);
|
||||
float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
|
||||
float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight;
|
||||
float fCameraAngle = dot((v3Ray), v3SamplePoint) / fHeight * 0.99;
|
||||
float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle)));
|
||||
vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
|
||||
v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
|
||||
v3SamplePoint += v3SampleRay;
|
||||
}
|
||||
vec3 v3Direction = v3CameraPos - v3Pos;
|
||||
float fCos = dot(v3LightPos, v3Direction) / length(v3Direction);
|
||||
float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
|
||||
vec3 color = v3FrontColor * (v3InvWavelength * fKrESun);
|
||||
vec3 secondaryColor = v3FrontColor * fKmESun;
|
||||
gl_FragColor.rgb = color + fMiePhase * secondaryColor;
|
||||
gl_FragColor.a = gl_FragColor.b;
|
||||
gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0/2.2));
|
||||
}
|
43
libraries/model/src/model/SkyFromSpace.slv
Executable file
43
libraries/model/src/model/SkyFromSpace.slv
Executable file
|
@ -0,0 +1,43 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html:
|
||||
//
|
||||
// NVIDIA Statement on the Software
|
||||
//
|
||||
// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are
|
||||
// detailed.
|
||||
//
|
||||
// No Warranty
|
||||
//
|
||||
// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL
|
||||
// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
//
|
||||
// Limitation of Liability
|
||||
//
|
||||
// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR
|
||||
// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT
|
||||
// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY
|
||||
// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH
|
||||
// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS.
|
||||
//
|
||||
|
||||
//
|
||||
// Atmospheric scattering vertex shader
|
||||
//
|
||||
// Author: Sean O'Neil
|
||||
//
|
||||
// Copyright (c) 2004 Sean O'Neil
|
||||
//
|
||||
|
||||
uniform float fOuterRadius; // The outer (atmosphere) radius
|
||||
|
||||
varying vec3 position;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
position = gl_Vertex.xyz * fOuterRadius;
|
||||
gl_Position = gl_ModelViewProjectionMatrix * vec4(position, 1.0);
|
||||
}
|
|
@ -13,6 +13,9 @@
|
|||
#include <glm/gtx/transform.hpp>
|
||||
#include <math.h>
|
||||
|
||||
#include "SkyFromAtmosphere_vert.h"
|
||||
#include "SkyFromAtmosphere_frag.h"
|
||||
|
||||
using namespace model;
|
||||
|
||||
|
||||
|
@ -131,6 +134,56 @@ void EarthSunModel::setSunLongitude(float lon) {
|
|||
_sunLongitude = validateLongitude(lon);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
Atmosphere::Atmosphere() {
|
||||
// only if created from nothing shall we create the Buffer to store the properties
|
||||
Data data;
|
||||
_dataBuffer = gpu::BufferView(new gpu::Buffer(sizeof(Data), (const gpu::Buffer::Byte*) &data));
|
||||
|
||||
setScatteringWavelength(_scatteringWavelength);
|
||||
setRayleighScattering(_rayleighScattering);
|
||||
setInnerOuterRadiuses(getInnerRadius(), getOuterRadius());
|
||||
}
|
||||
|
||||
void Atmosphere::setScatteringWavelength(Vec3 wavelength) {
|
||||
_scatteringWavelength = wavelength;
|
||||
Data& data = editData();
|
||||
data._invWaveLength = Vec4(1.0f / powf(wavelength.x, 4.0f), 1.0f / powf(wavelength.y, 4.0f), 1.0f / powf(wavelength.z, 4.0f), 0.0f);
|
||||
}
|
||||
|
||||
void Atmosphere::setRayleighScattering(float scattering) {
|
||||
_rayleighScattering = scattering;
|
||||
updateScattering();
|
||||
}
|
||||
|
||||
void Atmosphere::setMieScattering(float scattering) {
|
||||
_mieScattering = scattering;
|
||||
updateScattering();
|
||||
}
|
||||
|
||||
void Atmosphere::setSunBrightness(float brightness) {
|
||||
_sunBrightness = brightness;
|
||||
updateScattering();
|
||||
}
|
||||
|
||||
void Atmosphere::updateScattering() {
|
||||
Data& data = editData();
|
||||
|
||||
data._scatterings.x = getRayleighScattering() * getSunBrightness();
|
||||
data._scatterings.y = getMieScattering() * getSunBrightness();
|
||||
|
||||
data._scatterings.z = getRayleighScattering() * 4.0f * glm::pi<float>();
|
||||
data._scatterings.w = getMieScattering() * 4.0f * glm::pi<float>();
|
||||
}
|
||||
|
||||
void Atmosphere::setInnerOuterRadiuses(float inner, float outer) {
|
||||
Data& data = editData();
|
||||
data._radiuses.x = inner;
|
||||
data._radiuses.y = outer;
|
||||
data._scales.x = 1.0f / (outer - inner);
|
||||
data._scales.z = data._scales.x / data._scales.y;
|
||||
}
|
||||
|
||||
|
||||
const int NUM_DAYS_PER_YEAR = 365;
|
||||
const float NUM_HOURS_PER_DAY = 24.0f;
|
||||
|
@ -150,6 +203,12 @@ SunSkyStage::SunSkyStage() :
|
|||
setDayTime(12.0f);
|
||||
// Begining of march
|
||||
setYearTime(60.0f);
|
||||
|
||||
auto skyFromAtmosphereVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(SkyFromAtmosphere_vert)));
|
||||
auto skyFromAtmosphereFragment = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(SkyFromAtmosphere_frag)));
|
||||
auto skyShader = gpu::ShaderPointer(gpu::Shader::createProgram(skyFromAtmosphereVertex, skyFromAtmosphereFragment));
|
||||
_skyPipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, gpu::States()));
|
||||
|
||||
}
|
||||
|
||||
SunSkyStage::~SunSkyStage() {
|
||||
|
@ -205,5 +264,12 @@ void SunSkyStage::updateGraphicsObject() const {
|
|||
double originAlt = _earthSunModel.getAltitude();
|
||||
_sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f));
|
||||
|
||||
static int firstTime = 0;
|
||||
if (firstTime == 0) {
|
||||
firstTime++;
|
||||
bool result = gpu::Shader::makeProgram(*(_skyPipeline->getProgram()));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#ifndef hifi_model_Stage_h
|
||||
#define hifi_model_Stage_h
|
||||
|
||||
#include "gpu/Pipeline.h"
|
||||
|
||||
#include "Light.h"
|
||||
|
||||
namespace model {
|
||||
|
@ -104,6 +106,60 @@ protected:
|
|||
static Mat4d evalWorldToGeoLocationMat(double longitude, double latitude, double altitude, double scale);
|
||||
};
|
||||
|
||||
|
||||
class Atmosphere {
|
||||
public:
|
||||
|
||||
Atmosphere();
|
||||
Atmosphere(const Atmosphere& atmosphere);
|
||||
Atmosphere& operator= (const Atmosphere& atmosphere);
|
||||
virtual ~Atmosphere() {};
|
||||
|
||||
|
||||
void setScatteringWavelength(Vec3 wavelength);
|
||||
const Vec3& getScatteringWavelength() const { return _scatteringWavelength; }
|
||||
|
||||
void setRayleighScattering(float scattering);
|
||||
float getRayleighScattering() const { return _rayleighScattering; }
|
||||
|
||||
void setMieScattering(float scattering);
|
||||
float getMieScattering() const { return _mieScattering; }
|
||||
|
||||
void setSunBrightness(float brightness);
|
||||
float getSunBrightness() const { return _sunBrightness; }
|
||||
|
||||
void setInnerOuterRadiuses(float inner, float outer);
|
||||
float getInnerRadius() const { return getData()._radiuses.x; }
|
||||
float getOuterRadius() const { return getData()._radiuses.y; }
|
||||
|
||||
// Data to access the attribute values of the atmosphere
|
||||
class Data {
|
||||
public:
|
||||
Vec4 _invWaveLength = Vec4(0.0f);
|
||||
Vec4 _radiuses = Vec4(6000.0f, 6025.0f, 0.0f, 0.0f);
|
||||
Vec4 _scales = Vec4(0.0f, 0.25f, 0.0f, 0.0f);
|
||||
Vec4 _scatterings = Vec4(0.0f);
|
||||
Vec4 _control = Vec4(2.0f, -0.990f, -0.990f*-0.990f, 0.f);
|
||||
|
||||
Data() {}
|
||||
};
|
||||
|
||||
const UniformBufferView& getDataBuffer() const { return _dataBuffer; }
|
||||
|
||||
protected:
|
||||
UniformBufferView _dataBuffer;
|
||||
Vec3 _scatteringWavelength = Vec3(0.650f, 0.570f, 0.475f);
|
||||
float _rayleighScattering = 0.0025f;
|
||||
float _mieScattering = 0.0010f;
|
||||
float _sunBrightness = 20.0f;
|
||||
|
||||
const Data& getData() const { return _dataBuffer.get<Data>(); }
|
||||
Data& editData() { return _dataBuffer.edit<Data>(); }
|
||||
|
||||
void updateScattering();
|
||||
};
|
||||
typedef QSharedPointer< Atmosphere > AtmospherePointer;
|
||||
|
||||
// Sun sky stage generates the rendering primitives to display a scene realistically
|
||||
// at the specified location and time around earth
|
||||
class SunSkyStage {
|
||||
|
@ -139,9 +195,13 @@ public:
|
|||
float getSunIntensity() const { return getSunLight()->getIntensity(); }
|
||||
|
||||
LightPointer getSunLight() const { valid(); return _sunLight; }
|
||||
AtmospherePointer getAtmosphere() const { valid(); return _atmosphere; }
|
||||
|
||||
protected:
|
||||
LightPointer _sunLight;
|
||||
AtmospherePointer _atmosphere;
|
||||
|
||||
gpu::PipelinePointer _skyPipeline;
|
||||
|
||||
float _dayTime;
|
||||
int _yearTime;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <QtCore/QUrlQuery>
|
||||
#include <QtNetwork/QHttpMultiPart>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QEventLoop>
|
||||
#include <qthread.h>
|
||||
|
||||
#include <SettingHandle.h>
|
||||
|
@ -299,6 +300,8 @@ void AccountManager::processReply() {
|
|||
passErrorToCallback(requestReply);
|
||||
}
|
||||
delete requestReply;
|
||||
|
||||
emit replyFinished();
|
||||
}
|
||||
|
||||
void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) {
|
||||
|
@ -339,6 +342,15 @@ void AccountManager::passErrorToCallback(QNetworkReply* requestReply) {
|
|||
}
|
||||
}
|
||||
|
||||
void AccountManager::waitForAllPendingReplies() {
|
||||
while (_pendingCallbackMap.size() > 0) {
|
||||
QEventLoop loop;
|
||||
QObject::connect(this, &AccountManager::replyFinished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AccountManager::persistAccountToSettings() {
|
||||
if (_shouldPersistToSettingsFile) {
|
||||
// store this access token into the local settings
|
||||
|
|
|
@ -72,6 +72,8 @@ public:
|
|||
void requestProfile();
|
||||
|
||||
DataServerAccountInfo& getAccountInfo() { return _accountInfo; }
|
||||
|
||||
void waitForAllPendingReplies();
|
||||
|
||||
public slots:
|
||||
void requestAccessToken(const QString& login, const QString& password);
|
||||
|
@ -93,6 +95,8 @@ signals:
|
|||
void loginFailed();
|
||||
void logoutComplete();
|
||||
void balanceChanged(qint64 newBalance);
|
||||
void replyFinished();
|
||||
|
||||
private slots:
|
||||
void processReply();
|
||||
void handleKeypairGenerationError();
|
||||
|
|
|
@ -61,7 +61,7 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall
|
|||
params.errorCallbackReceiver = this;
|
||||
params.errorCallbackMethod = "requestError";
|
||||
}
|
||||
|
||||
|
||||
accountManager.authenticatedRequest(USER_ACTIVITY_URL,
|
||||
QNetworkAccessManager::PostOperation,
|
||||
params,
|
||||
|
@ -89,6 +89,8 @@ void UserActivityLogger::launch(QString applicationVersion) {
|
|||
void UserActivityLogger::close() {
|
||||
const QString ACTION_NAME = "close";
|
||||
logAction(ACTION_NAME, QJsonObject());
|
||||
|
||||
AccountManager::getInstance().waitForAllPendingReplies();
|
||||
}
|
||||
|
||||
void UserActivityLogger::changedDisplayName(QString displayName) {
|
||||
|
|
|
@ -18,12 +18,20 @@
|
|||
#include <cmath>
|
||||
#include <fstream> // to load voxels from file
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QDebug>
|
||||
#include <QEventLoop>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QVector>
|
||||
|
||||
#include <GeometryUtil.h>
|
||||
#include <OctalCode.h>
|
||||
#include <LogHandler.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <OctalCode.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <Shape.h>
|
||||
|
@ -1836,141 +1844,184 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
|
|||
bool Octree::readFromSVOFile(const char* fileName) {
|
||||
bool fileOk = false;
|
||||
|
||||
PacketVersion gotVersion = 0;
|
||||
std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate);
|
||||
QFile file(fileName);
|
||||
fileOk = file.open(QIODevice::ReadOnly);
|
||||
|
||||
if(fileOk) {
|
||||
QDataStream fileInputStream(&file);
|
||||
QFileInfo fileInfo(fileName);
|
||||
unsigned long fileLength = fileInfo.size();
|
||||
|
||||
if(file.is_open()) {
|
||||
emit importSize(1.0f, 1.0f, 1.0f);
|
||||
emit importProgress(0);
|
||||
|
||||
qDebug("Loading file %s...", fileName);
|
||||
|
||||
fileOk = readFromStream(fileLength, fileInputStream);
|
||||
|
||||
// get file length....
|
||||
unsigned long fileLength = file.tellg();
|
||||
file.seekg( 0, std::ios::beg );
|
||||
emit importProgress(100);
|
||||
file.close();
|
||||
}
|
||||
|
||||
return fileOk;
|
||||
}
|
||||
|
||||
bool Octree::readFromSVOURL(const QString& urlString) {
|
||||
bool readOk = false;
|
||||
|
||||
// determine if this is a local file or a network resource
|
||||
QUrl url(urlString);
|
||||
|
||||
if (url.isLocalFile()) {
|
||||
readOk = readFromSVOFile(qPrintable(url.toLocalFile()));
|
||||
} else {
|
||||
QNetworkRequest request;
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
request.setUrl(url);
|
||||
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkReply* reply = networkAccessManager.get(request);
|
||||
|
||||
qDebug() << "Downloading svo at" << qPrintable(urlString);
|
||||
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||
loop.exec();
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
int resourceSize = reply->bytesAvailable();
|
||||
QDataStream inputStream(reply);
|
||||
readOk = readFromStream(resourceSize, inputStream);
|
||||
}
|
||||
}
|
||||
return readOk;
|
||||
}
|
||||
|
||||
|
||||
bool Octree::readFromStream(unsigned long streamLength, QDataStream& inputStream) {
|
||||
bool fileOk = false;
|
||||
|
||||
PacketVersion gotVersion = 0;
|
||||
|
||||
unsigned long headerLength = 0; // bytes in the header
|
||||
|
||||
bool wantImportProgress = true;
|
||||
|
||||
PacketType expectedType = expectedDataPacketType();
|
||||
PacketVersion expectedVersion = versionForPacketType(expectedType);
|
||||
bool hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion);
|
||||
|
||||
// before reading the file, check to see if this version of the Octree supports file versions
|
||||
if (getWantSVOfileVersions()) {
|
||||
|
||||
// read just enough of the file to parse the header...
|
||||
const unsigned long HEADER_LENGTH = sizeof(PacketType) + sizeof(PacketVersion);
|
||||
unsigned char fileHeader[HEADER_LENGTH];
|
||||
inputStream.readRawData((char*)&fileHeader, HEADER_LENGTH);
|
||||
|
||||
unsigned long headerLength = 0; // bytes in the header
|
||||
headerLength = HEADER_LENGTH; // we need this later to skip to the data
|
||||
|
||||
unsigned char* dataAt = (unsigned char*)&fileHeader;
|
||||
unsigned long dataLength = HEADER_LENGTH;
|
||||
|
||||
// if so, read the first byte of the file and see if it matches the expected version code
|
||||
PacketType gotType;
|
||||
memcpy(&gotType, dataAt, sizeof(gotType));
|
||||
|
||||
dataAt += sizeof(expectedType);
|
||||
dataLength -= sizeof(expectedType);
|
||||
gotVersion = *dataAt;
|
||||
|
||||
bool wantImportProgress = true;
|
||||
if (gotType == expectedType) {
|
||||
if (canProcessVersion(gotVersion)) {
|
||||
dataAt += sizeof(gotVersion);
|
||||
dataLength -= sizeof(gotVersion);
|
||||
fileOk = true;
|
||||
qDebug("SVO file version match. Expected: %d Got: %d",
|
||||
versionForPacketType(expectedDataPacketType()), gotVersion);
|
||||
|
||||
PacketType expectedType = expectedDataPacketType();
|
||||
PacketVersion expectedVersion = versionForPacketType(expectedType);
|
||||
bool hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion);
|
||||
|
||||
// before reading the file, check to see if this version of the Octree supports file versions
|
||||
if (getWantSVOfileVersions()) {
|
||||
|
||||
// read just enough of the file to parse the header...
|
||||
const unsigned long HEADER_LENGTH = sizeof(PacketType) + sizeof(PacketVersion);
|
||||
unsigned char fileHeader[HEADER_LENGTH];
|
||||
file.read((char*)&fileHeader, HEADER_LENGTH);
|
||||
|
||||
headerLength = HEADER_LENGTH; // we need this later to skip to the data
|
||||
|
||||
unsigned char* dataAt = (unsigned char*)&fileHeader;
|
||||
unsigned long dataLength = HEADER_LENGTH;
|
||||
|
||||
// if so, read the first byte of the file and see if it matches the expected version code
|
||||
PacketType gotType;
|
||||
memcpy(&gotType, dataAt, sizeof(gotType));
|
||||
|
||||
dataAt += sizeof(expectedType);
|
||||
dataLength -= sizeof(expectedType);
|
||||
gotVersion = *dataAt;
|
||||
|
||||
if (gotType == expectedType) {
|
||||
if (canProcessVersion(gotVersion)) {
|
||||
dataAt += sizeof(gotVersion);
|
||||
dataLength -= sizeof(gotVersion);
|
||||
fileOk = true;
|
||||
qDebug("SVO file version match. Expected: %d Got: %d",
|
||||
versionForPacketType(expectedDataPacketType()), gotVersion);
|
||||
|
||||
hasBufferBreaks = versionHasSVOfileBreaks(gotVersion);
|
||||
} else {
|
||||
qDebug("SVO file version mismatch. Expected: %d Got: %d",
|
||||
versionForPacketType(expectedDataPacketType()), gotVersion);
|
||||
}
|
||||
hasBufferBreaks = versionHasSVOfileBreaks(gotVersion);
|
||||
} else {
|
||||
qDebug() << "SVO file type mismatch. Expected: " << nameForPacketType(expectedType)
|
||||
<< " Got: " << nameForPacketType(gotType);
|
||||
qDebug("SVO file version mismatch. Expected: %d Got: %d",
|
||||
versionForPacketType(expectedDataPacketType()), gotVersion);
|
||||
}
|
||||
|
||||
} else {
|
||||
qDebug() << " NOTE: this file type does not include type and version information.";
|
||||
fileOk = true; // assume the file is ok
|
||||
}
|
||||
|
||||
if (hasBufferBreaks) {
|
||||
qDebug() << " this version includes buffer breaks";
|
||||
} else {
|
||||
qDebug() << " this version does not include buffer breaks";
|
||||
qDebug() << "SVO file type mismatch. Expected: " << nameForPacketType(expectedType)
|
||||
<< " Got: " << nameForPacketType(gotType);
|
||||
}
|
||||
|
||||
if (fileOk) {
|
||||
} else {
|
||||
qDebug() << " NOTE: this file type does not include type and version information.";
|
||||
fileOk = true; // assume the file is ok
|
||||
}
|
||||
|
||||
if (hasBufferBreaks) {
|
||||
qDebug() << " this version includes buffer breaks";
|
||||
} else {
|
||||
qDebug() << " this version does not include buffer breaks";
|
||||
}
|
||||
|
||||
if (fileOk) {
|
||||
|
||||
// if this version of the file does not include buffer breaks, then we need to load the entire file at once
|
||||
if (!hasBufferBreaks) {
|
||||
|
||||
// if this version of the file does not include buffer breaks, then we need to load the entire file at once
|
||||
if (!hasBufferBreaks) {
|
||||
// read the entire file into a buffer, WHAT!? Why not.
|
||||
unsigned long dataLength = streamLength - headerLength;
|
||||
unsigned char* entireFileDataSection = new unsigned char[dataLength];
|
||||
inputStream.readRawData((char*)entireFileDataSection, dataLength);
|
||||
|
||||
unsigned char* dataAt = entireFileDataSection;
|
||||
|
||||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0,
|
||||
SharedNodePointer(), wantImportProgress, gotVersion);
|
||||
|
||||
readBitstreamToTree(dataAt, dataLength, args);
|
||||
delete[] entireFileDataSection;
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
// read the entire file into a buffer, WHAT!? Why not.
|
||||
unsigned long dataLength = fileLength - headerLength;
|
||||
unsigned char* entireFileDataSection = new unsigned char[dataLength];
|
||||
file.read((char*)entireFileDataSection, dataLength);
|
||||
unsigned char* dataAt = entireFileDataSection;
|
||||
unsigned long dataLength = streamLength - headerLength;
|
||||
unsigned long remainingLength = dataLength;
|
||||
const unsigned long MAX_CHUNK_LENGTH = MAX_OCTREE_PACKET_SIZE * 2;
|
||||
unsigned char* fileChunk = new unsigned char[MAX_CHUNK_LENGTH];
|
||||
|
||||
while (remainingLength > 0) {
|
||||
quint16 chunkLength = 0;
|
||||
|
||||
inputStream.readRawData((char*)&chunkLength, sizeof(chunkLength));
|
||||
remainingLength -= sizeof(chunkLength);
|
||||
|
||||
if (chunkLength > remainingLength) {
|
||||
qDebug() << "UNEXPECTED chunk size of:" << chunkLength
|
||||
<< "greater than remaining length:" << remainingLength;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chunkLength > MAX_CHUNK_LENGTH) {
|
||||
qDebug() << "UNEXPECTED chunk size of:" << chunkLength
|
||||
<< "greater than MAX_CHUNK_LENGTH:" << MAX_CHUNK_LENGTH;
|
||||
break;
|
||||
}
|
||||
|
||||
inputStream.readRawData((char*)fileChunk, chunkLength);
|
||||
|
||||
remainingLength -= chunkLength;
|
||||
|
||||
unsigned char* dataAt = fileChunk;
|
||||
unsigned long dataLength = chunkLength;
|
||||
|
||||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0,
|
||||
SharedNodePointer(), wantImportProgress, gotVersion);
|
||||
|
||||
readBitstreamToTree(dataAt, dataLength, args);
|
||||
delete[] entireFileDataSection;
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
unsigned long dataLength = fileLength - headerLength;
|
||||
unsigned long remainingLength = dataLength;
|
||||
const unsigned long MAX_CHUNK_LENGTH = MAX_OCTREE_PACKET_SIZE * 2;
|
||||
unsigned char* fileChunk = new unsigned char[MAX_CHUNK_LENGTH];
|
||||
|
||||
while (remainingLength > 0) {
|
||||
quint16 chunkLength = 0;
|
||||
|
||||
file.read((char*)&chunkLength, sizeof(chunkLength)); // read the chunk size from the file
|
||||
remainingLength -= sizeof(chunkLength);
|
||||
|
||||
if (chunkLength > remainingLength) {
|
||||
qDebug() << "UNEXPECTED chunk size of:" << chunkLength
|
||||
<< "greater than remaining length:" << remainingLength;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chunkLength > MAX_CHUNK_LENGTH) {
|
||||
qDebug() << "UNEXPECTED chunk size of:" << chunkLength
|
||||
<< "greater than MAX_CHUNK_LENGTH:" << MAX_CHUNK_LENGTH;
|
||||
break;
|
||||
}
|
||||
|
||||
file.read((char*)fileChunk, chunkLength); // read in a section of the file larger than the chunk;
|
||||
|
||||
remainingLength -= chunkLength;
|
||||
|
||||
unsigned char* dataAt = fileChunk;
|
||||
unsigned long dataLength = chunkLength;
|
||||
|
||||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0,
|
||||
SharedNodePointer(), wantImportProgress, gotVersion);
|
||||
|
||||
readBitstreamToTree(dataAt, dataLength, args);
|
||||
}
|
||||
|
||||
delete[] fileChunk;
|
||||
}
|
||||
|
||||
delete[] fileChunk;
|
||||
}
|
||||
|
||||
emit importProgress(100);
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
||||
return fileOk;
|
||||
}
|
||||
|
|
|
@ -326,7 +326,10 @@ public:
|
|||
|
||||
// these will read/write files that match the wireformat, excluding the 'V' leading
|
||||
void writeToSVOFile(const char* filename, OctreeElement* element = NULL);
|
||||
|
||||
bool readFromSVOFile(const char* filename);
|
||||
bool readFromSVOURL(const QString& url); // will support file urls as well...
|
||||
bool readFromStream(unsigned long streamLength, QDataStream& inputStream);
|
||||
|
||||
|
||||
unsigned long getOctreeElementsCount();
|
||||
|
|
148
libraries/physics/src/MeshInfo.cpp
Normal file
148
libraries/physics/src/MeshInfo.cpp
Normal file
|
@ -0,0 +1,148 @@
|
|||
//
|
||||
// MeshInfo.cpp
|
||||
// libraries/physics/src
|
||||
//
|
||||
// Created by Virendra Singh 2015.02.28
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "MeshInfo.h"
|
||||
#include <iostream>
|
||||
using namespace meshinfo;
|
||||
|
||||
//class to compute volume, mass, center of mass, and inertia tensor of a mesh.
|
||||
//origin is the default reference point for generating the tetrahedron from each triangle of the mesh.
|
||||
|
||||
MeshInfo::MeshInfo(vector<Vertex> *vertices, vector<int> *triangles) :\
|
||||
_vertices(vertices),
|
||||
_triangles(triangles),
|
||||
_centerOfMass(Vertex(0.0, 0.0, 0.0)){
|
||||
}
|
||||
|
||||
MeshInfo::~MeshInfo(){
|
||||
|
||||
_vertices = NULL;
|
||||
_triangles = NULL;
|
||||
|
||||
}
|
||||
|
||||
inline float MeshInfo::getVolume(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const{
|
||||
glm::mat4 tet = { glm::vec4(p1.x, p2.x, p3.x, p4.x), glm::vec4(p1.y, p2.y, p3.y, p4.y), glm::vec4(p1.z, p2.z, p3.z, p4.z),
|
||||
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) };
|
||||
return glm::determinant(tet) / 6.0f;
|
||||
}
|
||||
|
||||
Vertex MeshInfo::getMeshCentroid() const{
|
||||
return _centerOfMass;
|
||||
}
|
||||
|
||||
vector<float> MeshInfo::computeMassProperties(){
|
||||
vector<float> volumeAndInertia = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
|
||||
Vertex origin(0.0, 0.0, 0.0);
|
||||
glm::mat3 identity;
|
||||
float meshVolume = 0.0f;
|
||||
glm::mat3 globalInertiaTensors(0.0);
|
||||
|
||||
for (unsigned int i = 0; i < _triangles->size(); i += 3){
|
||||
Vertex p1 = _vertices->at(_triangles->at(i));
|
||||
Vertex p2 = _vertices->at(_triangles->at(i + 1));
|
||||
Vertex p3 = _vertices->at(_triangles->at(i + 2));
|
||||
float volume = getVolume(p1, p2, p3, origin);
|
||||
Vertex com = 0.25f * (p1 + p2 + p3);
|
||||
meshVolume += volume;
|
||||
_centerOfMass += com * volume;
|
||||
|
||||
//centroid is used for calculating inertia tensor relative to center of mass.
|
||||
// translate the tetrahedron to its center of mass using P = P - centroid
|
||||
Vertex p0 = origin - com;
|
||||
p1 = p1 - com;
|
||||
p2 = p2 - com;
|
||||
p3 = p3 - com;
|
||||
|
||||
//Calculate inertia tensor based on Tonon's Formulae given in the paper mentioned below.
|
||||
//http://docsdrive.com/pdfs/sciencepublications/jmssp/2005/8-11.pdf
|
||||
//Explicit exact formulas for the 3-D tetrahedron inertia tensor in terms of its vertex coordinates - F.Tonon
|
||||
|
||||
float i11 = (volume * 0.1f) * (
|
||||
p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y +
|
||||
p1.y*p1.y + p1.y*p2.y + p1.y*p3.y +
|
||||
p2.y*p2.y + p2.y*p3.y +
|
||||
p3.y*p3.y +
|
||||
p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z +
|
||||
p1.z*p1.z + p1.z*p2.z + p1.z*p3.z +
|
||||
p2.z*p2.z + p2.z*p3.z +
|
||||
p3.z*p3.z);
|
||||
|
||||
float i22 = (volume * 0.1f) * (
|
||||
p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x +
|
||||
p1.x*p1.x + p1.x*p2.x + p1.x*p3.x +
|
||||
p2.x*p2.x + p2.x*p3.x +
|
||||
p3.x*p3.x +
|
||||
p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z +
|
||||
p1.z*p1.z + p1.z*p2.z + p1.z*p3.z +
|
||||
p2.z*p2.z + p2.z*p3.z +
|
||||
p3.z*p3.z);
|
||||
|
||||
float i33 = (volume * 0.1f) * (
|
||||
p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x +
|
||||
p1.x*p1.x + p1.x*p2.x + p1.x*p3.x +
|
||||
p2.x*p2.x + p2.x*p3.x +
|
||||
p3.x*p3.x +
|
||||
p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y +
|
||||
p1.y*p1.y + p1.y*p2.y + p1.y*p3.y +
|
||||
p2.y*p2.y + p2.y*p3.y +
|
||||
p3.y*p3.y);
|
||||
|
||||
float i23 = -(volume * 0.05f) * (2.0f * (p0.y*p0.z + p1.y*p1.z + p2.y*p2.z + p3.y*p3.z) +
|
||||
p0.y*p1.z + p0.y*p2.z + p0.y*p3.z +
|
||||
p1.y*p0.z + p1.y*p2.z + p1.y*p3.z +
|
||||
p2.y*p0.z + p2.y*p1.z + p2.y*p3.z +
|
||||
p3.y*p0.z + p3.y*p1.z + p3.y*p2.z);
|
||||
|
||||
float i21 = -(volume * 0.05f) * (2.0f * (p0.x*p0.z + p1.x*p1.z + p2.x*p2.z + p3.x*p3.z) +
|
||||
p0.x*p1.z + p0.x*p2.z + p0.x*p3.z +
|
||||
p1.x*p0.z + p1.x*p2.z + p1.x*p3.z +
|
||||
p2.x*p0.z + p2.x*p1.z + p2.x*p3.z +
|
||||
p3.x*p0.z + p3.x*p1.z + p3.x*p2.z);
|
||||
|
||||
float i31 = -(volume * 0.05f) * (2.0f * (p0.x*p0.y + p1.x*p1.y + p2.x*p2.y + p3.x*p3.y) +
|
||||
p0.x*p1.y + p0.x*p2.y + p0.x*p3.y +
|
||||
p1.x*p0.y + p1.x*p2.y + p1.x*p3.y +
|
||||
p2.x*p0.y + p2.x*p1.y + p2.x*p3.y +
|
||||
p3.x*p0.y + p3.x*p1.y + p3.x*p2.y);
|
||||
|
||||
//3x3 of local inertia tensors of each tetrahedron. Inertia tensors are the diagonal elements
|
||||
// | I11 -I12 -I13 |
|
||||
// I = | -I21 I22 -I23 |
|
||||
// | -I31 -I32 I33 |
|
||||
glm::mat3 localInertiaTensors = { Vertex(i11, i21, i31), Vertex(i21, i22, i23),
|
||||
Vertex(i31, i23, i33) };
|
||||
|
||||
//Translate the inertia tensors from center of mass to origin
|
||||
//Parallel axis theorem J = I * m[(R.R)*Identity - RxR] where x is outer cross product
|
||||
globalInertiaTensors += localInertiaTensors + volume * ((glm::dot(com, com) * identity) -
|
||||
glm::outerProduct(com, com));
|
||||
}
|
||||
|
||||
//Translate accumulated center of mass from each tetrahedron to mesh's center of mass using parallel axis theorem
|
||||
if (meshVolume == 0){
|
||||
return volumeAndInertia;
|
||||
}
|
||||
_centerOfMass = (_centerOfMass / meshVolume);
|
||||
|
||||
//Translate the inertia tensors from origin to mesh's center of mass.
|
||||
globalInertiaTensors = globalInertiaTensors - meshVolume * ((glm::dot(_centerOfMass, _centerOfMass) *
|
||||
identity) - glm::outerProduct(_centerOfMass, _centerOfMass));
|
||||
|
||||
volumeAndInertia[0] = meshVolume;
|
||||
volumeAndInertia[1] = globalInertiaTensors[0][0]; //i11
|
||||
volumeAndInertia[2] = globalInertiaTensors[1][1]; //i22
|
||||
volumeAndInertia[3] = globalInertiaTensors[2][2]; //i33
|
||||
volumeAndInertia[4] = -globalInertiaTensors[2][1]; //i23 or i32
|
||||
volumeAndInertia[5] = -globalInertiaTensors[1][0]; //i21 or i12
|
||||
volumeAndInertia[6] = -globalInertiaTensors[2][0]; //i13 or i31
|
||||
return volumeAndInertia;
|
||||
}
|
33
libraries/physics/src/MeshInfo.h
Normal file
33
libraries/physics/src/MeshInfo.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// MeshInfo.h
|
||||
// libraries/physics/src
|
||||
//
|
||||
// Created by Virendra Singh 2015.02.28
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#ifndef hifi_MeshInfo_h
|
||||
#define hifi_MeshInfo_h
|
||||
#include <vector>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/norm.hpp>
|
||||
using namespace std;
|
||||
namespace meshinfo{
|
||||
typedef glm::vec3 Vertex;
|
||||
class MeshInfo{
|
||||
private:
|
||||
inline float getVolume(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const;
|
||||
vector<float> computeVolumeAndInertia(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const;
|
||||
public:
|
||||
vector<Vertex> *_vertices;
|
||||
Vertex _centerOfMass;
|
||||
vector<int> *_triangles;
|
||||
MeshInfo(vector<Vertex> *vertices, vector<int> *triangles);
|
||||
~MeshInfo();
|
||||
Vertex getMeshCentroid() const;
|
||||
vector<float> computeMassProperties();
|
||||
};
|
||||
}
|
||||
#endif // hifi_MeshInfo_h
|
|
@ -616,7 +616,7 @@ void PhysicsEngine::setAvatarData(AvatarData *avatarData) {
|
|||
glmToBullet(_avatarData->getPosition())));
|
||||
|
||||
// XXX these values should be computed from the character model.
|
||||
btScalar characterRadius = 0.3;
|
||||
btScalar characterRadius = 0.3f;
|
||||
btScalar characterHeight = 1.75 - 2.0f * characterRadius;
|
||||
btScalar stepHeight = btScalar(0.35);
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
<@include DeferredLighting.slh@>
|
||||
|
||||
|
||||
struct SphericalHarmonics {
|
||||
vec4 L00;
|
||||
vec4 L1m1;
|
||||
|
|
|
@ -270,6 +270,12 @@ void DeferredLightingEffect::render() {
|
|||
batch.setUniformBuffer(locations->lightBufferUnit, globalLight->getSchemaBuffer());
|
||||
gpu::GLBackend::renderBatch(batch);
|
||||
}
|
||||
|
||||
if (_atmosphere && (locations->atmosphereBufferUnit >= 0)) {
|
||||
gpu::Batch batch;
|
||||
batch.setUniformBuffer(locations->atmosphereBufferUnit, _atmosphere->getDataBuffer());
|
||||
gpu::GLBackend::renderBatch(batch);
|
||||
}
|
||||
glUniformMatrix4fv(locations->invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat));
|
||||
}
|
||||
|
||||
|
@ -511,6 +517,31 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit
|
|||
locations.lightBufferUnit = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
loc = program.uniformLocation("atmosphereBufferUnit");
|
||||
if (loc >= 0) {
|
||||
locations.atmosphereBufferUnit = loc;
|
||||
} else {
|
||||
locations.atmosphereBufferUnit = -1;
|
||||
}
|
||||
#elif defined(Q_OS_WIN)
|
||||
loc = glGetUniformBlockIndex(program.programId(), "atmosphereBufferUnit");
|
||||
if (loc >= 0) {
|
||||
glUniformBlockBinding(program.programId(), loc, 1);
|
||||
locations.atmosphereBufferUnit = 1;
|
||||
} else {
|
||||
locations.atmosphereBufferUnit = -1;
|
||||
}
|
||||
#else
|
||||
loc = program.uniformLocation("atmosphereBufferUnit");
|
||||
if (loc >= 0) {
|
||||
locations.atmosphereBufferUnit = loc;
|
||||
} else {
|
||||
locations.atmosphereBufferUnit = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
program.release();
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "ProgramObject.h"
|
||||
|
||||
#include "model/Light.h"
|
||||
#include "model/Stage.h"
|
||||
|
||||
class AbstractViewStateInterface;
|
||||
class PostLightingRenderable;
|
||||
|
@ -73,6 +74,7 @@ public:
|
|||
// update global lighting
|
||||
void setAmbientLightMode(int preset);
|
||||
void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity);
|
||||
void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; }
|
||||
|
||||
private:
|
||||
DeferredLightingEffect() {}
|
||||
|
@ -89,6 +91,7 @@ private:
|
|||
int radius;
|
||||
int ambientSphere;
|
||||
int lightBufferUnit;
|
||||
int atmosphereBufferUnit;
|
||||
int invViewMat;
|
||||
};
|
||||
|
||||
|
@ -146,6 +149,7 @@ private:
|
|||
AbstractViewStateInterface* _viewState;
|
||||
|
||||
int _ambientLightMode = 0;
|
||||
model::AtmospherePointer _atmosphere;
|
||||
};
|
||||
|
||||
/// Simple interface for objects that require something to be rendered after deferred lighting.
|
||||
|
|
|
@ -299,73 +299,156 @@ void Model::initJointTransforms() {
|
|||
|
||||
void Model::init() {
|
||||
if (!_program.isLinked()) {
|
||||
/* //Work in progress not used yet
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), 1));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), 3));
|
||||
|
||||
// Vertex shaders
|
||||
auto modelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_vert)));
|
||||
auto modelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_normal_map_vert)));
|
||||
auto modelLightmapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_vert)));
|
||||
auto modelLightmapNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert)));
|
||||
auto modelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_shadow_vert)));
|
||||
auto skinModelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_vert)));
|
||||
auto skinModelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)));
|
||||
auto skinModelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_shadow_vert)));
|
||||
|
||||
// Pixel shaders
|
||||
auto modelPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_frag)));
|
||||
auto modelNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_map_frag)));
|
||||
auto modelSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_specular_map_frag)));
|
||||
auto modelNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)));
|
||||
auto modelTranslucentPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_translucent_frag)));
|
||||
auto modelShadowPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_shadow_frag)));
|
||||
auto modelLightmapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_frag)));
|
||||
auto modelLightmapNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag)));
|
||||
auto modelLightmapSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)));
|
||||
auto modelLightmapNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)));
|
||||
|
||||
|
||||
bool makeResult = false;
|
||||
|
||||
// Programs
|
||||
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
auto normalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*normalMapProgram, slotBindings);
|
||||
|
||||
auto specularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelSpecularMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*specularMapProgram, slotBindings);
|
||||
|
||||
auto normalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalSpecularMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*normalSpecularMapProgram, slotBindings);
|
||||
|
||||
auto translucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelTranslucentPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*translucentProgram, slotBindings);
|
||||
|
||||
auto shadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelShadowVertex, modelShadowPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*shadowProgram, slotBindings);
|
||||
|
||||
auto lightmapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*lightmapProgram, slotBindings);
|
||||
|
||||
auto lightmapNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*lightmapNormalMapProgram, slotBindings);
|
||||
|
||||
auto lightmapSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapSpecularMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*lightmapSpecularMapProgram, slotBindings);
|
||||
|
||||
auto lightmapNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*lightmapNormalSpecularMapProgram, slotBindings);
|
||||
|
||||
auto skinProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*skinProgram, slotBindings);
|
||||
|
||||
auto skinNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*skinNormalMapProgram, slotBindings);
|
||||
|
||||
auto skinSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelSpecularMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*skinSpecularMapProgram, slotBindings);
|
||||
|
||||
auto skinNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalSpecularMapPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*skinNormalSpecularMapProgram, slotBindings);
|
||||
|
||||
auto skinShadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelShadowVertex, modelShadowPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*skinShadowProgram, slotBindings);
|
||||
|
||||
auto skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel));
|
||||
makeResult = gpu::Shader::makeProgram(*skinTranslucentProgram, slotBindings);
|
||||
*/
|
||||
|
||||
_program.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||
_program.addShaderFromSourceCode(QGLShader::Fragment, model_frag);
|
||||
initProgram(_program, _locations);
|
||||
|
||||
_normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
|
||||
_normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
|
||||
initProgram(_normalMapProgram, _normalMapLocations);
|
||||
|
||||
_specularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||
_specularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag);
|
||||
initProgram(_specularMapProgram, _specularMapLocations);
|
||||
|
||||
_normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
|
||||
_normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag);
|
||||
initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations);
|
||||
|
||||
_translucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||
_translucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag);
|
||||
initProgram(_translucentProgram, _translucentLocations);
|
||||
|
||||
// Lightmap
|
||||
_lightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert);
|
||||
_lightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag);
|
||||
initProgram(_lightmapProgram, _lightmapLocations);
|
||||
|
||||
_lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert);
|
||||
_lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag);
|
||||
initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations);
|
||||
|
||||
_lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert);
|
||||
_lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag);
|
||||
initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations);
|
||||
|
||||
_lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert);
|
||||
_lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag);
|
||||
initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations);
|
||||
// end lightmap
|
||||
|
||||
|
||||
_shadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert);
|
||||
_shadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag);
|
||||
// Shadow program uses the same locations as standard rendering path but we still need to set the bindings
|
||||
Model::Locations tempLoc;
|
||||
initProgram(_shadowProgram, tempLoc);
|
||||
|
||||
_skinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
|
||||
_skinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag);
|
||||
initSkinProgram(_skinProgram, _skinLocations);
|
||||
|
||||
_skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert);
|
||||
_skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
|
||||
initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations);
|
||||
|
||||
_skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||
_skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag);
|
||||
initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations);
|
||||
|
||||
_skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert);
|
||||
_skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag);
|
||||
initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations);
|
||||
|
||||
_skinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert);
|
||||
_skinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag);
|
||||
initSkinProgram(_skinShadowProgram, _skinShadowLocations);
|
||||
|
||||
|
||||
_skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
|
||||
|
||||
_normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
|
||||
_normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
|
||||
initProgram(_normalMapProgram, _normalMapLocations);
|
||||
|
||||
_specularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||
_specularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag);
|
||||
initProgram(_specularMapProgram, _specularMapLocations);
|
||||
|
||||
_normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
|
||||
_normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag);
|
||||
initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations);
|
||||
|
||||
_translucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||
_translucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag);
|
||||
initProgram(_translucentProgram, _translucentLocations);
|
||||
|
||||
// Lightmap
|
||||
_lightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert);
|
||||
_lightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag);
|
||||
initProgram(_lightmapProgram, _lightmapLocations);
|
||||
|
||||
_lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert);
|
||||
_lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag);
|
||||
initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations);
|
||||
|
||||
_lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert);
|
||||
_lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag);
|
||||
initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations);
|
||||
|
||||
_lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert);
|
||||
_lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag);
|
||||
initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations);
|
||||
// end lightmap
|
||||
|
||||
|
||||
_shadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert);
|
||||
_shadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag);
|
||||
// Shadow program uses the same locations as standard rendering path but we still need to set the bindings
|
||||
Model::Locations tempLoc;
|
||||
initProgram(_shadowProgram, tempLoc);
|
||||
|
||||
_skinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
|
||||
_skinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag);
|
||||
initSkinProgram(_skinProgram, _skinLocations);
|
||||
|
||||
_skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert);
|
||||
_skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
|
||||
initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations);
|
||||
|
||||
_skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||
_skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag);
|
||||
initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations);
|
||||
|
||||
_skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert);
|
||||
_skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag);
|
||||
initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations);
|
||||
|
||||
_skinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert);
|
||||
_skinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag);
|
||||
initSkinProgram(_skinShadowProgram, _skinShadowLocations);
|
||||
|
||||
|
||||
_skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
|
||||
_skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag);
|
||||
initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations);
|
||||
}
|
||||
|
|
|
@ -309,6 +309,7 @@ private:
|
|||
int _blendNumber;
|
||||
int _appliedBlendNumber;
|
||||
|
||||
|
||||
static ProgramObject _program;
|
||||
static ProgramObject _normalMapProgram;
|
||||
static ProgramObject _specularMapProgram;
|
||||
|
|
235
tests/physics/src/MeshInfoTests.cpp
Normal file
235
tests/physics/src/MeshInfoTests.cpp
Normal file
|
@ -0,0 +1,235 @@
|
|||
//
|
||||
// MeshInfoTests.cpp
|
||||
// tests/physics/src
|
||||
//
|
||||
// Created by Virendra Singh on 2015.03.02
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <MeshInfo.h>
|
||||
|
||||
#include "MeshInfoTests.h"
|
||||
const float epsilon = 0.015f;
|
||||
void MeshInfoTests::testWithTetrahedron(){
|
||||
glm::vec3 p0(8.33220, -11.86875, 0.93355);
|
||||
glm::vec3 p1(0.75523, 5.00000, 16.37072);
|
||||
glm::vec3 p2(52.61236, 5.00000, -5.38580);
|
||||
glm::vec3 p3(2.00000, 5.00000, 3.00000);
|
||||
glm::vec3 centroid(15.92492, 0.782813, 3.72962);
|
||||
|
||||
//translate the tetrahedron so that its apex is on origin
|
||||
glm::vec3 p11 = p1 - p0;
|
||||
glm::vec3 p22 = p2 - p0;
|
||||
glm::vec3 p33 = p3 - p0;
|
||||
vector<glm::vec3> vertices = { p11, p22, p33 };
|
||||
vector<int> triangles = { 0, 1, 2 };
|
||||
|
||||
float volume = 1873.233236f;
|
||||
float inertia_a = 43520.33257f;
|
||||
//actual should be 194711.28938f. But for some reason it becomes 194711.296875 during
|
||||
//runtime due to how floating points are stored.
|
||||
float inertia_b = 194711.289f;
|
||||
float inertia_c = 191168.76173f;
|
||||
float inertia_aa = 4417.66150f;
|
||||
float inertia_bb = -46343.16662f;
|
||||
float inertia_cc = 11996.20119f;
|
||||
|
||||
meshinfo::MeshInfo meshinfo(&vertices,&triangles);
|
||||
vector<float> voumeAndInertia = meshinfo.computeMassProperties();
|
||||
glm::vec3 tetCenterOfMass = meshinfo.getMeshCentroid();
|
||||
|
||||
//get original center of mass
|
||||
tetCenterOfMass = tetCenterOfMass + p0;
|
||||
glm::vec3 diff = centroid - tetCenterOfMass;
|
||||
std::cout << std::setprecision(12);
|
||||
//test if centroid is correct
|
||||
if (diff.x > epsilon || diff.y > epsilon || diff.z > epsilon){
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Centroid is incorrect : Expected = " << centroid.x << " " <<
|
||||
centroid.y << " " << centroid.z << ", actual = " << tetCenterOfMass.x << " " << tetCenterOfMass.y <<
|
||||
" " << tetCenterOfMass.z << std::endl;
|
||||
}
|
||||
|
||||
//test if volume is correct
|
||||
if (abs(volume - voumeAndInertia.at(0)) > epsilon){
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume << " " <<
|
||||
", actual = " << voumeAndInertia.at(0) << std::endl;
|
||||
}
|
||||
|
||||
//test if moment of inertia with respect to x axis is correct
|
||||
if (abs(inertia_a - (voumeAndInertia.at(1))) > epsilon){
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to x axis is incorrect : Expected = " <<
|
||||
inertia_a << " " << ", actual = " << voumeAndInertia.at(1) << std::endl;
|
||||
}
|
||||
|
||||
//test if moment of inertia with respect to y axis is correct
|
||||
if (abs(inertia_b - voumeAndInertia.at(2)) > epsilon){
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to y axis is incorrect : Expected = " <<
|
||||
inertia_b << " " << ", actual = " << (voumeAndInertia.at(2)) << std::endl;
|
||||
}
|
||||
|
||||
//test if moment of inertia with respect to z axis is correct
|
||||
if (abs(inertia_c - (voumeAndInertia.at(3))) > epsilon){
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia with respect to z axis is incorrect : Expected = " <<
|
||||
inertia_c << " " << ", actual = " << (voumeAndInertia.at(3)) << std::endl;
|
||||
}
|
||||
|
||||
//test if product of inertia with respect to x axis is correct
|
||||
if (abs(inertia_aa - (voumeAndInertia.at(4))) > epsilon){
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to x axis is incorrect : Expected = " <<
|
||||
inertia_aa << " " << ", actual = " << (voumeAndInertia.at(4)) << std::endl;
|
||||
}
|
||||
|
||||
//test if product of inertia with respect to y axis is correct
|
||||
if (abs(inertia_bb - (voumeAndInertia.at(5))) > epsilon){
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to y axis is incorrect : Expected = " <<
|
||||
inertia_bb << " " << ", actual = " << (voumeAndInertia.at(5)) << std::endl;
|
||||
}
|
||||
|
||||
//test if product of inertia with respect to z axis is correct
|
||||
if (abs(inertia_cc - (voumeAndInertia.at(6))) > epsilon){
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Product of inertia with respect to z axis is incorrect : Expected = " <<
|
||||
inertia_cc << " " << ", actual = " << (voumeAndInertia.at(6)) << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MeshInfoTests::testWithTetrahedronAsMesh(){
|
||||
glm::vec3 p0(8.33220, -11.86875, 0.93355);
|
||||
glm::vec3 p1(0.75523, 5.00000, 16.37072);
|
||||
glm::vec3 p2(52.61236, 5.00000, -5.38580);
|
||||
glm::vec3 p3(2.00000, 5.00000, 3.00000);
|
||||
glm::vec3 centroid(15.92492, 0.782813, 3.72962);
|
||||
float volume = 1873.233236f;
|
||||
float inertia_a = 43520.33257f;
|
||||
//actual should be 194711.28938f. But for some reason it becomes 194711.296875 during
|
||||
//runtime due to how floating points are stored.
|
||||
float inertia_b = 194711.289f;
|
||||
float inertia_c = 191168.76173f;
|
||||
float inertia_aa = 4417.66150f;
|
||||
float inertia_bb = -46343.16662f;
|
||||
float inertia_cc = 11996.20119f;
|
||||
std::cout << std::setprecision(12);
|
||||
vector<glm::vec3> vertices = { p0, p1, p2, p3 };
|
||||
vector<int> triangles = { 0, 2, 1, 0, 3, 2, 0, 1, 3, 1, 2, 3 };
|
||||
meshinfo::MeshInfo massProp(&vertices, &triangles);
|
||||
vector<float> volumeAndInertia = massProp.computeMassProperties();
|
||||
std::cout << volumeAndInertia[0] << " " << volumeAndInertia[1] << " " << volumeAndInertia[2]
|
||||
<< " " << volumeAndInertia[3]
|
||||
<< " " << volumeAndInertia[4]
|
||||
<< " " << volumeAndInertia[5] << " " << volumeAndInertia[6] << std::endl;
|
||||
|
||||
//translate the tetrahedron so that the model is placed at origin i.e. com is at origin
|
||||
p0 -= centroid;
|
||||
p1 -= centroid;
|
||||
p2 -= centroid;
|
||||
p3 -= centroid;
|
||||
}
|
||||
void MeshInfoTests::testWithCube(){
|
||||
glm::vec3 p0(1.0, -1.0, -1.0);
|
||||
glm::vec3 p1(1.0, -1.0, 1.0);
|
||||
glm::vec3 p2(-1.0, -1.0, 1.0);
|
||||
glm::vec3 p3(-1.0, -1.0, -1.0);
|
||||
glm::vec3 p4(1.0, 1.0, -1.0);
|
||||
glm::vec3 p5(1.0, 1.0, 1.0);
|
||||
glm::vec3 p6(-1.0, 1.0, 1.0);
|
||||
glm::vec3 p7(-1.0, 1.0, -1.0);
|
||||
vector<glm::vec3> vertices;
|
||||
vertices.push_back(p0);
|
||||
vertices.push_back(p1);
|
||||
vertices.push_back(p2);
|
||||
vertices.push_back(p3);
|
||||
vertices.push_back(p4);
|
||||
vertices.push_back(p5);
|
||||
vertices.push_back(p6);
|
||||
vertices.push_back(p7);
|
||||
std::cout << std::setprecision(10);
|
||||
vector<int> triangles = { 0, 1, 2, 0, 2, 3, 4, 7, 6, 4, 6, 5, 0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2, 2, 6,
|
||||
7, 2, 7, 3, 4, 0, 3, 4, 3, 7 };
|
||||
glm::vec3 centerOfMass(0.0, 0.0, 0.0);
|
||||
double volume = 8.0;
|
||||
double side = 2.0;
|
||||
double inertia = (volume * side * side) / 6.0; //inertia of a unit cube is (mass * side * side) /6
|
||||
|
||||
//test with origin as reference point
|
||||
meshinfo::MeshInfo massProp(&vertices, &triangles);
|
||||
vector<float> volumeAndInertia = massProp.computeMassProperties();
|
||||
if (abs(centerOfMass.x - massProp.getMeshCentroid().x) > epsilon || abs(centerOfMass.y - massProp.getMeshCentroid().y) > epsilon ||
|
||||
abs(centerOfMass.z - massProp.getMeshCentroid().z) > epsilon){
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x << " " <<
|
||||
centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp.getMeshCentroid().x << " " <<
|
||||
massProp.getMeshCentroid().y << " " << massProp.getMeshCentroid().z << std::endl;
|
||||
}
|
||||
|
||||
if (abs(volume - volumeAndInertia.at(0)) > epsilon){
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume <<
|
||||
", actual = " << volumeAndInertia.at(0) << std::endl;
|
||||
}
|
||||
|
||||
if (abs(inertia - (volumeAndInertia.at(1))) > epsilon || abs(inertia - (volumeAndInertia.at(2))) > epsilon ||
|
||||
abs(inertia - (volumeAndInertia.at(3))) > epsilon){
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia is incorrect : Expected = " << inertia << " " <<
|
||||
inertia << " " << inertia << ", actual = " << (volumeAndInertia.at(1)) << " " << (volumeAndInertia.at(2)) <<
|
||||
" " << (volumeAndInertia.at(3)) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void MeshInfoTests::testWithUnitCube()
|
||||
{
|
||||
glm::vec3 p0(0, 0, 1);
|
||||
glm::vec3 p1(1, 0, 1);
|
||||
glm::vec3 p2(0, 1, 1);
|
||||
glm::vec3 p3(1, 1, 1);
|
||||
glm::vec3 p4(0, 0, 0);
|
||||
glm::vec3 p5(1, 0, 0);
|
||||
glm::vec3 p6(0, 1, 0);
|
||||
glm::vec3 p7(1, 1, 0);
|
||||
vector<glm::vec3> vertices;
|
||||
vertices.push_back(p0);
|
||||
vertices.push_back(p1);
|
||||
vertices.push_back(p2);
|
||||
vertices.push_back(p3);
|
||||
vertices.push_back(p4);
|
||||
vertices.push_back(p5);
|
||||
vertices.push_back(p6);
|
||||
vertices.push_back(p7);
|
||||
vector<int> triangles = { 0, 1, 2, 1, 3, 2, 2, 3, 7, 2, 7, 6, 1, 7, 3, 1, 5, 7, 6, 7, 4, 7, 5, 4, 0, 4, 1,
|
||||
1, 4, 5, 2, 6, 4, 0, 2, 4 };
|
||||
glm::vec3 centerOfMass(0.5, 0.5, 0.5);
|
||||
double volume = 1.0;
|
||||
double side = 1.0;
|
||||
double inertia = (volume * side * side) / 6.0; //inertia of a unit cube is (mass * side * side) /6
|
||||
std::cout << std::setprecision(10);
|
||||
|
||||
//test with origin as reference point
|
||||
meshinfo::MeshInfo massProp(&vertices, &triangles);
|
||||
vector<float> volumeAndInertia = massProp.computeMassProperties();
|
||||
if (abs(centerOfMass.x - massProp.getMeshCentroid().x) > epsilon || abs(centerOfMass.y - massProp.getMeshCentroid().y) >
|
||||
epsilon || abs(centerOfMass.z - massProp.getMeshCentroid().z) > epsilon){
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Center of mass is incorrect : Expected = " << centerOfMass.x <<
|
||||
" " << centerOfMass.y << " " << centerOfMass.z << ", actual = " << massProp.getMeshCentroid().x << " " <<
|
||||
massProp.getMeshCentroid().y << " " << massProp.getMeshCentroid().z << std::endl;
|
||||
}
|
||||
|
||||
if (abs(volume - volumeAndInertia.at(0)) > epsilon){
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Volume is incorrect : Expected = " << volume <<
|
||||
", actual = " << volumeAndInertia.at(0) << std::endl;
|
||||
}
|
||||
|
||||
if (abs(inertia - (volumeAndInertia.at(1))) > epsilon || abs(inertia - (volumeAndInertia.at(2))) > epsilon ||
|
||||
abs(inertia - (volumeAndInertia.at(3))) > epsilon){
|
||||
std::cout << __FILE__ << ":" << __LINE__ << " ERROR : Moment of inertia is incorrect : Expected = " << inertia << " " <<
|
||||
inertia << " " << inertia << ", actual = " << (volumeAndInertia.at(1)) << " " << (volumeAndInertia.at(2)) <<
|
||||
" " << (volumeAndInertia.at(3)) << std::endl;
|
||||
}
|
||||
}
|
||||
void MeshInfoTests::runAllTests(){
|
||||
testWithTetrahedron();
|
||||
testWithTetrahedronAsMesh();
|
||||
testWithUnitCube();
|
||||
testWithCube();
|
||||
}
|
21
tests/physics/src/MeshInfoTests.h
Normal file
21
tests/physics/src/MeshInfoTests.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// MeshInfoTests.h
|
||||
// tests/physics/src
|
||||
//
|
||||
// Created by Virendra Singh on 2015.03.02
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_MeshInfoTests_h
|
||||
#define hifi_MeshInfoTests_h
|
||||
namespace MeshInfoTests{
|
||||
void testWithTetrahedron();
|
||||
void testWithUnitCube();
|
||||
void testWithCube();
|
||||
void runAllTests();
|
||||
void testWithTetrahedronAsMesh();
|
||||
}
|
||||
#endif // hifi_MeshInfoTests_h
|
|
@ -13,6 +13,7 @@
|
|||
#include "ShapeInfoTests.h"
|
||||
#include "ShapeManagerTests.h"
|
||||
#include "BulletUtilTests.h"
|
||||
#include "MeshInfoTests.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ShapeColliderTests::runAllTests();
|
||||
|
@ -20,5 +21,6 @@ int main(int argc, char** argv) {
|
|||
ShapeInfoTests::runAllTests();
|
||||
ShapeManagerTests::runAllTests();
|
||||
BulletUtilTests::runAllTests();
|
||||
MeshInfoTests::runAllTests();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -192,9 +192,17 @@ int main (int argc, char** argv) {
|
|||
targetStringStream << "#ifndef scribe_" << targetName << "_h" << std::endl;
|
||||
targetStringStream << "#define scribe_" << targetName << "_h" << std::endl << std::endl;
|
||||
|
||||
targetStringStream << "const char " << targetName << "[] = R\"XXXX(" << destStringStream.str() << ")XXXX\";";
|
||||
// targetStringStream << "const char " << targetName << "[] = R\"XXXX(" << destStringStream.str() << ")XXXX\";";
|
||||
std::istringstream destStringStreamAgain(destStringStream.str());
|
||||
targetStringStream << "const char " << targetName << "[] = \n";
|
||||
while (!destStringStreamAgain.eof()) {
|
||||
std::string lineToken;
|
||||
std::getline(destStringStreamAgain, lineToken);
|
||||
// targetStringStream << "\"" << lineToken << "\"\n";
|
||||
targetStringStream << "R\"X(" << lineToken << ")X\"\"\\n\"\n";
|
||||
}
|
||||
|
||||
targetStringStream << std::endl << std::endl;
|
||||
targetStringStream << ";\n" << std::endl << std::endl;
|
||||
targetStringStream << "#endif" << std::endl;
|
||||
} else {
|
||||
targetStringStream << destStringStream.str();
|
||||
|
|
Loading…
Reference in a new issue