mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 21:57:00 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into persist-entities-as-json
This commit is contained in:
commit
918cfa8b4e
57 changed files with 3524 additions and 555 deletions
|
@ -37,7 +37,7 @@ macro(COPY_DLLS_BESIDE_WINDOWS_EXECUTABLE)
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
TARGET ${TARGET_NAME}
|
TARGET ${TARGET_NAME}
|
||||||
POST_BUILD
|
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 ()
|
endif ()
|
||||||
endmacro()
|
endmacro()
|
|
@ -17,4 +17,5 @@ Script.load("headMove.js");
|
||||||
Script.load("inspect.js");
|
Script.load("inspect.js");
|
||||||
Script.load("lobby.js");
|
Script.load("lobby.js");
|
||||||
Script.load("notifications.js");
|
Script.load("notifications.js");
|
||||||
Script.load("lookWithMouse.js")
|
Script.load("lookWithMouse.js");
|
||||||
|
Script.load("users.js");
|
||||||
|
|
|
@ -125,7 +125,7 @@ var toolBar = (function () {
|
||||||
width: toolWidth,
|
width: toolWidth,
|
||||||
height: toolHeight,
|
height: toolHeight,
|
||||||
alpha: 0.9,
|
alpha: 0.9,
|
||||||
visible: true
|
visible: false
|
||||||
});
|
});
|
||||||
|
|
||||||
browseModelsButton = toolBar.addTool({
|
browseModelsButton = toolBar.addTool({
|
||||||
|
@ -133,7 +133,7 @@ var toolBar = (function () {
|
||||||
width: toolWidth,
|
width: toolWidth,
|
||||||
height: toolHeight,
|
height: toolHeight,
|
||||||
alpha: 0.9,
|
alpha: 0.9,
|
||||||
visible: true
|
visible: false
|
||||||
});
|
});
|
||||||
|
|
||||||
newCubeButton = toolBar.addTool({
|
newCubeButton = toolBar.addTool({
|
||||||
|
@ -142,7 +142,7 @@ var toolBar = (function () {
|
||||||
width: toolWidth,
|
width: toolWidth,
|
||||||
height: toolHeight,
|
height: toolHeight,
|
||||||
alpha: 0.9,
|
alpha: 0.9,
|
||||||
visible: true
|
visible: false
|
||||||
});
|
});
|
||||||
|
|
||||||
newSphereButton = toolBar.addTool({
|
newSphereButton = toolBar.addTool({
|
||||||
|
@ -151,7 +151,7 @@ var toolBar = (function () {
|
||||||
width: toolWidth,
|
width: toolWidth,
|
||||||
height: toolHeight,
|
height: toolHeight,
|
||||||
alpha: 0.9,
|
alpha: 0.9,
|
||||||
visible: true
|
visible: false
|
||||||
});
|
});
|
||||||
|
|
||||||
newLightButton = toolBar.addTool({
|
newLightButton = toolBar.addTool({
|
||||||
|
@ -160,7 +160,7 @@ var toolBar = (function () {
|
||||||
width: toolWidth,
|
width: toolWidth,
|
||||||
height: toolHeight,
|
height: toolHeight,
|
||||||
alpha: 0.9,
|
alpha: 0.9,
|
||||||
visible: true
|
visible: false
|
||||||
});
|
});
|
||||||
|
|
||||||
newTextButton = toolBar.addTool({
|
newTextButton = toolBar.addTool({
|
||||||
|
@ -169,9 +169,8 @@ var toolBar = (function () {
|
||||||
width: toolWidth,
|
width: toolWidth,
|
||||||
height: toolHeight,
|
height: toolHeight,
|
||||||
alpha: 0.9,
|
alpha: 0.9,
|
||||||
visible: true
|
visible: false
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
that.setActive = function(active) {
|
that.setActive = function(active) {
|
||||||
|
@ -196,11 +195,22 @@ var toolBar = (function () {
|
||||||
propertiesTool.setVisible(true);
|
propertiesTool.setVisible(true);
|
||||||
Window.setFocus();
|
Window.setFocus();
|
||||||
}
|
}
|
||||||
|
that.showTools(isActive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toolBar.selectTool(activeButton, isActive);
|
toolBar.selectTool(activeButton, isActive);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Sets visibility of tool buttons, excluding the power button
|
||||||
|
that.showTools = function(doShow) {
|
||||||
|
toolBar.showTool(newModelButton, doShow);
|
||||||
|
toolBar.showTool(browseModelsButton, doShow);
|
||||||
|
toolBar.showTool(newCubeButton, doShow);
|
||||||
|
toolBar.showTool(newSphereButton, doShow);
|
||||||
|
toolBar.showTool(newLightButton, doShow);
|
||||||
|
toolBar.showTool(newTextButton, doShow);
|
||||||
|
};
|
||||||
|
|
||||||
var RESIZE_INTERVAL = 50;
|
var RESIZE_INTERVAL = 50;
|
||||||
var RESIZE_TIMEOUT = 120000; // 2 minutes
|
var RESIZE_TIMEOUT = 120000; // 2 minutes
|
||||||
var RESIZE_MAX_CHECKS = RESIZE_TIMEOUT / RESIZE_INTERVAL;
|
var RESIZE_MAX_CHECKS = RESIZE_TIMEOUT / RESIZE_INTERVAL;
|
||||||
|
|
|
@ -271,6 +271,10 @@ ToolBar = function(x, y, direction) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.showTool = function(tool, doShow) {
|
||||||
|
this.tools[tool].show(doShow);
|
||||||
|
}
|
||||||
|
|
||||||
this.show = function(doShow) {
|
this.show = function(doShow) {
|
||||||
for(var tool in this.tools) {
|
for(var tool in this.tools) {
|
||||||
|
|
|
@ -38,6 +38,13 @@ function touchUpdateEvent(event) {
|
||||||
if (wantDebugging) {
|
if (wantDebugging) {
|
||||||
print("touchUpdateEvent event.x,y=" + event.x + ", " + event.y);
|
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_YAW_SCALE = -0.25;
|
||||||
var MOUSE_PITCH_SCALE = -12.5;
|
var MOUSE_PITCH_SCALE = -12.5;
|
||||||
|
|
250
examples/users.js
Normal file
250
examples/users.js
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
//
|
||||||
|
// users.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by David Rowe on 9 Mar 2015.
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
|
||||||
|
var usersWindow = (function () {
|
||||||
|
|
||||||
|
var WINDOW_WIDTH_2D = 150,
|
||||||
|
WINDOW_MARGIN_2D = 12,
|
||||||
|
WINDOW_FOREGROUND_COLOR_2D = { red: 240, green: 240, blue: 240 },
|
||||||
|
WINDOW_FOREGROUND_ALPHA_2D = 0.9,
|
||||||
|
WINDOW_HEADING_COLOR_2D = { red: 180, green: 180, blue: 180 },
|
||||||
|
WINDOW_HEADING_ALPHA_2D = 0.9,
|
||||||
|
WINDOW_BACKGROUND_COLOR_2D = { red: 80, green: 80, blue: 80 },
|
||||||
|
WINDOW_BACKGROUND_ALPHA_2D = 0.7,
|
||||||
|
windowHeight = 0,
|
||||||
|
usersPane2D,
|
||||||
|
usersHeading2D,
|
||||||
|
USERS_FONT_2D = { size: 14 },
|
||||||
|
usersLineHeight,
|
||||||
|
usersLineSpacing,
|
||||||
|
|
||||||
|
usersOnline, // Raw data
|
||||||
|
linesOfUsers, // Array of indexes pointing into usersOnline
|
||||||
|
|
||||||
|
API_URL = "https://metaverse.highfidelity.io/api/v1/users?status=online",
|
||||||
|
HTTP_GET_TIMEOUT = 60000, // ms = 1 minute
|
||||||
|
usersRequest,
|
||||||
|
processUsers,
|
||||||
|
usersTimedOut,
|
||||||
|
usersTimer = null,
|
||||||
|
UPDATE_TIMEOUT = 5000, // ms = 5s
|
||||||
|
|
||||||
|
MENU_NAME = "Tools",
|
||||||
|
MENU_ITEM = "Users Online",
|
||||||
|
MENU_ITEM_AFTER = "Chat...",
|
||||||
|
|
||||||
|
isVisible = true,
|
||||||
|
|
||||||
|
viewportHeight;
|
||||||
|
|
||||||
|
function onMousePressEvent(event) {
|
||||||
|
var clickedOverlay,
|
||||||
|
numLinesBefore,
|
||||||
|
overlayX,
|
||||||
|
overlayY,
|
||||||
|
minY,
|
||||||
|
maxY,
|
||||||
|
lineClicked;
|
||||||
|
|
||||||
|
if (!isVisible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||||
|
if (clickedOverlay === usersPane2D) {
|
||||||
|
|
||||||
|
overlayX = event.x - WINDOW_MARGIN_2D;
|
||||||
|
overlayY = event.y - viewportHeight + windowHeight - WINDOW_MARGIN_2D - (usersLineHeight + usersLineSpacing);
|
||||||
|
|
||||||
|
numLinesBefore = Math.floor(overlayY / (usersLineHeight + usersLineSpacing));
|
||||||
|
minY = numLinesBefore * (usersLineHeight + usersLineSpacing);
|
||||||
|
maxY = minY + usersLineHeight;
|
||||||
|
|
||||||
|
lineClicked = -1;
|
||||||
|
if (minY <= overlayY && overlayY <= maxY) {
|
||||||
|
lineClicked = numLinesBefore;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 <= lineClicked && lineClicked < linesOfUsers.length
|
||||||
|
&& overlayX <= usersOnline[linesOfUsers[lineClicked]].usernameWidth) {
|
||||||
|
//print("Go to " + usersOnline[linesOfUsers[lineClicked]].username);
|
||||||
|
location.goToUser(usersOnline[linesOfUsers[lineClicked]].username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateWindow() {
|
||||||
|
var displayText = "",
|
||||||
|
myUsername,
|
||||||
|
user,
|
||||||
|
i;
|
||||||
|
|
||||||
|
myUsername = GlobalServices.username;
|
||||||
|
linesOfUsers = [];
|
||||||
|
for (i = 0; i < usersOnline.length; i += 1) {
|
||||||
|
user = usersOnline[i];
|
||||||
|
if (user.username !== myUsername && user.online) {
|
||||||
|
usersOnline[i].usernameWidth = Overlays.textSize(usersPane2D, user.username).width;
|
||||||
|
linesOfUsers.push(i);
|
||||||
|
displayText += "\n" + user.username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
windowHeight = (linesOfUsers.length > 0 ? linesOfUsers.length + 1 : 1) * (usersLineHeight + usersLineSpacing)
|
||||||
|
- usersLineSpacing + 2 * WINDOW_MARGIN_2D; // First or only line is for heading
|
||||||
|
|
||||||
|
Overlays.editOverlay(usersPane2D, {
|
||||||
|
y: viewportHeight - windowHeight,
|
||||||
|
height: windowHeight,
|
||||||
|
text: displayText
|
||||||
|
});
|
||||||
|
|
||||||
|
Overlays.editOverlay(usersHeading2D, {
|
||||||
|
y: viewportHeight - windowHeight + WINDOW_MARGIN_2D,
|
||||||
|
text: linesOfUsers.length > 0 ? "Online" : "No users online"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestUsers() {
|
||||||
|
usersRequest = new XMLHttpRequest();
|
||||||
|
usersRequest.open("GET", API_URL, true);
|
||||||
|
usersRequest.timeout = HTTP_GET_TIMEOUT;
|
||||||
|
usersRequest.ontimeout = usersTimedOut;
|
||||||
|
usersRequest.onreadystatechange = processUsers;
|
||||||
|
usersRequest.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
processUsers = function () {
|
||||||
|
var response;
|
||||||
|
|
||||||
|
if (usersRequest.readyState === usersRequest.DONE) {
|
||||||
|
if (usersRequest.status === 200) {
|
||||||
|
response = JSON.parse(usersRequest.responseText);
|
||||||
|
if (response.status !== "success") {
|
||||||
|
print("Error: Request for users status returned status = " + response.status);
|
||||||
|
usersTimer = Script.setTimeout(requestUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!response.hasOwnProperty("data") || !response.data.hasOwnProperty("users")) {
|
||||||
|
print("Error: Request for users status returned invalid data");
|
||||||
|
usersTimer = Script.setTimeout(requestUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
usersOnline = response.data.users;
|
||||||
|
updateWindow();
|
||||||
|
} else {
|
||||||
|
print("Error: Request for users status returned " + usersRequest.status + " " + usersRequest.statusText);
|
||||||
|
usersTimer = Script.setTimeout(requestUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
usersTimer = Script.setTimeout(requestUsers, UPDATE_TIMEOUT); // Update after finished processing.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
usersTimedOut = function () {
|
||||||
|
print("Error: Request for users status timed out");
|
||||||
|
usersTimer = Script.setTimeout(requestUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay.
|
||||||
|
};
|
||||||
|
|
||||||
|
function setVisible(visible) {
|
||||||
|
isVisible = visible;
|
||||||
|
|
||||||
|
if (isVisible) {
|
||||||
|
if (usersTimer === null) {
|
||||||
|
requestUsers();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Script.clearTimeout(usersTimer);
|
||||||
|
usersTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Overlays.editOverlay(usersPane2D, { visible: isVisible });
|
||||||
|
Overlays.editOverlay(usersHeading2D, { visible: isVisible });
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMenuItemEvent(event) {
|
||||||
|
if (event === MENU_ITEM) {
|
||||||
|
setVisible(Menu.isOptionChecked(MENU_ITEM));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
viewportHeight = Controller.getViewportDimensions().y;
|
||||||
|
Overlays.editOverlay(usersPane2D, {
|
||||||
|
y: viewportHeight - windowHeight
|
||||||
|
});
|
||||||
|
Overlays.editOverlay(usersHeading2D, {
|
||||||
|
y: viewportHeight - windowHeight + WINDOW_MARGIN_2D
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUp() {
|
||||||
|
usersPane2D = Overlays.addOverlay("text", {
|
||||||
|
bounds: { x: 0, y: 0, width: WINDOW_WIDTH_2D, height: 0 },
|
||||||
|
topMargin: WINDOW_MARGIN_2D,
|
||||||
|
leftMargin: WINDOW_MARGIN_2D,
|
||||||
|
color: WINDOW_FOREGROUND_COLOR_2D,
|
||||||
|
alpha: WINDOW_FOREGROUND_ALPHA_2D,
|
||||||
|
backgroundColor: WINDOW_BACKGROUND_COLOR_2D,
|
||||||
|
backgroundAlpha: WINDOW_BACKGROUND_ALPHA_2D,
|
||||||
|
text: "",
|
||||||
|
font: USERS_FONT_2D,
|
||||||
|
visible: isVisible
|
||||||
|
});
|
||||||
|
|
||||||
|
usersHeading2D = Overlays.addOverlay("text", {
|
||||||
|
x: WINDOW_MARGIN_2D,
|
||||||
|
width: WINDOW_WIDTH_2D - 2 * WINDOW_MARGIN_2D,
|
||||||
|
height: USERS_FONT_2D.size,
|
||||||
|
topMargin: 0,
|
||||||
|
leftMargin: 0,
|
||||||
|
color: WINDOW_HEADING_COLOR_2D,
|
||||||
|
alpha: WINDOW_HEADING_ALPHA_2D,
|
||||||
|
backgroundAlpha: 0.0,
|
||||||
|
text: "No users online",
|
||||||
|
font: USERS_FONT_2D,
|
||||||
|
visible: isVisible
|
||||||
|
});
|
||||||
|
|
||||||
|
viewportHeight = Controller.getViewportDimensions().y;
|
||||||
|
|
||||||
|
usersLineHeight = Math.floor(Overlays.textSize(usersPane2D, "1").height);
|
||||||
|
usersLineSpacing = Math.floor(Overlays.textSize(usersPane2D, "1\n2").height - 2 * usersLineHeight);
|
||||||
|
|
||||||
|
Controller.mousePressEvent.connect(onMousePressEvent);
|
||||||
|
|
||||||
|
Menu.addMenuItem({
|
||||||
|
menuName: MENU_NAME,
|
||||||
|
menuItemName: MENU_ITEM,
|
||||||
|
afterItem: MENU_ITEM_AFTER,
|
||||||
|
isCheckable: true,
|
||||||
|
isChecked: isVisible
|
||||||
|
});
|
||||||
|
Menu.menuItemEvent.connect(onMenuItemEvent);
|
||||||
|
|
||||||
|
Script.update.connect(update);
|
||||||
|
|
||||||
|
requestUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
function tearDown() {
|
||||||
|
Menu.removeMenuItem(MENU_NAME, MENU_ITEM);
|
||||||
|
|
||||||
|
Script.clearTimeout(usersTimer);
|
||||||
|
Overlays.deleteOverlay(usersHeading2D);
|
||||||
|
Overlays.deleteOverlay(usersPane2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
setUp();
|
||||||
|
Script.scriptEnding.connect(tearDown);
|
||||||
|
}());
|
|
@ -20,11 +20,11 @@ var trailingLoudness = 0.0;
|
||||||
var soundClip = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Tabla+Loops/Tabla1.wav");
|
var soundClip = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Tabla+Loops/Tabla1.wav");
|
||||||
|
|
||||||
var properties = {
|
var properties = {
|
||||||
type: "Box",
|
type: "Box",
|
||||||
position: orbitCenter,
|
position: orbitCenter,
|
||||||
dimensions: { x: 0.25, y: 0.25, z: 0.25 },
|
dimensions: { x: 0.25, y: 0.25, z: 0.25 },
|
||||||
color: { red: 100, green: 0, blue : 0 }
|
color: { red: 100, green: 0, blue : 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
var objectId = Entities.addEntity(properties);
|
var objectId = Entities.addEntity(properties);
|
||||||
var sound = Audio.playSound(soundClip, { position: orbitCenter, loop: true, volume: 0.5 });
|
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 };
|
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;
|
trailingLoudness = 0.9 * trailingLoudness + 0.1 * sound.loudness;
|
||||||
Entities.editEntity( objectId, { position: currentPosition, color: { red: Math.min(trailingLoudness * 2000, 255), green: 0, blue: 0 } } );
|
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() {
|
Script.scriptEnding.connect(function() {
|
||||||
|
|
|
@ -462,6 +462,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
// enable mouse tracking; otherwise, we only get drag events
|
// enable mouse tracking; otherwise, we only get drag events
|
||||||
_glWidget->setMouseTracking(true);
|
_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 = new ToolWindow();
|
||||||
_toolWindow->setWindowFlags(_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint);
|
_toolWindow->setWindowFlags(_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint);
|
||||||
_toolWindow->setWindowTitle("Tools");
|
_toolWindow->setWindowTitle("Tools");
|
||||||
|
@ -1268,6 +1274,18 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
|
||||||
return;
|
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);
|
_entities.mouseMoveEvent(event, deviceID);
|
||||||
|
|
||||||
_controllerScriptingInterface.emitMouseMoveEvent(event, deviceID); // send events to any registered scripts
|
_controllerScriptingInterface.emitMouseMoveEvent(event, deviceID); // send events to any registered scripts
|
||||||
|
@ -1533,14 +1551,47 @@ void Application::setFullscreen(bool fullscreen) {
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)) {
|
||||||
if (fullscreen) {
|
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);
|
_window->menuBar()->setMaximumHeight(0);
|
||||||
} else {
|
} else {
|
||||||
_window->menuBar()->setMaximumHeight(QWIDGETSIZE_MAX);
|
_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) {
|
if (!_aboutToQuit) {
|
||||||
_window->show();
|
_window->show();
|
||||||
}
|
}
|
||||||
|
@ -2890,6 +2941,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
||||||
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
|
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
|
||||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity());
|
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity());
|
||||||
|
DependencyManager::get<DeferredLightingEffect>()->setGlobalAtmosphere(skyStage->getAtmosphere());
|
||||||
|
|
||||||
PROFILE_RANGE("DeferredLighting");
|
PROFILE_RANGE("DeferredLighting");
|
||||||
PerformanceTimer perfTimer("lighting");
|
PerformanceTimer perfTimer("lighting");
|
||||||
|
|
|
@ -586,6 +586,9 @@ private:
|
||||||
GLCanvas* _glWidget = new GLCanvas(); // our GLCanvas has a couple extra features
|
GLCanvas* _glWidget = new GLCanvas(); // our GLCanvas has a couple extra features
|
||||||
|
|
||||||
void checkSkeleton();
|
void checkSkeleton();
|
||||||
|
|
||||||
|
QWidget* _fullscreenMenuWidget = new QWidget();
|
||||||
|
int _menuBarHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Application_h
|
#endif // hifi_Application_h
|
||||||
|
|
|
@ -58,6 +58,7 @@ void LoginDialog::reset() {
|
||||||
_ui->emailLineEdit->setFocus();
|
_ui->emailLineEdit->setFocus();
|
||||||
_ui->logoLabel->setPixmap(QPixmap(PathUtils::resourcesPath() + "images/hifi-logo.svg"));
|
_ui->logoLabel->setPixmap(QPixmap(PathUtils::resourcesPath() + "images/hifi-logo.svg"));
|
||||||
_ui->loginButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/login.svg"));
|
_ui->loginButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/login.svg"));
|
||||||
|
_ui->closeButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/close.svg"));
|
||||||
_ui->infoLabel->setVisible(false);
|
_ui->infoLabel->setVisible(false);
|
||||||
_ui->errorLabel->setVisible(false);
|
_ui->errorLabel->setVisible(false);
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ public:
|
||||||
virtual TextOverlay* createClone() const;
|
virtual TextOverlay* createClone() const;
|
||||||
virtual QScriptValue getProperty(const QString& property);
|
virtual QScriptValue getProperty(const QString& property);
|
||||||
|
|
||||||
QSizeF textSize(const QString& test) const; // Pixels
|
QSizeF textSize(const QString& text) const; // Pixels
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _text;
|
QString _text;
|
||||||
|
|
|
@ -320,6 +320,7 @@ bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
|
||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
adjustedAudioFormat.setSampleRate(FORTY_FOUR);
|
adjustedAudioFormat.setSampleRate(FORTY_FOUR);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
const int HALF_FORTY_FOUR = FORTY_FOUR / 2;
|
const int HALF_FORTY_FOUR = FORTY_FOUR / 2;
|
||||||
|
|
||||||
if (audioDevice.supportedSampleRates().contains(AudioConstants::SAMPLE_RATE * 2)) {
|
if (audioDevice.supportedSampleRates().contains(AudioConstants::SAMPLE_RATE * 2)) {
|
||||||
|
@ -397,18 +398,24 @@ soxr_error_t possibleResampling(soxr_t resampler,
|
||||||
numSourceSamples,
|
numSourceSamples,
|
||||||
sourceAudioFormat, destinationAudioFormat);
|
sourceAudioFormat, destinationAudioFormat);
|
||||||
|
|
||||||
qDebug() << "resample from" << sourceAudioFormat << "to" << destinationAudioFormat
|
|
||||||
<< "from" << numChannelCoversionSamples << "to" << numDestinationSamples;
|
|
||||||
|
|
||||||
resampleError = soxr_process(resampler,
|
resampleError = soxr_process(resampler,
|
||||||
channelConversionSamples, numChannelCoversionSamples, NULL,
|
channelConversionSamples, numChannelCoversionSamples, NULL,
|
||||||
destinationSamples, numDestinationSamples, NULL);
|
destinationSamples, numDestinationSamples, NULL);
|
||||||
|
|
||||||
delete[] channelConversionSamples;
|
delete[] channelConversionSamples;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
unsigned int numAdjustedSourceSamples = numSourceSamples;
|
||||||
|
unsigned int numAdjustedDestinationSamples = numDestinationSamples;
|
||||||
|
|
||||||
|
if (sourceAudioFormat.channelCount() == 2 && destinationAudioFormat.channelCount() == 2) {
|
||||||
|
numAdjustedSourceSamples /= 2;
|
||||||
|
numAdjustedDestinationSamples /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
resampleError = soxr_process(resampler,
|
resampleError = soxr_process(resampler,
|
||||||
sourceSamples, numSourceSamples, NULL,
|
sourceSamples, numAdjustedSourceSamples, NULL,
|
||||||
destinationSamples, numDestinationSamples, NULL);
|
destinationSamples, numAdjustedDestinationSamples, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return resampleError;
|
return resampleError;
|
||||||
|
@ -429,9 +436,12 @@ soxr_t soxrResamplerFromInputFormatToOutputFormat(const QAudioFormat& sourceAudi
|
||||||
// setup soxr_quality_spec_t for quality options
|
// setup soxr_quality_spec_t for quality options
|
||||||
soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0);
|
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(),
|
soxr_t newResampler = soxr_create(sourceAudioFormat.sampleRate(),
|
||||||
destinationAudioFormat.sampleRate(),
|
destinationAudioFormat.sampleRate(),
|
||||||
1,
|
channelCount,
|
||||||
&soxrError, &inputToNetworkSpec, &qualitySpec, 0);
|
&soxrError, &inputToNetworkSpec, &qualitySpec, 0);
|
||||||
|
|
||||||
if (soxrError) {
|
if (soxrError) {
|
||||||
|
@ -1136,7 +1146,7 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice
|
||||||
if (!outputDeviceInfo.isNull()) {
|
if (!outputDeviceInfo.isNull()) {
|
||||||
qDebug() << "The audio output device " << outputDeviceInfo.deviceName() << "is available.";
|
qDebug() << "The audio output device " << outputDeviceInfo.deviceName() << "is available.";
|
||||||
_outputAudioDeviceName = outputDeviceInfo.deviceName().trimmed();
|
_outputAudioDeviceName = outputDeviceInfo.deviceName().trimmed();
|
||||||
|
|
||||||
if (adjustedFormatForAudioDevice(outputDeviceInfo, _desiredOutputFormat, _outputFormat)) {
|
if (adjustedFormatForAudioDevice(outputDeviceInfo, _desiredOutputFormat, _outputFormat)) {
|
||||||
qDebug() << "The format to be used for audio output is" << _outputFormat;
|
qDebug() << "The format to be used for audio output is" << _outputFormat;
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@ class AbstractAudioInterface;
|
||||||
|
|
||||||
class AudioInjector : public QObject {
|
class AudioInjector : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(AudioInjectorOptions options WRITE setOptions READ getOptions)
|
||||||
public:
|
public:
|
||||||
AudioInjector(QObject* parent);
|
AudioInjector(QObject* parent);
|
||||||
AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions);
|
AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions);
|
||||||
|
@ -51,7 +53,9 @@ public slots:
|
||||||
void triggerDeleteAfterFinish() { _shouldDeleteAfterFinish = true; }
|
void triggerDeleteAfterFinish() { _shouldDeleteAfterFinish = true; }
|
||||||
void stopAndDeleteLater();
|
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; }
|
void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; }
|
||||||
float getLoudness() const { return _loudness; }
|
float getLoudness() const { return _loudness; }
|
||||||
bool isPlaying() const { return !_isFinished; }
|
bool isPlaying() const { return !_isFinished; }
|
||||||
|
|
|
@ -99,10 +99,11 @@ void EntitySimulation::sortEntitiesThatMoved() {
|
||||||
_mortalEntities.remove(entity);
|
_mortalEntities.remove(entity);
|
||||||
_updateableEntities.remove(entity);
|
_updateableEntities.remove(entity);
|
||||||
removeEntityInternal(entity);
|
removeEntityInternal(entity);
|
||||||
|
itemItr = _entitiesToBeSorted.erase(itemItr);
|
||||||
} else {
|
} else {
|
||||||
moveOperator.addEntityToMoveList(entity, newCube);
|
moveOperator.addEntityToMoveList(entity, newCube);
|
||||||
|
++itemItr;
|
||||||
}
|
}
|
||||||
++itemItr;
|
|
||||||
}
|
}
|
||||||
if (moveOperator.hasMovingEntities()) {
|
if (moveOperator.hasMovingEntities()) {
|
||||||
PerformanceTimer perfTimer("recurseTreeWithOperator");
|
PerformanceTimer perfTimer("recurseTreeWithOperator");
|
||||||
|
|
|
@ -25,7 +25,8 @@ Batch::Batch() :
|
||||||
_buffers(),
|
_buffers(),
|
||||||
_textures(),
|
_textures(),
|
||||||
_streamFormats(),
|
_streamFormats(),
|
||||||
_transforms()
|
_transforms(),
|
||||||
|
_pipelines()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@ void Batch::clear() {
|
||||||
_textures.clear();
|
_textures.clear();
|
||||||
_streamFormats.clear();
|
_streamFormats.clear();
|
||||||
_transforms.clear();
|
_transforms.clear();
|
||||||
|
_pipelines.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Batch::cacheResource(Resource* res) {
|
uint32 Batch::cacheResource(Resource* res) {
|
||||||
|
@ -159,6 +161,12 @@ void Batch::setProjectionTransform(const Mat4& proj) {
|
||||||
_params.push_back(cacheData(sizeof(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) {
|
void Batch::setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size) {
|
||||||
ADD_COMMAND(setUniformBuffer);
|
ADD_COMMAND(setUniformBuffer);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#include "Stream.h"
|
#include "Stream.h"
|
||||||
#include "Texture.h"
|
#include "Texture.h"
|
||||||
|
|
||||||
|
#include "Pipeline.h"
|
||||||
|
|
||||||
#if defined(NSIGHT_FOUND)
|
#if defined(NSIGHT_FOUND)
|
||||||
#include "nvToolsExt.h"
|
#include "nvToolsExt.h"
|
||||||
class ProfileRange {
|
class ProfileRange {
|
||||||
|
@ -96,7 +98,9 @@ public:
|
||||||
void setViewTransform(const Transform& view);
|
void setViewTransform(const Transform& view);
|
||||||
void setProjectionTransform(const Mat4& proj);
|
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 BufferPointer& buffer, Offset offset, Offset size);
|
||||||
void setUniformBuffer(uint32 slot, const BufferView& view); // not a command, just a shortcut from a BufferView
|
void setUniformBuffer(uint32 slot, const BufferView& view); // not a command, just a shortcut from a BufferView
|
||||||
|
|
||||||
|
@ -164,6 +168,7 @@ public:
|
||||||
COMMAND_setViewTransform,
|
COMMAND_setViewTransform,
|
||||||
COMMAND_setProjectionTransform,
|
COMMAND_setProjectionTransform,
|
||||||
|
|
||||||
|
COMMAND_setPipeline,
|
||||||
COMMAND_setUniformBuffer,
|
COMMAND_setUniformBuffer,
|
||||||
COMMAND_setUniformTexture,
|
COMMAND_setUniformTexture,
|
||||||
|
|
||||||
|
@ -281,6 +286,7 @@ public:
|
||||||
typedef Cache<TexturePointer>::Vector TextureCaches;
|
typedef Cache<TexturePointer>::Vector TextureCaches;
|
||||||
typedef Cache<Stream::FormatPointer>::Vector StreamFormatCaches;
|
typedef Cache<Stream::FormatPointer>::Vector StreamFormatCaches;
|
||||||
typedef Cache<Transform>::Vector TransformCaches;
|
typedef Cache<Transform>::Vector TransformCaches;
|
||||||
|
typedef Cache<PipelinePointer>::Vector PipelineCaches;
|
||||||
|
|
||||||
typedef unsigned char Byte;
|
typedef unsigned char Byte;
|
||||||
typedef std::vector<Byte> Bytes;
|
typedef std::vector<Byte> Bytes;
|
||||||
|
@ -320,6 +326,7 @@ public:
|
||||||
TextureCaches _textures;
|
TextureCaches _textures;
|
||||||
StreamFormatCaches _streamFormats;
|
StreamFormatCaches _streamFormats;
|
||||||
TransformCaches _transforms;
|
TransformCaches _transforms;
|
||||||
|
PipelineCaches _pipelines;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,3 +10,14 @@
|
||||||
//
|
//
|
||||||
#include "Context.h"
|
#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 "Resource.h"
|
||||||
#include "Texture.h"
|
#include "Texture.h"
|
||||||
|
#include "Shader.h"
|
||||||
|
#include "Pipeline.h"
|
||||||
|
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
|
@ -46,25 +48,39 @@ public:
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
static void setGPUObject(const Buffer& buffer, T* bo) {
|
static void setGPUObject(const Buffer& buffer, T* bo) {
|
||||||
buffer.setGPUObject(reinterpret_cast<GPUObject*>(bo));
|
buffer.setGPUObject(bo);
|
||||||
}
|
}
|
||||||
template< typename T >
|
template< typename T >
|
||||||
static T* getGPUObject(const Buffer& buffer) {
|
static T* getGPUObject(const Buffer& buffer) {
|
||||||
return reinterpret_cast<T*>(buffer.getGPUObject());
|
return reinterpret_cast<T*>(buffer.getGPUObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
void syncGPUObject(const Buffer& buffer);
|
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
static void setGPUObject(const Texture& texture, T* to) {
|
static void setGPUObject(const Texture& texture, T* to) {
|
||||||
texture.setGPUObject(reinterpret_cast<GPUObject*>(to));
|
texture.setGPUObject(to);
|
||||||
}
|
}
|
||||||
template< typename T >
|
template< typename T >
|
||||||
static T* getGPUObject(const Texture& texture) {
|
static T* getGPUObject(const Texture& texture) {
|
||||||
return reinterpret_cast<T*>(texture.getGPUObject());
|
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:
|
protected:
|
||||||
|
|
||||||
|
@ -78,8 +94,17 @@ public:
|
||||||
|
|
||||||
void enqueueBatch(Batch& batch);
|
void enqueueBatch(Batch& batch);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
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,
|
NUINT8,
|
||||||
|
|
||||||
NUM_TYPES,
|
NUM_TYPES,
|
||||||
|
|
||||||
|
BOOL = UINT8,
|
||||||
};
|
};
|
||||||
// Array providing the size in bytes for a given scalar type
|
// Array providing the size in bytes for a given scalar type
|
||||||
static const int TYPE_SIZE[NUM_TYPES] = {
|
static const int TYPE_SIZE[NUM_TYPES] = {
|
||||||
|
@ -81,9 +83,9 @@ enum Dimension {
|
||||||
VEC2,
|
VEC2,
|
||||||
VEC3,
|
VEC3,
|
||||||
VEC4,
|
VEC4,
|
||||||
|
MAT2,
|
||||||
MAT3,
|
MAT3,
|
||||||
MAT4,
|
MAT4,
|
||||||
|
|
||||||
NUM_DIMENSIONS,
|
NUM_DIMENSIONS,
|
||||||
};
|
};
|
||||||
// Count (of scalars) in an Element for a given Dimension
|
// Count (of scalars) in an Element for a given Dimension
|
||||||
|
@ -92,8 +94,9 @@ static const int DIMENSION_COUNT[NUM_DIMENSIONS] = {
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
4,
|
4,
|
||||||
|
4,
|
||||||
9,
|
9,
|
||||||
16
|
16,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Semantic of an Element
|
// Semantic of an Element
|
||||||
|
@ -118,6 +121,13 @@ enum Semantic {
|
||||||
SRGBA,
|
SRGBA,
|
||||||
SBGRA,
|
SBGRA,
|
||||||
|
|
||||||
|
UNIFORM,
|
||||||
|
UNIFORM_BUFFER,
|
||||||
|
SAMPLER,
|
||||||
|
SAMPLER_MULTISAMPLE,
|
||||||
|
SAMPLER_SHADOW,
|
||||||
|
|
||||||
|
|
||||||
NUM_SEMANTICS,
|
NUM_SEMANTICS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
||||||
(&::gpu::GLBackend::do_setViewTransform),
|
(&::gpu::GLBackend::do_setViewTransform),
|
||||||
(&::gpu::GLBackend::do_setProjectionTransform),
|
(&::gpu::GLBackend::do_setProjectionTransform),
|
||||||
|
|
||||||
|
(&::gpu::GLBackend::do_setPipeline),
|
||||||
(&::gpu::GLBackend::do_setUniformBuffer),
|
(&::gpu::GLBackend::do_setUniformBuffer),
|
||||||
(&::gpu::GLBackend::do_setUniformTexture),
|
(&::gpu::GLBackend::do_setUniformTexture),
|
||||||
|
|
||||||
|
@ -71,7 +72,8 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
||||||
|
|
||||||
GLBackend::GLBackend() :
|
GLBackend::GLBackend() :
|
||||||
_input(),
|
_input(),
|
||||||
_transform()
|
_transform(),
|
||||||
|
_pipeline()
|
||||||
{
|
{
|
||||||
initTransform();
|
initTransform();
|
||||||
}
|
}
|
||||||
|
@ -134,6 +136,7 @@ void GLBackend::checkGLError() {
|
||||||
void GLBackend::do_draw(Batch& batch, uint32 paramOffset) {
|
void GLBackend::do_draw(Batch& batch, uint32 paramOffset) {
|
||||||
updateInput();
|
updateInput();
|
||||||
updateTransform();
|
updateTransform();
|
||||||
|
updatePipeline();
|
||||||
|
|
||||||
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
|
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
|
||||||
GLenum mode = _primitiveToGLmode[primitiveType];
|
GLenum mode = _primitiveToGLmode[primitiveType];
|
||||||
|
@ -147,6 +150,7 @@ void GLBackend::do_draw(Batch& batch, uint32 paramOffset) {
|
||||||
void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) {
|
void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) {
|
||||||
updateInput();
|
updateInput();
|
||||||
updateTransform();
|
updateTransform();
|
||||||
|
updatePipeline();
|
||||||
|
|
||||||
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
|
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
|
||||||
GLenum mode = _primitiveToGLmode[primitiveType];
|
GLenum mode = _primitiveToGLmode[primitiveType];
|
||||||
|
@ -167,389 +171,6 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) {
|
||||||
CHECK_GL_ERROR();
|
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
|
// 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
|
// 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
|
// 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) {
|
void GLBackend::do_glUseProgram(Batch& batch, uint32 paramOffset) {
|
||||||
|
|
||||||
_shader._program = batch._params[paramOffset]._uint;
|
_pipeline._program = batch._params[paramOffset]._uint;
|
||||||
glUseProgram(_shader._program);
|
// 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();
|
CHECK_GL_ERROR();
|
||||||
}
|
}
|
||||||
|
@ -998,49 +621,3 @@ void GLBackend::do_glColor4f(Batch& batch, uint32 paramOffset) {
|
||||||
CHECK_GL_ERROR();
|
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 void checkGLError();
|
||||||
|
|
||||||
|
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet());
|
||||||
|
|
||||||
|
|
||||||
class GLBuffer : public GPUObject {
|
class GLBuffer : public GPUObject {
|
||||||
|
@ -44,7 +45,7 @@ public:
|
||||||
GLBuffer();
|
GLBuffer();
|
||||||
~GLBuffer();
|
~GLBuffer();
|
||||||
};
|
};
|
||||||
static void syncGPUObject(const Buffer& buffer);
|
static GLBuffer* syncGPUObject(const Buffer& buffer);
|
||||||
static GLuint getBufferID(const Buffer& buffer);
|
static GLuint getBufferID(const Buffer& buffer);
|
||||||
|
|
||||||
class GLTexture : public GPUObject {
|
class GLTexture : public GPUObject {
|
||||||
|
@ -57,9 +58,33 @@ public:
|
||||||
GLTexture();
|
GLTexture();
|
||||||
~GLTexture();
|
~GLTexture();
|
||||||
};
|
};
|
||||||
static void syncGPUObject(const Texture& texture);
|
static GLTexture* syncGPUObject(const Texture& texture);
|
||||||
static GLuint getTextureID(const TexturePointer& 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_ATTRIBUTES = Stream::NUM_INPUT_SLOTS;
|
||||||
static const int MAX_NUM_INPUT_BUFFERS = 16;
|
static const int MAX_NUM_INPUT_BUFFERS = 16;
|
||||||
|
|
||||||
|
@ -145,18 +170,24 @@ protected:
|
||||||
_lastMode(GL_TEXTURE) {}
|
_lastMode(GL_TEXTURE) {}
|
||||||
} _transform;
|
} _transform;
|
||||||
|
|
||||||
// Shader Stage
|
// Pipeline Stage
|
||||||
|
void do_setPipeline(Batch& batch, uint32 paramOffset);
|
||||||
void do_setUniformBuffer(Batch& batch, uint32 paramOffset);
|
void do_setUniformBuffer(Batch& batch, uint32 paramOffset);
|
||||||
void do_setUniformTexture(Batch& batch, uint32 paramOffset);
|
void do_setUniformTexture(Batch& batch, uint32 paramOffset);
|
||||||
|
|
||||||
void updateShader();
|
void updatePipeline();
|
||||||
struct ShaderStageState {
|
struct PipelineStageState {
|
||||||
|
|
||||||
|
PipelinePointer _pipeline;
|
||||||
GLuint _program;
|
GLuint _program;
|
||||||
|
bool _invalidProgram;
|
||||||
|
|
||||||
ShaderStageState() :
|
PipelineStageState() :
|
||||||
_program(0) {}
|
_pipeline(),
|
||||||
} _shader;
|
_program(0),
|
||||||
|
_invalidProgram(false)
|
||||||
|
{}
|
||||||
|
} _pipeline;
|
||||||
|
|
||||||
|
|
||||||
// TODO: As long as we have gl calls explicitely issued from interface
|
// 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);
|
GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(texture);
|
||||||
|
|
||||||
// If GPU object already created and in sync
|
// 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 gpu object info is in sync with sysmem version
|
||||||
if (object->_contentStamp >= texture.getDataStamp()) {
|
if (object->_contentStamp >= texture.getDataStamp()) {
|
||||||
// Then all good, GPU object is ready to be used
|
// Then all good, GPU object is ready to be used
|
||||||
return;
|
return object;
|
||||||
} else {
|
} else {
|
||||||
// Need to update the content of the GPU object from the source sysmem of the texture
|
// Need to update the content of the GPU object from the source sysmem of the texture
|
||||||
needUpdate = true;
|
needUpdate = true;
|
||||||
}
|
}
|
||||||
} else if (!texture.isDefined()) {
|
} else if (!texture.isDefined()) {
|
||||||
// NO texture definition yet so let's avoid thinking
|
// NO texture definition yet so let's avoid thinking
|
||||||
return;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// need to have a gpu object?
|
// 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";
|
qDebug() << "GLBackend::syncGPUObject(const Texture&) case for Texture Type " << texture.getType() << " not supported";
|
||||||
}
|
}
|
||||||
CHECK_GL_ERROR();
|
CHECK_GL_ERROR();
|
||||||
|
|
||||||
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -328,8 +330,7 @@ GLuint GLBackend::getTextureID(const TexturePointer& texture) {
|
||||||
if (!texture) {
|
if (!texture) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
GLBackend::syncGPUObject(*texture);
|
GLTexture* object = GLBackend::syncGPUObject(*texture);
|
||||||
GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texture);
|
|
||||||
if (object) {
|
if (object) {
|
||||||
return object->_texture;
|
return object->_texture;
|
||||||
} else {
|
} 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
|
// The size in bytes of data stored in the resource
|
||||||
virtual Size getSize() const = 0;
|
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:
|
protected:
|
||||||
|
|
||||||
Resource() {}
|
Resource() {}
|
||||||
|
@ -140,12 +152,11 @@ protected:
|
||||||
|
|
||||||
Sysmem* _sysmem = NULL;
|
Sysmem* _sysmem = NULL;
|
||||||
|
|
||||||
mutable GPUObject* _gpuObject = NULL;
|
|
||||||
|
|
||||||
// This shouldn't be used by anything else than the Backend class with the proper casting.
|
// 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; }
|
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
|
||||||
GPUObject* getGPUObject() const { return _gpuObject; }
|
GPUObject* getGPUObject() const { return _gpuObject; }
|
||||||
|
|
||||||
friend class Backend;
|
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);
|
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.
|
// 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; }
|
void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
|
||||||
GPUObject* getGPUObject() const { return _gpuObject; }
|
GPUObject* getGPUObject() const { return _gpuObject; }
|
||||||
|
|
||||||
friend class Backend;
|
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 <glm/gtx/transform.hpp>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "SkyFromAtmosphere_vert.h"
|
||||||
|
#include "SkyFromAtmosphere_frag.h"
|
||||||
|
|
||||||
using namespace model;
|
using namespace model;
|
||||||
|
|
||||||
|
|
||||||
|
@ -131,6 +134,56 @@ void EarthSunModel::setSunLongitude(float lon) {
|
||||||
_sunLongitude = validateLongitude(lon);
|
_sunLongitude = validateLongitude(lon);
|
||||||
invalidate();
|
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 int NUM_DAYS_PER_YEAR = 365;
|
||||||
const float NUM_HOURS_PER_DAY = 24.0f;
|
const float NUM_HOURS_PER_DAY = 24.0f;
|
||||||
|
@ -150,6 +203,12 @@ SunSkyStage::SunSkyStage() :
|
||||||
setDayTime(12.0f);
|
setDayTime(12.0f);
|
||||||
// Begining of march
|
// Begining of march
|
||||||
setYearTime(60.0f);
|
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() {
|
SunSkyStage::~SunSkyStage() {
|
||||||
|
@ -205,5 +264,12 @@ void SunSkyStage::updateGraphicsObject() const {
|
||||||
double originAlt = _earthSunModel.getAltitude();
|
double originAlt = _earthSunModel.getAltitude();
|
||||||
_sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f));
|
_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
|
#ifndef hifi_model_Stage_h
|
||||||
#define hifi_model_Stage_h
|
#define hifi_model_Stage_h
|
||||||
|
|
||||||
|
#include "gpu/Pipeline.h"
|
||||||
|
|
||||||
#include "Light.h"
|
#include "Light.h"
|
||||||
|
|
||||||
namespace model {
|
namespace model {
|
||||||
|
@ -104,6 +106,60 @@ protected:
|
||||||
static Mat4d evalWorldToGeoLocationMat(double longitude, double latitude, double altitude, double scale);
|
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
|
// Sun sky stage generates the rendering primitives to display a scene realistically
|
||||||
// at the specified location and time around earth
|
// at the specified location and time around earth
|
||||||
class SunSkyStage {
|
class SunSkyStage {
|
||||||
|
@ -139,9 +195,13 @@ public:
|
||||||
float getSunIntensity() const { return getSunLight()->getIntensity(); }
|
float getSunIntensity() const { return getSunLight()->getIntensity(); }
|
||||||
|
|
||||||
LightPointer getSunLight() const { valid(); return _sunLight; }
|
LightPointer getSunLight() const { valid(); return _sunLight; }
|
||||||
|
AtmospherePointer getAtmosphere() const { valid(); return _atmosphere; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LightPointer _sunLight;
|
LightPointer _sunLight;
|
||||||
|
AtmospherePointer _atmosphere;
|
||||||
|
|
||||||
|
gpu::PipelinePointer _skyPipeline;
|
||||||
|
|
||||||
float _dayTime;
|
float _dayTime;
|
||||||
int _yearTime;
|
int _yearTime;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <QtCore/QUrlQuery>
|
#include <QtCore/QUrlQuery>
|
||||||
#include <QtNetwork/QHttpMultiPart>
|
#include <QtNetwork/QHttpMultiPart>
|
||||||
#include <QtNetwork/QNetworkRequest>
|
#include <QtNetwork/QNetworkRequest>
|
||||||
|
#include <QEventLoop>
|
||||||
#include <qthread.h>
|
#include <qthread.h>
|
||||||
|
|
||||||
#include <SettingHandle.h>
|
#include <SettingHandle.h>
|
||||||
|
@ -299,6 +300,8 @@ void AccountManager::processReply() {
|
||||||
passErrorToCallback(requestReply);
|
passErrorToCallback(requestReply);
|
||||||
}
|
}
|
||||||
delete requestReply;
|
delete requestReply;
|
||||||
|
|
||||||
|
emit replyFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) {
|
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() {
|
void AccountManager::persistAccountToSettings() {
|
||||||
if (_shouldPersistToSettingsFile) {
|
if (_shouldPersistToSettingsFile) {
|
||||||
// store this access token into the local settings
|
// store this access token into the local settings
|
||||||
|
|
|
@ -72,6 +72,8 @@ public:
|
||||||
void requestProfile();
|
void requestProfile();
|
||||||
|
|
||||||
DataServerAccountInfo& getAccountInfo() { return _accountInfo; }
|
DataServerAccountInfo& getAccountInfo() { return _accountInfo; }
|
||||||
|
|
||||||
|
void waitForAllPendingReplies();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void requestAccessToken(const QString& login, const QString& password);
|
void requestAccessToken(const QString& login, const QString& password);
|
||||||
|
@ -93,6 +95,8 @@ signals:
|
||||||
void loginFailed();
|
void loginFailed();
|
||||||
void logoutComplete();
|
void logoutComplete();
|
||||||
void balanceChanged(qint64 newBalance);
|
void balanceChanged(qint64 newBalance);
|
||||||
|
void replyFinished();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void processReply();
|
void processReply();
|
||||||
void handleKeypairGenerationError();
|
void handleKeypairGenerationError();
|
||||||
|
|
|
@ -61,7 +61,7 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall
|
||||||
params.errorCallbackReceiver = this;
|
params.errorCallbackReceiver = this;
|
||||||
params.errorCallbackMethod = "requestError";
|
params.errorCallbackMethod = "requestError";
|
||||||
}
|
}
|
||||||
|
|
||||||
accountManager.authenticatedRequest(USER_ACTIVITY_URL,
|
accountManager.authenticatedRequest(USER_ACTIVITY_URL,
|
||||||
QNetworkAccessManager::PostOperation,
|
QNetworkAccessManager::PostOperation,
|
||||||
params,
|
params,
|
||||||
|
@ -89,6 +89,8 @@ void UserActivityLogger::launch(QString applicationVersion) {
|
||||||
void UserActivityLogger::close() {
|
void UserActivityLogger::close() {
|
||||||
const QString ACTION_NAME = "close";
|
const QString ACTION_NAME = "close";
|
||||||
logAction(ACTION_NAME, QJsonObject());
|
logAction(ACTION_NAME, QJsonObject());
|
||||||
|
|
||||||
|
AccountManager::getInstance().waitForAllPendingReplies();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserActivityLogger::changedDisplayName(QString displayName) {
|
void UserActivityLogger::changedDisplayName(QString displayName) {
|
||||||
|
|
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())));
|
glmToBullet(_avatarData->getPosition())));
|
||||||
|
|
||||||
// XXX these values should be computed from the character model.
|
// 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 characterHeight = 1.75 - 2.0f * characterRadius;
|
||||||
btScalar stepHeight = btScalar(0.35);
|
btScalar stepHeight = btScalar(0.35);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
<@include DeferredLighting.slh@>
|
<@include DeferredLighting.slh@>
|
||||||
|
|
||||||
|
|
||||||
struct SphericalHarmonics {
|
struct SphericalHarmonics {
|
||||||
vec4 L00;
|
vec4 L00;
|
||||||
vec4 L1m1;
|
vec4 L1m1;
|
||||||
|
|
|
@ -270,6 +270,12 @@ void DeferredLightingEffect::render() {
|
||||||
batch.setUniformBuffer(locations->lightBufferUnit, globalLight->getSchemaBuffer());
|
batch.setUniformBuffer(locations->lightBufferUnit, globalLight->getSchemaBuffer());
|
||||||
gpu::GLBackend::renderBatch(batch);
|
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));
|
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;
|
locations.lightBufferUnit = -1;
|
||||||
}
|
}
|
||||||
#endif
|
#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();
|
program.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "ProgramObject.h"
|
#include "ProgramObject.h"
|
||||||
|
|
||||||
#include "model/Light.h"
|
#include "model/Light.h"
|
||||||
|
#include "model/Stage.h"
|
||||||
|
|
||||||
class AbstractViewStateInterface;
|
class AbstractViewStateInterface;
|
||||||
class PostLightingRenderable;
|
class PostLightingRenderable;
|
||||||
|
@ -73,6 +74,7 @@ public:
|
||||||
// update global lighting
|
// update global lighting
|
||||||
void setAmbientLightMode(int preset);
|
void setAmbientLightMode(int preset);
|
||||||
void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity);
|
void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity);
|
||||||
|
void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DeferredLightingEffect() {}
|
DeferredLightingEffect() {}
|
||||||
|
@ -89,6 +91,7 @@ private:
|
||||||
int radius;
|
int radius;
|
||||||
int ambientSphere;
|
int ambientSphere;
|
||||||
int lightBufferUnit;
|
int lightBufferUnit;
|
||||||
|
int atmosphereBufferUnit;
|
||||||
int invViewMat;
|
int invViewMat;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -146,6 +149,7 @@ private:
|
||||||
AbstractViewStateInterface* _viewState;
|
AbstractViewStateInterface* _viewState;
|
||||||
|
|
||||||
int _ambientLightMode = 0;
|
int _ambientLightMode = 0;
|
||||||
|
model::AtmospherePointer _atmosphere;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Simple interface for objects that require something to be rendered after deferred lighting.
|
/// Simple interface for objects that require something to be rendered after deferred lighting.
|
||||||
|
|
|
@ -299,73 +299,156 @@ void Model::initJointTransforms() {
|
||||||
|
|
||||||
void Model::init() {
|
void Model::init() {
|
||||||
if (!_program.isLinked()) {
|
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::Vertex, model_vert);
|
||||||
_program.addShaderFromSourceCode(QGLShader::Fragment, model_frag);
|
_program.addShaderFromSourceCode(QGLShader::Fragment, model_frag);
|
||||||
initProgram(_program, _locations);
|
initProgram(_program, _locations);
|
||||||
|
|
||||||
_normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
|
_normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
|
||||||
_normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
|
_normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
|
||||||
initProgram(_normalMapProgram, _normalMapLocations);
|
initProgram(_normalMapProgram, _normalMapLocations);
|
||||||
|
|
||||||
_specularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
_specularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||||
_specularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag);
|
_specularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag);
|
||||||
initProgram(_specularMapProgram, _specularMapLocations);
|
initProgram(_specularMapProgram, _specularMapLocations);
|
||||||
|
|
||||||
_normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
|
_normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
|
||||||
_normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag);
|
_normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag);
|
||||||
initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations);
|
initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations);
|
||||||
|
|
||||||
_translucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
_translucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||||
_translucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag);
|
_translucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag);
|
||||||
initProgram(_translucentProgram, _translucentLocations);
|
initProgram(_translucentProgram, _translucentLocations);
|
||||||
|
|
||||||
// Lightmap
|
// Lightmap
|
||||||
_lightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert);
|
_lightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert);
|
||||||
_lightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag);
|
_lightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag);
|
||||||
initProgram(_lightmapProgram, _lightmapLocations);
|
initProgram(_lightmapProgram, _lightmapLocations);
|
||||||
|
|
||||||
_lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert);
|
_lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert);
|
||||||
_lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag);
|
_lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag);
|
||||||
initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations);
|
initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations);
|
||||||
|
|
||||||
_lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert);
|
_lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert);
|
||||||
_lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag);
|
_lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag);
|
||||||
initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations);
|
initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations);
|
||||||
|
|
||||||
_lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert);
|
_lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert);
|
||||||
_lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag);
|
_lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag);
|
||||||
initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations);
|
initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations);
|
||||||
// end lightmap
|
// end lightmap
|
||||||
|
|
||||||
|
|
||||||
_shadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert);
|
_shadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert);
|
||||||
_shadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag);
|
_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
|
// Shadow program uses the same locations as standard rendering path but we still need to set the bindings
|
||||||
Model::Locations tempLoc;
|
Model::Locations tempLoc;
|
||||||
initProgram(_shadowProgram, tempLoc);
|
initProgram(_shadowProgram, tempLoc);
|
||||||
|
|
||||||
_skinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
|
_skinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
|
||||||
_skinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag);
|
_skinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag);
|
||||||
initSkinProgram(_skinProgram, _skinLocations);
|
initSkinProgram(_skinProgram, _skinLocations);
|
||||||
|
|
||||||
_skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert);
|
_skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert);
|
||||||
_skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
|
_skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
|
||||||
initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations);
|
initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations);
|
||||||
|
|
||||||
_skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
_skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||||
_skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag);
|
_skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag);
|
||||||
initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations);
|
initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations);
|
||||||
|
|
||||||
_skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert);
|
_skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert);
|
||||||
_skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag);
|
_skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag);
|
||||||
initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations);
|
initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations);
|
||||||
|
|
||||||
_skinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert);
|
_skinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert);
|
||||||
_skinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag);
|
_skinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag);
|
||||||
initSkinProgram(_skinShadowProgram, _skinShadowLocations);
|
initSkinProgram(_skinShadowProgram, _skinShadowLocations);
|
||||||
|
|
||||||
|
|
||||||
_skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
|
_skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
|
||||||
_skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag);
|
_skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag);
|
||||||
initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations);
|
initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations);
|
||||||
}
|
}
|
||||||
|
|
|
@ -309,6 +309,7 @@ private:
|
||||||
int _blendNumber;
|
int _blendNumber;
|
||||||
int _appliedBlendNumber;
|
int _appliedBlendNumber;
|
||||||
|
|
||||||
|
|
||||||
static ProgramObject _program;
|
static ProgramObject _program;
|
||||||
static ProgramObject _normalMapProgram;
|
static ProgramObject _normalMapProgram;
|
||||||
static ProgramObject _specularMapProgram;
|
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 "ShapeInfoTests.h"
|
||||||
#include "ShapeManagerTests.h"
|
#include "ShapeManagerTests.h"
|
||||||
#include "BulletUtilTests.h"
|
#include "BulletUtilTests.h"
|
||||||
|
#include "MeshInfoTests.h"
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
ShapeColliderTests::runAllTests();
|
ShapeColliderTests::runAllTests();
|
||||||
|
@ -20,5 +21,6 @@ int main(int argc, char** argv) {
|
||||||
ShapeInfoTests::runAllTests();
|
ShapeInfoTests::runAllTests();
|
||||||
ShapeManagerTests::runAllTests();
|
ShapeManagerTests::runAllTests();
|
||||||
BulletUtilTests::runAllTests();
|
BulletUtilTests::runAllTests();
|
||||||
|
MeshInfoTests::runAllTests();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,9 +192,17 @@ int main (int argc, char** argv) {
|
||||||
targetStringStream << "#ifndef scribe_" << targetName << "_h" << std::endl;
|
targetStringStream << "#ifndef scribe_" << targetName << "_h" << std::endl;
|
||||||
targetStringStream << "#define scribe_" << targetName << "_h" << std::endl << 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;
|
targetStringStream << "#endif" << std::endl;
|
||||||
} else {
|
} else {
|
||||||
targetStringStream << destStringStream.str();
|
targetStringStream << destStringStream.str();
|
||||||
|
|
Loading…
Reference in a new issue