diff --git a/examples/edit.js b/examples/edit.js
index b2e52eee20..50a66ea31f 100644
--- a/examples/edit.js
+++ b/examples/edit.js
@@ -38,6 +38,10 @@ var lightOverlayManager = new LightOverlayManager();
var cameraManager = new CameraManager();
var grid = Grid();
+gridTool = GridTool({
+ horizontalGrid: grid
+});
+gridTool.setVisible(false);
var entityListTool = EntityListTool();
@@ -341,7 +345,7 @@ var toolBar = (function() {
isActive = active;
if (!isActive) {
entityListTool.setVisible(false);
- // gridTool.setVisible(false);
+ gridTool.setVisible(false);
grid.setEnabled(false);
propertiesTool.setVisible(false);
selectionManager.clearSelections();
@@ -349,7 +353,7 @@ var toolBar = (function() {
} else {
hasShownPropertiesTool = false;
entityListTool.setVisible(true);
- // gridTool.setVisible(true);
+ gridTool.setVisible(true);
grid.setEnabled(true);
propertiesTool.setVisible(true);
Window.setFocus();
diff --git a/examples/html/gridControls.html b/examples/html/gridControls.html
index 1a3e949446..dd41125de4 100644
--- a/examples/html/gridControls.html
+++ b/examples/html/gridControls.html
@@ -33,8 +33,8 @@
elPosY.value = origin.y.toFixed(2);
}
- if (data.minorGridWidth !== undefined) {
- elMinorSpacing.value = data.minorGridWidth;
+ if (data.minorGridEvery !== undefined) {
+ elMinorSpacing.value = data.minorGridEvery;
}
if (data.majorGridEvery !== undefined) {
@@ -60,7 +60,7 @@
origin: {
y: elPosY.value,
},
- minorGridWidth: elMinorSpacing.value,
+ minorGridEvery: elMinorSpacing.value,
majorGridEvery: elMajorSpacing.value,
gridColor: gridColor,
colorIndex: gridColorIndex,
@@ -132,21 +132,21 @@
-
+
-
+
-
+
diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js
index 54f80e9c96..fbd2ec7ea0 100644
--- a/examples/libraries/gridTool.js
+++ b/examples/libraries/gridTool.js
@@ -12,24 +12,26 @@ Grid = function(opts) {
];
var colorIndex = 0;
var gridAlpha = 0.6;
- var origin = { x: 0, y: 0, z: 0 };
+ var origin = { x: 0, y: +MyAvatar.getJointPosition('LeftToeBase').y.toFixed(1) + 0.1, z: 0 };
+ var scale = 500;
+ var minorGridEvery = 1.0;
var majorGridEvery = 5;
- var minorGridWidth = 0.2;
var halfSize = 40;
- var yOffset = 0.001;
var worldSize = 16384;
var snapToGrid = false;
var gridOverlay = Overlays.addOverlay("grid", {
- position: { x: 0 , y: 0, z: 0 },
- visible: true,
+ rotation: Quat.fromPitchYawRollDegrees(90, 0, 0),
+ dimensions: { x: scale, y: scale, z: scale },
+ position: origin,
+ visible: false,
+ drawInFront: false,
color: colors[0],
alpha: gridAlpha,
- rotation: Quat.fromPitchYawRollDegrees(90, 0, 0),
- minorGridWidth: 0.1,
- majorGridEvery: 2,
+ minorGridEvery: minorGridEvery,
+ majorGridEvery: majorGridEvery,
});
that.visible = false;
@@ -39,17 +41,13 @@ Grid = function(opts) {
return origin;
}
- that.getMinorIncrement = function() { return minorGridWidth; };
- that.getMajorIncrement = function() { return minorGridWidth * majorGridEvery; };
-
- that.getMinorGridWidth = function() { return minorGridWidth; };
- that.setMinorGridWidth = function(value) {
- minorGridWidth = value;
+ that.getMinorIncrement = function() { return minorGridEvery; };
+ that.setMinorIncrement = function(value) {
+ minorGridEvery = value;
updateGrid();
- };
-
- that.getMajorGridEvery = function() { return majorGridEvery; };
- that.setMajorGridEvery = function(value) {
+ }
+ that.getMajorIncrement = function() { return majorGridEvery; };
+ that.setMajorIncrement = function(value) {
majorGridEvery = value;
updateGrid();
};
@@ -106,7 +104,7 @@ Grid = function(opts) {
dimensions = { x: 0, y: 0, z: 0 };
}
- var spacing = majorOnly ? (minorGridWidth * majorGridEvery) : minorGridWidth;
+ var spacing = majorOnly ? majorGridEvery : minorGridEvery;
position = Vec3.subtract(position, origin);
@@ -122,7 +120,7 @@ Grid = function(opts) {
return delta;
}
- var spacing = majorOnly ? (minorGridWidth * majorGridEvery) : minorGridWidth;
+ var spacing = majorOnly ? majorGridEvery : minorGridEvery;
var snappedDelta = {
x: Math.round(delta.x / spacing) * spacing,
@@ -135,9 +133,7 @@ Grid = function(opts) {
that.setPosition = function(newPosition, noUpdate) {
- origin = Vec3.subtract(newPosition, { x: 0, y: yOffset, z: 0 });
- origin.x = 0;
- origin.z = 0;
+ origin = { x: 0, y: newPosition.y, z: 0 };
updateGrid();
if (!noUpdate) {
@@ -149,7 +145,7 @@ Grid = function(opts) {
if (that.onUpdate) {
that.onUpdate({
origin: origin,
- minorGridWidth: minorGridWidth,
+ minorGridEvery: minorGridEvery,
majorGridEvery: majorGridEvery,
gridSize: halfSize,
visible: that.visible,
@@ -171,8 +167,8 @@ Grid = function(opts) {
that.setPosition(pos, true);
}
- if (data.minorGridWidth) {
- minorGridWidth = data.minorGridWidth;
+ if (data.minorGridEvery) {
+ minorGridEvery = data.minorGridEvery;
}
if (data.majorGridEvery) {
@@ -191,20 +187,22 @@ Grid = function(opts) {
that.setVisible(data.visible, true);
}
- updateGrid();
+ updateGrid(true);
}
- function updateGrid() {
+ function updateGrid(noUpdate) {
Overlays.editOverlay(gridOverlay, {
- position: { x: origin.y, y: origin.y, z: -origin.y },
+ position: { x: 0, y: origin.y, z: 0 },
visible: that.visible && that.enabled,
- minorGridWidth: minorGridWidth,
+ minorGridEvery: minorGridEvery,
majorGridEvery: majorGridEvery,
color: colors[colorIndex],
alpha: gridAlpha,
});
- that.emitUpdate();
+ if (!noUpdate) {
+ that.emitUpdate();
+ }
}
function cleanup() {
@@ -247,7 +245,7 @@ GridTool = function(opts) {
} else if (data.type == "update") {
horizontalGrid.update(data);
for (var i = 0; i < listeners.length; i++) {
- listeners[i](data);
+ listeners[i] && listeners[i](data);
}
} else if (data.type == "action") {
var action = data.action;
diff --git a/interface/src/audio/AudioScope.cpp b/interface/src/audio/AudioScope.cpp
index d0567c55d7..d92c5a2fda 100644
--- a/interface/src/audio/AudioScope.cpp
+++ b/interface/src/audio/AudioScope.cpp
@@ -117,8 +117,8 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) {
static const glm::vec4 inputColor = { 0.3f, 1.0f, 0.3f, 1.0f };
static const glm::vec4 outputLeftColor = { 1.0f, 0.3f, 0.3f, 1.0f };
static const glm::vec4 outputRightColor = { 0.3f, 0.3f, 1.0f, 1.0f };
- static const int gridRows = 2;
- int gridCols = _framesPerScope;
+ static const int gridCols = 2;
+ int gridRows = _framesPerScope;
int x = (width - (int)SCOPE_WIDTH) / 2;
int y = (height - (int)SCOPE_HEIGHT) / 2;
@@ -127,6 +127,12 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) {
gpu::Batch& batch = *renderArgs->_batch;
auto geometryCache = DependencyManager::get();
+
+ // Grid uses its own pipeline, so draw it before setting another
+ const float GRID_EDGE = 0.005f;
+ geometryCache->renderGrid(batch, glm::vec2(x, y), glm::vec2(x + w, y + h),
+ gridRows, gridCols, GRID_EDGE, gridColor, true, _audioScopeGrid);
+
geometryCache->useSimpleDrawPipeline(batch);
auto textureCache = DependencyManager::get();
batch.setResourceTexture(0, textureCache->getWhiteTexture());
@@ -139,7 +145,6 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) {
batch.setViewTransform(Transform());
geometryCache->renderQuad(batch, x, y, w, h, backgroundColor, _audioScopeBackground);
- geometryCache->renderGrid(batch, x, y, w, h, gridRows, gridCols, gridColor, _audioScopeGrid);
renderLineStrip(batch, _inputID, inputColor, x, y, _samplesPerScope, _scopeInputOffset, _scopeInput);
renderLineStrip(batch, _outputLeftID, outputLeftColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputLeft);
renderLineStrip(batch, _outputRightD, outputRightColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputRight);
diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp
index fca6a3796a..817e71a4da 100644
--- a/interface/src/ui/overlays/Grid3DOverlay.cpp
+++ b/interface/src/ui/overlays/Grid3DOverlay.cpp
@@ -13,6 +13,8 @@
#include
+#include
+
#include
#include
#include
@@ -20,17 +22,28 @@
QString const Grid3DOverlay::TYPE = "grid";
+const float DEFAULT_SCALE = 100.0f;
-Grid3DOverlay::Grid3DOverlay() :
- _minorGridWidth(1.0),
- _majorGridEvery(5) {
+Grid3DOverlay::Grid3DOverlay() {
+ setDimensions(DEFAULT_SCALE);
+ updateGrid();
}
Grid3DOverlay::Grid3DOverlay(const Grid3DOverlay* grid3DOverlay) :
Planar3DOverlay(grid3DOverlay),
- _minorGridWidth(grid3DOverlay->_minorGridWidth),
- _majorGridEvery(grid3DOverlay->_majorGridEvery)
+ _majorGridEvery(grid3DOverlay->_majorGridEvery),
+ _minorGridEvery(grid3DOverlay->_minorGridEvery)
{
+ updateGrid();
+}
+
+AABox Grid3DOverlay::getBounds() const {
+ if (_followCamera) {
+ // This is a UI element that should always be in view, lie to the octree to avoid culling
+ const AABox DOMAIN_BOX = AABox(glm::vec3(-TREE_SCALE / 2), TREE_SCALE);
+ return DOMAIN_BOX;
+ }
+ return Planar3DOverlay::getBounds();
}
void Grid3DOverlay::render(RenderArgs* args) {
@@ -38,15 +51,8 @@ void Grid3DOverlay::render(RenderArgs* args) {
return; // do nothing if we're not visible
}
- const int MINOR_GRID_DIVISIONS = 200;
- const int MAJOR_GRID_DIVISIONS = 100;
const float MAX_COLOR = 255.0f;
- // center the grid around the camera position on the plane
- glm::vec3 rotated = glm::inverse(getRotation()) * args->_viewFrustum->getPosition();
-
- float spacing = _minorGridWidth;
-
float alpha = getAlpha();
xColor color = getColor();
glm::vec4 gridColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
@@ -54,72 +60,65 @@ void Grid3DOverlay::render(RenderArgs* args) {
auto batch = args->_batch;
if (batch) {
+ auto minCorner = glm::vec2(-0.5f, -0.5f);
+ auto maxCorner = glm::vec2(0.5f, 0.5f);
+
+ auto position = getPosition();
+ if (_followCamera) {
+ // Get the camera position rounded to the nearest major grid line
+ // This grid is for UI and should lie on worldlines
+ auto cameraPosition =
+ (float)_majorGridEvery * glm::round(args->_viewFrustum->getPosition() / (float)_majorGridEvery);
+
+ position += glm::vec3(cameraPosition.x, 0.0f, cameraPosition.z);
+ }
+
Transform transform;
transform.setRotation(getRotation());
+ transform.setScale(glm::vec3(getDimensions(), 1.0f));
+ transform.setTranslation(position);
+ batch->setModelTransform(transform);
-
- // Minor grid
- {
- auto position = glm::vec3(_minorGridWidth * (floorf(rotated.x / spacing) - MINOR_GRID_DIVISIONS / 2),
- spacing * (floorf(rotated.y / spacing) - MINOR_GRID_DIVISIONS / 2),
- getPosition().z);
- float scale = MINOR_GRID_DIVISIONS * spacing;
-
- transform.setTranslation(position);
- transform.setScale(scale);
-
- batch->setModelTransform(transform);
-
- DependencyManager::get()->renderGrid(*batch, MINOR_GRID_DIVISIONS, MINOR_GRID_DIVISIONS, gridColor);
- }
-
- // Major grid
- {
- spacing *= _majorGridEvery;
- auto position = glm::vec3(spacing * (floorf(rotated.x / spacing) - MAJOR_GRID_DIVISIONS / 2),
- spacing * (floorf(rotated.y / spacing) - MAJOR_GRID_DIVISIONS / 2),
- getPosition().z);
- float scale = MAJOR_GRID_DIVISIONS * spacing;
-
- transform.setTranslation(position);
- transform.setScale(scale);
-
- // FIXME: THe line width of 4.0f is not supported anymore, we ll need a workaround
-
- batch->setModelTransform(transform);
-
- DependencyManager::get()->renderGrid(*batch, MAJOR_GRID_DIVISIONS, MAJOR_GRID_DIVISIONS, gridColor);
- }
+ const float MINOR_GRID_EDGE = 0.0025f;
+ const float MAJOR_GRID_EDGE = 0.005f;
+ DependencyManager::get()->renderGrid(*batch, minCorner, maxCorner,
+ _minorGridRowDivisions, _minorGridColDivisions, MINOR_GRID_EDGE,
+ _majorGridRowDivisions, _majorGridColDivisions, MAJOR_GRID_EDGE,
+ gridColor, _drawInFront);
}
}
const render::ShapeKey Grid3DOverlay::getShapeKey() {
- auto builder = render::ShapeKey::Builder();
- if (getAlpha() != 1.0f) {
- builder.withTranslucent();
- }
- return builder.build();
+ return render::ShapeKey::Builder().withOwnPipeline();
}
void Grid3DOverlay::setProperties(const QScriptValue& properties) {
Planar3DOverlay::setProperties(properties);
-
- if (properties.property("minorGridWidth").isValid()) {
- _minorGridWidth = properties.property("minorGridWidth").toVariant().toFloat();
+ if (properties.property("followCamera").isValid()) {
+ _followCamera = properties.property("followCamera").toVariant().toBool();
}
if (properties.property("majorGridEvery").isValid()) {
_majorGridEvery = properties.property("majorGridEvery").toVariant().toInt();
}
+
+ if (properties.property("minorGridEvery").isValid()) {
+ _minorGridEvery = properties.property("minorGridEvery").toVariant().toFloat();
+ }
+
+ updateGrid();
}
QScriptValue Grid3DOverlay::getProperty(const QString& property) {
- if (property == "minorGridWidth") {
- return _minorGridWidth;
+ if (property == "followCamera") {
+ return _followCamera;
}
if (property == "majorGridEvery") {
return _majorGridEvery;
}
+ if (property == "minorGridEvery") {
+ return _minorGridEvery;
+ }
return Planar3DOverlay::getProperty(property);
}
@@ -128,3 +127,16 @@ Grid3DOverlay* Grid3DOverlay::createClone() const {
return new Grid3DOverlay(this);
}
+void Grid3DOverlay::updateGrid() {
+ const int MAJOR_GRID_EVERY_MIN = 1;
+ const float MINOR_GRID_EVERY_MIN = 0.01f;
+
+ _majorGridEvery = std::max(_majorGridEvery, MAJOR_GRID_EVERY_MIN);
+ _minorGridEvery = std::max(_minorGridEvery, MINOR_GRID_EVERY_MIN);
+
+ _majorGridRowDivisions = getDimensions().x / _majorGridEvery;
+ _majorGridColDivisions = getDimensions().y / _majorGridEvery;
+
+ _minorGridRowDivisions = getDimensions().x / _minorGridEvery;
+ _minorGridColDivisions = getDimensions().y / _minorGridEvery;
+}
diff --git a/interface/src/ui/overlays/Grid3DOverlay.h b/interface/src/ui/overlays/Grid3DOverlay.h
index f9744f3954..3614a13000 100644
--- a/interface/src/ui/overlays/Grid3DOverlay.h
+++ b/interface/src/ui/overlays/Grid3DOverlay.h
@@ -24,6 +24,8 @@ public:
Grid3DOverlay();
Grid3DOverlay(const Grid3DOverlay* grid3DOverlay);
+ virtual AABox getBounds() const;
+
virtual void render(RenderArgs* args);
virtual const render::ShapeKey getShapeKey() override;
virtual void setProperties(const QScriptValue& properties);
@@ -31,9 +33,21 @@ public:
virtual Grid3DOverlay* createClone() const;
+ // Grids are UI tools, and may not be intersected (pickable)
+ virtual bool findRayIntersection(const glm::vec3&, const glm::vec3&, float&, BoxFace&, glm::vec3&) { return false; }
+
private:
- float _minorGridWidth;
- int _majorGridEvery;
+ void updateGrid();
+
+ bool _followCamera { true };
+
+ int _majorGridEvery { 5 };
+ float _majorGridRowDivisions;
+ float _majorGridColDivisions;
+
+ float _minorGridEvery { 1.0f };
+ float _minorGridRowDivisions;
+ float _minorGridColDivisions;
};
#endif // hifi_Grid3DOverlay_h
diff --git a/interface/src/ui/overlays/Planar3DOverlay.h b/interface/src/ui/overlays/Planar3DOverlay.h
index 63de15a8f8..0542a8b491 100644
--- a/interface/src/ui/overlays/Planar3DOverlay.h
+++ b/interface/src/ui/overlays/Planar3DOverlay.h
@@ -20,7 +20,7 @@ public:
Planar3DOverlay();
Planar3DOverlay(const Planar3DOverlay* planar3DOverlay);
- AABox getBounds() const;
+ virtual AABox getBounds() const;
glm::vec2 getDimensions() const { return _dimensions; }
void setDimensions(float value) { _dimensions = glm::vec2(value); }
diff --git a/libraries/gpu/src/gpu/Paint.slh b/libraries/gpu/src/gpu/Paint.slh
new file mode 100644
index 0000000000..5f49b20b30
--- /dev/null
+++ b/libraries/gpu/src/gpu/Paint.slh
@@ -0,0 +1,47 @@
+
+<@if not GPU_PAINT_SLH@>
+<@def GPU_PAINT_SLH@>
+
+float paintStripe(float value, float offset, float scale, float edge) {
+ float width = fwidth(value);
+ float normalizedWidth = width * scale;
+
+ float x0 = (value + offset) * scale - normalizedWidth / 2;
+ float x1 = x0 + normalizedWidth;
+
+ float balance = 1.0 - edge;
+ float i0 = edge * floor(x0) + max(0.0, fract(x0) - balance);
+ float i1 = edge * floor(x1) + max(0.0, fract(x1) - balance);
+ float strip = (i1 - i0) / normalizedWidth;
+
+ return clamp(strip, 0.0, 1.0);
+}
+
+float paintGrid(vec2 value, vec2 offset, vec2 scale, vec2 edge) {
+ return max(
+ paintStripe(value.x, offset.x, scale.x, edge.x),
+ paintStripe(value.y, offset.y, scale.y, edge.y));
+}
+
+float paintGridMajor(vec2 value, vec2 offset, vec2 scale, vec2 edge) {
+ return paintGrid(value, offset, scale, edge);
+}
+
+float paintGridMajorMinor(vec2 value, vec4 offset, vec4 scale, vec4 edge) {
+ return max(
+ paintGrid(value, offset.xy, scale.xy, edge.xy),
+ paintGrid(value, offset.zw, scale.zw, edge.zw));
+}
+
+<@endif@>
diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp
index ed6b8f2f5b..756e18dc8b 100644
--- a/libraries/render-utils/src/GeometryCache.cpp
+++ b/libraries/render-utils/src/GeometryCache.cpp
@@ -22,17 +22,19 @@
#include "TextureCache.h"
#include "RenderUtilsLogging.h"
-#include "standardTransformPNTC_vert.h"
-#include "standardDrawTexture_frag.h"
-
#include "gpu/StandardShaderLib.h"
#include "model/TextureMap.h"
+#include "standardTransformPNTC_vert.h"
+#include "standardDrawTexture_frag.h"
+
#include "simple_vert.h"
#include "simple_textured_frag.h"
#include "simple_textured_emisive_frag.h"
+#include "grid_frag.h"
+
//#define WANT_DEBUG
const int GeometryCache::UNKNOWN_ID = -1;
@@ -564,186 +566,49 @@ void GeometryCache::renderWireSphere(gpu::Batch& batch) {
renderWireShape(batch, Sphere);
}
+void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
+ int majorRows, int majorCols, float majorEdge,
+ int minorRows, int minorCols, float minorEdge,
+ const glm::vec4& color, bool isLayered, int id) {
+ static const glm::vec2 MIN_TEX_COORD(0.0f, 0.0f);
+ static const glm::vec2 MAX_TEX_COORD(1.0f, 1.0f);
-void GeometryCache::renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions, const glm::vec4& color) {
- IntPair key(xDivisions, yDivisions);
- Vec3Pair colorKey(glm::vec3(color.x, color.y, yDivisions), glm::vec3(color.z, color.y, xDivisions));
-
- int vertices = (xDivisions + 1 + yDivisions + 1) * 2;
- if (!_gridBuffers.contains(key)) {
- auto verticesBuffer = std::make_shared();
-
- float* vertexData = new float[vertices * 2];
- float* vertex = vertexData;
-
- for (int i = 0; i <= xDivisions; i++) {
- float x = (float)i / xDivisions;
-
- *(vertex++) = x;
- *(vertex++) = 0.0f;
-
- *(vertex++) = x;
- *(vertex++) = 1.0f;
- }
- for (int i = 0; i <= yDivisions; i++) {
- float y = (float)i / yDivisions;
-
- *(vertex++) = 0.0f;
- *(vertex++) = y;
-
- *(vertex++) = 1.0f;
- *(vertex++) = y;
- }
-
- verticesBuffer->append(sizeof(float) * vertices * 2, (gpu::Byte*) vertexData);
- delete[] vertexData;
-
- _gridBuffers[key] = verticesBuffer;
- }
-
- if (!_gridColors.contains(colorKey)) {
- auto colorBuffer = std::make_shared();
- _gridColors[colorKey] = colorBuffer;
-
- int compactColor = ((int(color.x * 255.0f) & 0xFF)) |
- ((int(color.y * 255.0f) & 0xFF) << 8) |
- ((int(color.z * 255.0f) & 0xFF) << 16) |
- ((int(color.w * 255.0f) & 0xFF) << 24);
-
- int* colorData = new int[vertices];
- int* colorDataAt = colorData;
-
- for(int v = 0; v < vertices; v++) {
- *(colorDataAt++) = compactColor;
- }
-
- colorBuffer->append(sizeof(int) * vertices, (gpu::Byte*) colorData);
- delete[] colorData;
- }
- gpu::BufferPointer verticesBuffer = _gridBuffers[key];
- gpu::BufferPointer colorBuffer = _gridColors[colorKey];
-
- const int VERTICES_SLOT = 0;
- const int COLOR_SLOT = 1;
- auto streamFormat = std::make_shared(); // 1 for everyone
-
- streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
- streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
-
- gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);
- gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element);
-
- batch.setInputFormat(streamFormat);
- batch.setInputBuffer(VERTICES_SLOT, verticesView);
- batch.setInputBuffer(COLOR_SLOT, colorView);
- batch.draw(gpu::LINES, vertices, 0);
-}
-
-// TODO: why do we seem to create extra BatchItemDetails when we resize the window?? what's that??
-void GeometryCache::renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id) {
- #ifdef WANT_DEBUG
- qCDebug(renderutils) << "GeometryCache::renderGrid(x["<(sizeof(GridSchema), (const gpu::Byte*) &gridSchema);
- if (registered && _registeredAlternateGridBuffers.contains(id)) {
- _registeredAlternateGridBuffers[id].reset();
- #ifdef WANT_DEBUG
- qCDebug(renderutils) << "renderGrid()... RELEASING REGISTERED VERTICES BUFFER";
- #endif
+ if (registered && _registeredGridBuffers.contains(id)) {
+ gridBuffer = _registeredGridBuffers[id];
}
- auto verticesBuffer = std::make_shared();
if (registered) {
- _registeredAlternateGridBuffers[id] = verticesBuffer;
- _lastRegisteredAlternateGridBuffers[id] = key;
+ _registeredGridBuffers[id] = gridBuffer;
+ _lastRegisteredGridBuffer[id] = key;
} else {
- _alternateGridBuffers[key] = verticesBuffer;
+ _gridBuffers[key] = gridBuffer;
}
- float* vertexData = new float[vertices * 2];
- float* vertex = vertexData;
-
- int dx = width / cols;
- int dy = height / rows;
- int tx = x;
- int ty = y;
-
- // Draw horizontal grid lines
- for (int i = rows + 1; --i >= 0; ) {
- *(vertex++) = x;
- *(vertex++) = ty;
-
- *(vertex++) = x + width;
- *(vertex++) = ty;
-
- ty += dy;
- }
- // Draw vertical grid lines
- for (int i = cols + 1; --i >= 0; ) {
- *(vertex++) = tx;
- *(vertex++) = y;
-
- *(vertex++) = tx;
- *(vertex++) = y + height;
- tx += dx;
- }
-
- verticesBuffer->append(sizeof(float) * vertices * 2, (gpu::Byte*) vertexData);
- delete[] vertexData;
+ gridBuffer.edit().period = glm::vec4(majorRows, majorCols, minorRows, minorCols);
+ gridBuffer.edit().offset.x = -(majorEdge / majorRows) / 2;
+ gridBuffer.edit().offset.y = -(majorEdge / majorCols) / 2;
+ gridBuffer.edit().offset.z = -(minorEdge / minorRows) / 2;
+ gridBuffer.edit().offset.w = -(minorEdge / minorCols) / 2;
+ gridBuffer.edit().edge = glm::vec4(glm::vec2(majorEdge),
+ // If rows or columns are not set, do not draw minor gridlines
+ glm::vec2((minorRows != 0 && minorCols != 0) ? minorEdge : 0.0f));
}
- if (!_gridColors.contains(colorKey)) {
- auto colorBuffer = std::make_shared();
- _gridColors[colorKey] = colorBuffer;
+ // Set the grid pipeline
+ useGridPipeline(batch, registered ? _registeredGridBuffers[id] : _gridBuffers[key], isLayered);
- int compactColor = ((int(color.x * 255.0f) & 0xFF)) |
- ((int(color.y * 255.0f) & 0xFF) << 8) |
- ((int(color.z * 255.0f) & 0xFF) << 16) |
- ((int(color.w * 255.0f) & 0xFF) << 24);
-
- int* colorData = new int[vertices];
- int* colorDataAt = colorData;
-
-
- for(int v = 0; v < vertices; v++) {
- *(colorDataAt++) = compactColor;
- }
-
- colorBuffer->append(sizeof(int) * vertices, (gpu::Byte*) colorData);
- delete[] colorData;
- }
- gpu::BufferPointer verticesBuffer = registered ? _registeredAlternateGridBuffers[id] : _alternateGridBuffers[key];
-
- gpu::BufferPointer colorBuffer = _gridColors[colorKey];
-
- const int VERTICES_SLOT = 0;
- const int COLOR_SLOT = 1;
- auto streamFormat = std::make_shared(); // 1 for everyone
-
- streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
- streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
-
- gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), streamFormat->getAttributes().at(gpu::Stream::POSITION)._element);
- gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element);
-
- batch.setInputFormat(streamFormat);
- batch.setInputBuffer(VERTICES_SLOT, verticesView);
- batch.setInputBuffer(COLOR_SLOT, colorView);
- batch.draw(gpu::LINES, vertices, 0);
+ renderQuad(batch, minCorner, maxCorner, MIN_TEX_COORD, MAX_TEX_COORD, color, id);
}
void GeometryCache::updateVertices(int id, const QVector& points, const glm::vec4& color) {
@@ -1772,7 +1637,6 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
auto state = std::make_shared();
-
// enable decal blend
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
@@ -1792,6 +1656,30 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
}
}
+void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool isLayered) {
+ if (!_gridPipeline) {
+ auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert));
+ auto ps = gpu::Shader::createPixel(std::string(grid_frag));
+ auto program = gpu::Shader::createProgram(vs, ps);
+ gpu::Shader::makeProgram((*program));
+ _gridSlot = program->getBuffers().findLocation("gridBuffer");
+
+ auto stateLayered = std::make_shared();
+ stateLayered->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
+ _gridPipelineLayered = gpu::Pipeline::create(program, stateLayered);
+
+ auto state = std::make_shared(stateLayered->getValues());
+ const float DEPTH_BIAS = 0.001f;
+ state->setDepthBias(DEPTH_BIAS);
+ state->setDepthTest(true, false, gpu::LESS_EQUAL);
+ _gridPipeline = gpu::Pipeline::create(program, state);
+ }
+
+ gpu::PipelinePointer pipeline = isLayered ? _gridPipelineLayered : _gridPipeline;
+ batch.setPipeline(pipeline);
+ batch.setUniformBuffer(_gridSlot, gridBuffer);
+}
+
class SimpleProgramKey {
diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h
index 32cdec56bf..b69ebf8531 100644
--- a/libraries/render-utils/src/GeometryCache.h
+++ b/libraries/render-utils/src/GeometryCache.h
@@ -31,8 +31,8 @@
class SimpleProgramKey;
-typedef glm::vec3 Vec3Key;
-
+typedef QPair Vec2FloatPair;
+typedef QPair Vec2FloatPairPair;
typedef QPair Vec2Pair;
typedef QPair Vec2PairPair;
typedef QPair Vec3Pair;
@@ -43,9 +43,10 @@ typedef QPair Vec3PairVec4Pair;
typedef QPair Vec4PairVec4;
typedef QPair Vec4PairVec4Pair;
-inline uint qHash(const glm::vec2& v, uint seed) {
+inline uint qHash(const Vec2FloatPairPair& v, uint seed) {
// multiply by prime numbers greater than the possible size
- return qHash(v.x + 5009 * v.y, seed);
+ return qHash(v.first.first.x + 5009 * v.first.first.y + 5011 * v.first.second +
+ 5021 * v.second.first.x + 5023 * v.second.first.y + 5039 * v.second.second);
}
inline uint qHash(const Vec2Pair& v, uint seed) {
@@ -203,8 +204,14 @@ public:
void renderWireSphere(gpu::Batch& batch);
size_t getSphereTriangleCount();
- void renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions, const glm::vec4& color);
- void renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id = UNKNOWN_ID);
+ void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
+ int majorRows, int majorCols, float majorEdge,
+ int minorRows, int minorCols, float minorEdge,
+ const glm::vec4& color, bool isLayered, int id = UNKNOWN_ID);
+ void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
+ int rows, int cols, float edge, const glm::vec4& color, bool isLayered, int id = UNKNOWN_ID) {
+ renderGrid(batch, minCorner, maxCorner, rows, cols, edge, 0, 0, 0.0f, color, isLayered, id);
+ }
void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID);
@@ -310,6 +317,19 @@ private:
gpu::BufferPointer _shapeVertices{ std::make_shared() };
gpu::BufferPointer _shapeIndices{ std::make_shared() };
+ class GridSchema {
+ public:
+ // data is arranged as majorRow, majorCol, minorRow, minorCol
+ glm::vec4 period;
+ glm::vec4 offset;
+ glm::vec4 edge;
+ };
+ using GridBuffer = gpu::BufferView;
+ void useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool isLayered);
+ gpu::PipelinePointer _gridPipeline;
+ gpu::PipelinePointer _gridPipelineLayered;
+ int _gridSlot;
+
class BatchItemDetails {
public:
static int population;
@@ -366,11 +386,9 @@ private:
QHash _dashedLines;
QHash _registeredDashedLines;
- QHash _gridBuffers;
- QHash _alternateGridBuffers;
- QHash _registeredAlternateGridBuffers;
- QHash _lastRegisteredAlternateGridBuffers;
- QHash _gridColors;
+ QHash _lastRegisteredGridBuffer;
+ QHash _gridBuffers;
+ QHash _registeredGridBuffers;
QHash > _networkGeometry;
diff --git a/libraries/render-utils/src/grid.slf b/libraries/render-utils/src/grid.slf
new file mode 100644
index 0000000000..901d343268
--- /dev/null
+++ b/libraries/render-utils/src/grid.slf
@@ -0,0 +1,44 @@
+<@include gpu/Config.slh@>
+<$VERSION_HEADER$>
+// Generated on <$_SCRIBE_DATE$>
+// grid.slf
+// fragment shader
+//
+// Created by Zach Pomerantz on 2/16/2016.
+// Copyright 2016 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 gpu/Paint.slh@>
+
+struct Grid {
+ vec4 period;
+ vec4 offset;
+ vec4 edge;
+};
+
+uniform gridBuffer { Grid grid; };
+Grid getGrid() { return grid; };
+
+in vec2 varTexCoord0;
+in vec4 varColor;
+
+out vec4 outFragColor;
+
+void main(void) {
+ Grid grid = getGrid();
+
+ float alpha;
+ if (grid.edge.z == 0.0) {
+ alpha = paintGrid(varTexCoord0, grid.offset.xy, grid.period.xy, grid.edge.xy);
+ } else {
+ alpha = paintGridMajorMinor(varTexCoord0, grid.offset, grid.period, grid.edge);
+ }
+ if (alpha == 0.0) {
+ discard;
+ }
+
+ outFragColor = vec4(varColor.xyz, varColor.w * alpha);
+}