mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-04 21:53:12 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into octree-shared-pointers
This commit is contained in:
commit
8a60bba4eb
51 changed files with 2185 additions and 414 deletions
|
@ -73,7 +73,7 @@ endfunction()
|
|||
|
||||
|
||||
macro(AUTOSCRIBE_SHADER_LIB)
|
||||
|
||||
message("Autoscribe running for ${TARGET_NAME}")
|
||||
file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
|
||||
foreach(HIFI_LIBRARY ${ARGN})
|
||||
#if (NOT TARGET ${HIFI_LIBRARY})
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
|
||||
macro(SETUP_HIFI_LIBRARY)
|
||||
|
||||
project(${TARGET_NAME})
|
||||
project(${TARGET_NAME})
|
||||
message("Setting up project ${TARGET_NAME}")
|
||||
|
||||
# grab the implemenation and header files
|
||||
file(GLOB_RECURSE LIB_SRCS "src/*.h" "src/*.cpp" "src/*.c")
|
||||
|
@ -33,5 +34,8 @@ macro(SETUP_HIFI_LIBRARY)
|
|||
foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES})
|
||||
target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE})
|
||||
endforeach()
|
||||
|
||||
# Don't make scribed shaders cumulative
|
||||
set(AUTOSCRIBE_SHADER_LIB_SRC "")
|
||||
|
||||
endmacro(SETUP_HIFI_LIBRARY)
|
76
examples/entityScripts/detectTouchExample.js
Normal file
76
examples/entityScripts/detectTouchExample.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// detectTouchExample.js
|
||||
// examples/entityScripts
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 9/3/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example of an entity script which when assigned to an entity, will detect when the entity is being touched by the avatars hands
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
Script.include("../libraries/utils.js");
|
||||
|
||||
var _this;
|
||||
|
||||
// this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember
|
||||
// our this object, so we can access it in cases where we're called without a this (like in the case of various global signals)
|
||||
DetectTouched = function() {
|
||||
_this = this;
|
||||
};
|
||||
|
||||
DetectTouched.prototype = {
|
||||
|
||||
// update() will be called regulary, because we've hooked the update signal in our preload() function.
|
||||
// we will check the avatars hand positions and if either hand is in our bounding box, we will notice that
|
||||
update: function() {
|
||||
// because the update() signal doesn't have a valid this, we need to use our memorized _this to access our entityID
|
||||
var entityID = _this.entityID;
|
||||
|
||||
var leftHandPosition = MyAvatar.getLeftPalmPosition();
|
||||
var rightHandPosition = MyAvatar.getRightPalmPosition();
|
||||
var props = Entities.getEntityProperties(entityID);
|
||||
var entityMinPoint = props.boundingBox.brn;
|
||||
var entityMaxPoint = props.boundingBox.tfl;
|
||||
|
||||
if (pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint) || pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint)) {
|
||||
|
||||
// remember we're being grabbed so we can detect being released
|
||||
_this.beingTouched = true;
|
||||
|
||||
// print out that we're being grabbed
|
||||
print("I'm being touched...");
|
||||
|
||||
} else if (_this.beingTouched) {
|
||||
|
||||
// if we are not being grabbed, and we previously were, then we were just released, remember that
|
||||
// and print out a message
|
||||
_this.beingTouched = false;
|
||||
print("I'm am no longer being touched...");
|
||||
}
|
||||
},
|
||||
|
||||
// preload() will be called when the entity has become visible (or known) to the interface
|
||||
// it gives us a chance to set our local JavaScript object up. In this case it means:
|
||||
// * remembering our entityID, so we can access it in cases where we're called without an entityID
|
||||
// * connecting to the update signal so we can check our grabbed state
|
||||
preload: function(entityID) {
|
||||
print("preload!");
|
||||
this.entityID = entityID;
|
||||
Script.update.connect(this.update);
|
||||
},
|
||||
|
||||
// unload() will be called when our entity is no longer available. It may be because we were deleted,
|
||||
// or because we've left the domain or quit the application. In all cases we want to unhook our connection
|
||||
// to the update signal
|
||||
unload: function(entityID) {
|
||||
Script.update.disconnect(this.update);
|
||||
},
|
||||
};
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new DetectTouched();
|
||||
})
|
170
examples/example/entities/particlesTest.js
Normal file
170
examples/example/entities/particlesTest.js
Normal file
|
@ -0,0 +1,170 @@
|
|||
//
|
||||
// particlesTest.js
|
||||
// examples/example/entities
|
||||
//
|
||||
// Created by David Rowe on 2 Sep 2015.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Click on the box entity to display different particle effects.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function () {
|
||||
var box,
|
||||
particles,
|
||||
particleExample = -1,
|
||||
NUM_PARTICLE_EXAMPLES = 11,
|
||||
PARTICLE_RADIUS = 0.04;
|
||||
|
||||
function onClickDownOnEntity(entityID) {
|
||||
if (entityID === box || entityID === particles) {
|
||||
particleExample = (particleExample + 1) % NUM_PARTICLE_EXAMPLES;
|
||||
|
||||
switch (particleExample) {
|
||||
case 0:
|
||||
print("Simple emitter");
|
||||
Entities.editEntity(particles, {
|
||||
velocitySpread: { x: 0.0, y: 0.0, z: 0.0 },
|
||||
accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 },
|
||||
radiusSpread: 0.0,
|
||||
animationIsPlaying: true
|
||||
});
|
||||
break;
|
||||
case 1:
|
||||
print("Velocity spread");
|
||||
Entities.editEntity(particles, {
|
||||
velocitySpread: { x: 0.1, y: 0.0, z: 0.1 }
|
||||
});
|
||||
break;
|
||||
case 2:
|
||||
print("Acceleration spread");
|
||||
Entities.editEntity(particles, {
|
||||
velocitySpread: { x: 0.0, y: 0.0, z: 0.0 },
|
||||
accelerationSpread: { x: 0.0, y: 0.1, z: 0.0 }
|
||||
});
|
||||
break;
|
||||
case 3:
|
||||
print("Radius spread");
|
||||
Entities.editEntity(particles, {
|
||||
accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 },
|
||||
radiusSpread: 0.035
|
||||
});
|
||||
break;
|
||||
case 4:
|
||||
print("Radius start and finish");
|
||||
Entities.editEntity(particles, {
|
||||
radiusSpread: 0.0,
|
||||
radiusStart: 0.0,
|
||||
radiusFinish: 0.0
|
||||
});
|
||||
break;
|
||||
case 5:
|
||||
print("Alpha 0.5");
|
||||
Entities.editEntity(particles, {
|
||||
radiusStart: PARTICLE_RADIUS,
|
||||
radiusFinish: PARTICLE_RADIUS,
|
||||
alpha: 0.5
|
||||
});
|
||||
break;
|
||||
case 6:
|
||||
print("Alpha spread");
|
||||
Entities.editEntity(particles, {
|
||||
alpha: 0.5,
|
||||
alphaSpread: 0.5
|
||||
});
|
||||
break;
|
||||
case 7:
|
||||
print("Alpha start and finish");
|
||||
Entities.editEntity(particles, {
|
||||
alphaSpread: 0.0,
|
||||
alpha: 1.0,
|
||||
alphaStart: 0.0,
|
||||
alphaFinish: 0.0
|
||||
});
|
||||
break;
|
||||
case 8:
|
||||
print("Color spread");
|
||||
Entities.editEntity(particles, {
|
||||
alpha: 1.0,
|
||||
alphaStart: 1.0,
|
||||
alphaFinish: 1.0,
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
colorSpread: { red: 128, green: 0, blue: 0 }
|
||||
});
|
||||
break;
|
||||
case 9:
|
||||
print("Color start and finish");
|
||||
Entities.editEntity(particles, {
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
colorSpread: { red: 0, green: 0, blue: 0 },
|
||||
colorStart: { red: 255, green: 0, blue: 0 },
|
||||
colorFinish: { red: 0, green: 255, blue: 0 }
|
||||
});
|
||||
break;
|
||||
case 10:
|
||||
print("Stop emitting");
|
||||
Entities.editEntity(particles, {
|
||||
colorStart: { red: 255, green: 255, blue: 255 },
|
||||
colorFinish: { red: 255, green: 255, blue: 255 },
|
||||
animationIsPlaying: false
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
var spawnPoint = Vec3.sum(MyAvatar.position, Vec3.multiply(4.0, Quat.getFront(Camera.getOrientation()))),
|
||||
animation = {
|
||||
fps: 30,
|
||||
frameIndex: 0,
|
||||
running: true,
|
||||
firstFrame: 0,
|
||||
lastFrame: 30,
|
||||
loop: true
|
||||
};
|
||||
|
||||
box = Entities.addEntity({
|
||||
type: "Box",
|
||||
position: spawnPoint,
|
||||
dimensions: { x: 0.3, y: 0.3, z: 0.3 },
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
lifetime: 3600 // 1 hour; just in case
|
||||
});
|
||||
|
||||
particles = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
position: spawnPoint,
|
||||
particleRadius: PARTICLE_RADIUS,
|
||||
radiusSpread: 0.0,
|
||||
emitRate: 2.0,
|
||||
emitVelocity: { x: 0.0, y: 1.0, z: 0.0 },
|
||||
velocitySpread: { x: 0.0, y: 0.0, z: 0.0 },
|
||||
emitAcceleration: { x: 0.0, y: -0.3, z: 0.0 },
|
||||
accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 },
|
||||
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
lifespan: 5.0,
|
||||
visible: true,
|
||||
locked: false,
|
||||
animationSettings: animation,
|
||||
animationIsPlaying: false,
|
||||
lifetime: 3600 // 1 hour; just in case
|
||||
});
|
||||
|
||||
Entities.clickDownOnEntity.connect(onClickDownOnEntity);
|
||||
|
||||
print("Click on the box to cycle through particle examples");
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
Entities.clickDownOnEntity.disconnect(onClickDownOnEntity);
|
||||
Entities.deleteEntity(particles);
|
||||
Entities.deleteEntity(box);
|
||||
}
|
||||
|
||||
setUp();
|
||||
Script.scriptEnding.connect(tearDown);
|
||||
}());
|
|
@ -146,3 +146,9 @@ getEyeRelativePosition = function(v) {
|
|||
getAvatarRelativeRotation = function(q) {
|
||||
return Quat.multiply(MyAvatar.orientation, q);
|
||||
}
|
||||
|
||||
pointInExtents = function(point, minPoint, maxPoint) {
|
||||
return (point.x >= minPoint.x && point.x <= maxPoint.x) &&
|
||||
(point.y >= minPoint.y && point.y <= maxPoint.y) &&
|
||||
(point.z >= minPoint.z && point.z <= maxPoint.z);
|
||||
}
|
|
@ -43,7 +43,7 @@
|
|||
emitVelocity: {x: 0, y: 5, z: 0},
|
||||
velocitySpread: {x: 2, y: 0, z: 2},
|
||||
emitAcceleration: {x: 0, y: -9.8, z: 0},
|
||||
textures: "https://raw.githubusercontent.com/ericrius1/SantasLair/santa/assets/smokeparticle.png",
|
||||
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
|
||||
color: color,
|
||||
lifespan: 1.0,
|
||||
visible: true,
|
||||
|
|
6
examples/shaders/exampleSkyboxUserDataV2.json
Normal file
6
examples/shaders/exampleSkyboxUserDataV2.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"ProceduralEntity":
|
||||
{
|
||||
"shaderUrl": "https://s3.amazonaws.com/Oculus/shadertoys/relentlessSkybox.fs"
|
||||
}
|
||||
}
|
144
examples/shaders/shadertoys/relentlessSkybox.fs
Normal file
144
examples/shaders/shadertoys/relentlessSkybox.fs
Normal file
|
@ -0,0 +1,144 @@
|
|||
// srtuss, 2013
|
||||
|
||||
// collecting some design ideas for a new game project.
|
||||
// no raymarching is used.
|
||||
|
||||
// if i could add a custom soundtrack, it'd use this one (essential for desired sensation)
|
||||
// http://www.youtube.com/watch?v=1uFAu65tZpo
|
||||
|
||||
//#define GREEN_VERSION
|
||||
|
||||
// ** improved camera shaking
|
||||
// ** cleaned up code
|
||||
// ** added stuff to the gates
|
||||
|
||||
// *******************************************************************************************
|
||||
// Please do NOT use this shader in your own productions/videos/games without my permission!
|
||||
// If you'd still like to do so, please drop me a mail (stral@aon.at)
|
||||
// *******************************************************************************************
|
||||
float time = iGlobalTime;
|
||||
|
||||
vec2 rotate(vec2 p, float a) {
|
||||
return vec2(p.x * cos(a) - p.y * sin(a), p.x * sin(a) + p.y * cos(a));
|
||||
}
|
||||
|
||||
float box(vec2 p, vec2 b, float r) {
|
||||
return length(max(abs(p) - b, 0.0)) - r;
|
||||
}
|
||||
|
||||
// iq's ray-plane-intersection code
|
||||
vec3 intersect(in vec3 o, in vec3 d, vec3 c, vec3 u, vec3 v)
|
||||
{
|
||||
vec3 q = o - c;
|
||||
return vec3(
|
||||
dot(cross(u, v), q),
|
||||
dot(cross(q, u), d),
|
||||
dot(cross(v, q), d)) / dot(cross(v, u), d);
|
||||
}
|
||||
|
||||
// some noise functions for fast developing
|
||||
float rand11(float p) {
|
||||
return fract(sin(p * 591.32) * 43758.5357);
|
||||
}
|
||||
float rand12(vec2 p) {
|
||||
return fract(sin(dot(p.xy, vec2(12.9898, 78.233))) * 43758.5357);
|
||||
}
|
||||
vec2 rand21(float p) {
|
||||
return fract(vec2(sin(p * 591.32), cos(p * 391.32)));
|
||||
}
|
||||
vec2 rand22(in vec2 p)
|
||||
{
|
||||
return fract(vec2(sin(p.x * 591.32 + p.y * 154.077), cos(p.x * 391.32 + p.y * 49.077)));
|
||||
}
|
||||
|
||||
float noise11(float p) {
|
||||
float fl = floor(p);
|
||||
return mix(rand11(fl), rand11(fl + 1.0), fract(p)); //smoothstep(0.0, 1.0, fract(p)));
|
||||
}
|
||||
float fbm11(float p) {
|
||||
return noise11(p) * 0.5 + noise11(p * 2.0) * 0.25 + noise11(p * 5.0) * 0.125;
|
||||
}
|
||||
vec3 noise31(float p) {
|
||||
return vec3(noise11(p), noise11(p + 18.952), noise11(p - 11.372)) * 2.0 - 1.0;
|
||||
}
|
||||
|
||||
// something that looks a bit like godrays coming from the surface
|
||||
float sky(vec3 p) {
|
||||
float a = atan(p.x, p.z);
|
||||
float t = time * 0.1;
|
||||
float v = rand11(floor(a * 4.0 + t)) * 0.5 + rand11(floor(a * 8.0 - t)) * 0.25
|
||||
+ rand11(floor(a * 16.0 + t)) * 0.125;
|
||||
return v;
|
||||
}
|
||||
|
||||
vec3 voronoi(in vec2 x)
|
||||
{
|
||||
vec2 n = floor(x); // grid cell id
|
||||
vec2 f = fract(x);// grid internal position
|
||||
vec2 mg;// shortest distance...
|
||||
vec2 mr;// ..and second shortest distance
|
||||
float md = 8.0, md2 = 8.0;
|
||||
for(int j = -1; j <= 1; j ++)
|
||||
{
|
||||
for(int i = -1; i <= 1; i ++)
|
||||
{
|
||||
vec2 g = vec2(float(i), float(j)); // cell id
|
||||
vec2 o = rand22(n + g);// offset to edge point
|
||||
vec2 r = g + o - f;
|
||||
|
||||
float d = max(abs(r.x), abs(r.y));// distance to the edge
|
||||
|
||||
if(d < md)
|
||||
{ md2 = md; md = d; mr = r; mg = g;}
|
||||
else if(d < md2)
|
||||
{ md2 = d;}
|
||||
}
|
||||
}
|
||||
return vec3(n + mg, md2 - md);
|
||||
}
|
||||
|
||||
|
||||
|
||||
vec3 getSkyboxColor() {
|
||||
vec3 rd = normalize(_normal);
|
||||
vec3 ro = vec3(0, 0, 1);
|
||||
float inten = 0.0;
|
||||
|
||||
// background
|
||||
float sd = dot(rd, vec3(0.0, 1.0, 0.0));
|
||||
inten = pow(1.0 - abs(sd), 20.0) + pow(sky(rd), 5.0) * step(0.0, rd.y) * 0.2;
|
||||
|
||||
vec3 its;
|
||||
float v, g;
|
||||
|
||||
// voronoi floor layers
|
||||
for(int i = 0; i < 4; i ++)
|
||||
{
|
||||
float layer = float(i);
|
||||
its = intersect(ro, rd, vec3(0.0, -5.0 - layer * 5.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0));
|
||||
if(its.x > 0.0)
|
||||
{
|
||||
vec3 vo = voronoi((its.yz) * 0.05 + 8.0 * rand21(float(i)));
|
||||
v = exp(-100.0 * (vo.z - 0.02));
|
||||
|
||||
float fx = 0.0;
|
||||
|
||||
// add some special fx to lowest layer
|
||||
if(i == 3)
|
||||
{
|
||||
float crd = 0.0; //fract(time * 0.2) * 50.0 - 25.0;
|
||||
float fxi = cos(vo.x * 0.2 + time * 1.5);//abs(crd - vo.x);
|
||||
fx = clamp(smoothstep(0.9, 1.0, fxi), 0.0, 0.9) * 1.0 * rand12(vo.xy);
|
||||
fx *= exp(-3.0 * vo.z) * 2.0;
|
||||
}
|
||||
inten += v * 0.1 + fx;
|
||||
}
|
||||
}
|
||||
|
||||
inten *= 0.4 + (sin(time) * 0.5 + 0.5) * 0.6;
|
||||
|
||||
vec3 ct = vec3(0.6, 0.8, 9.0);
|
||||
// find a color for the computed intensity
|
||||
vec3 col = pow(vec3(inten), ct);
|
||||
return col;
|
||||
}
|
11
examples/utilities/tests/allPerfTests.js
Normal file
11
examples/utilities/tests/allPerfTests.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// Created by Seiji Emery on 9/4/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
|
||||
//
|
||||
|
||||
Script.include("entityPerfTest.js");
|
||||
Script.include("mathPerfTest.js");
|
||||
Script.include("forLoopPerfTest.js");
|
107
examples/utilities/tests/entityPerfTest.js
Normal file
107
examples/utilities/tests/entityPerfTest.js
Normal file
|
@ -0,0 +1,107 @@
|
|||
//
|
||||
// Created by Seiji Emery on 9/4/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
|
||||
//
|
||||
|
||||
Script.include("perfTest.js");
|
||||
|
||||
function makeEntity () {
|
||||
return Entities.addEntity({
|
||||
type: "Box",
|
||||
position: Vec3.sum(MyAvatar.position, {
|
||||
x: 0.0, y: 0.0, z: 1.0
|
||||
}),
|
||||
dimensions: { x: 0.1, y: 0.1, z: 0.1 },
|
||||
userData: "fooooooooooooooooooooooo"
|
||||
});
|
||||
}
|
||||
|
||||
// Create + run tests
|
||||
(function () {
|
||||
var entityTests = new TestRunner();
|
||||
|
||||
entityTests.addTestCase('getEntityProperties')
|
||||
.before(function () {
|
||||
this.entity = makeEntity();
|
||||
})
|
||||
.after(function() {
|
||||
Entities.deleteEntity(this.entity);
|
||||
})
|
||||
.run(function() {
|
||||
var properties = Entities.getEntityProperties(this.entity);
|
||||
var foo = properties.userData;
|
||||
});
|
||||
|
||||
entityTests.addTestCase('add + delete entity')
|
||||
.run(function() {
|
||||
var entity = makeEntity();
|
||||
Entities.deleteEntity(entity);
|
||||
});
|
||||
entityTests.addTestCase('update entity')
|
||||
.before(function () {
|
||||
this.entity = makeEntity();
|
||||
})
|
||||
.after(function () {
|
||||
Entities.deleteEntity(this.entity);
|
||||
})
|
||||
.run(function() {
|
||||
Entities.editEntity(this.entity, { userData: "barrrrrrr" });
|
||||
});
|
||||
|
||||
TestCase.prototype.withEntityOp = function(op) {
|
||||
this.before(function(){
|
||||
this.entity = makeEntity();
|
||||
})
|
||||
this.after(function(){
|
||||
Entities.deleteEntity(this.entity);
|
||||
})
|
||||
this.run(op);
|
||||
}
|
||||
entityTests.addTestCase('find closest entity')
|
||||
.withEntityOp(function() {
|
||||
Entities.findClosestEntity(this.entity, MyAvatar.position, 100.0);
|
||||
})
|
||||
entityTests.addTestCase('findEntities')
|
||||
.withEntityOp(function(){
|
||||
Entities.findEntities(this.entity, MyAvatar.position, 10.0);
|
||||
})
|
||||
entityTests.addTestCase('findEntitiesInBox')
|
||||
.withEntityOp(function(){
|
||||
Entities.findEntitiesInBox(this.entity, MyAvatar.position, {x: 10.0, y: 10.0, z: 10.0});
|
||||
})
|
||||
|
||||
TestCase.prototype.withRay = function(op) {
|
||||
this.before(function(){
|
||||
this.ray = Camera.computePickRay(500, 200);
|
||||
});
|
||||
this.run(op);
|
||||
}
|
||||
entityTests.addTestCase('findRayIntersection, precisionPicking=true')
|
||||
.withRay(function(){
|
||||
Entities.findRayIntersection(this.ray, true);
|
||||
})
|
||||
entityTests.addTestCase('findRayIntersection, precisionPicking=false')
|
||||
.withRay(function(){
|
||||
Entities.findRayIntersection(this.ray, false);
|
||||
});
|
||||
entityTests.addTestCase('findRayIntersectionBlocking, precisionPicking=true')
|
||||
.withRay(function(){
|
||||
Entities.findRayIntersectionBlocking(this.ray, true);
|
||||
})
|
||||
entityTests.addTestCase('findRayIntersectionBlocking, precisionPicking=false')
|
||||
.withRay(function(){
|
||||
Entities.findRayIntersectionBlocking(this.ray, false);
|
||||
})
|
||||
entityTests.addTestCase('no-op')
|
||||
.run(function(){});
|
||||
|
||||
print("Running entity tests");
|
||||
entityTests.runAllTestsWithIterations([10, 100, 1000], 1e3, 10);
|
||||
entityTests.writeResultsToLog();
|
||||
})();
|
||||
|
||||
|
||||
|
140
examples/utilities/tests/forLoopPerfTest.js
Normal file
140
examples/utilities/tests/forLoopPerfTest.js
Normal file
|
@ -0,0 +1,140 @@
|
|||
//
|
||||
// Created by Seiji Emery on 9/4/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
|
||||
//
|
||||
// Checks various types of js iteration (for loops, for/in loops, Array.forEach, and Object.keys)
|
||||
// for speed + efficiency. Mostly a sanity check for my own code.
|
||||
//
|
||||
|
||||
Script.include("perfTest.js");
|
||||
|
||||
(function () {
|
||||
var input1 = [];
|
||||
var input2 = [];
|
||||
var N = 1000;
|
||||
for (var i = 0; i < N; ++i) {
|
||||
input1.push(Math.random());
|
||||
input2.push(Math.random());
|
||||
}
|
||||
TestCase.prototype.withArray = function(n, func) {
|
||||
this.before(function () {
|
||||
this.array = [];
|
||||
for (var i = 0; i < n; ++i) {
|
||||
this.array.push(0);
|
||||
}
|
||||
});
|
||||
this.run(fcn);
|
||||
}
|
||||
|
||||
print("For loop test -- prelim tests");
|
||||
var prelimTests = new TestRunner();
|
||||
prelimTests.addTestCase('Array.push (test component)')
|
||||
.before(function () {
|
||||
this.array = [];
|
||||
})
|
||||
.run(function () {
|
||||
this.array.push(1);
|
||||
});
|
||||
prelimTests.addTestCase('Array.push with mul op (test component)')
|
||||
.before(function() {
|
||||
this.array = [];
|
||||
})
|
||||
.run(function (i) {
|
||||
this.array.push(input1[i] * Math.PI);
|
||||
})
|
||||
prelimTests.runAllTestsWithIterations([1e4, 1e5, 1e6], 1e6, 10);
|
||||
|
||||
print("For loop test (n = " + N + ")");
|
||||
var loopTests = new TestRunner();
|
||||
loopTests.addTestCase('for (var i = 0; i < n; ++i) { ... }')
|
||||
.before(function () {
|
||||
this.array = [];
|
||||
})
|
||||
.run(function () {
|
||||
for (var i = 0; i < N; ++i) {
|
||||
this.array.push(input1[i] * Math.PI);
|
||||
}
|
||||
})
|
||||
loopTests.addTestCase('while (n --> 0) { ... } (reversed)')
|
||||
.before(function () {
|
||||
this.array = [];
|
||||
})
|
||||
.run(function () {
|
||||
var n = N;
|
||||
while (n --> 0) {
|
||||
this.array.push(input1[n] * Math.PI);
|
||||
}
|
||||
})
|
||||
loopTests.addTestCase('Array.forEach(function(v, i) { ... })')
|
||||
.before(function () {
|
||||
this.array = [];
|
||||
})
|
||||
.run(function () {
|
||||
input1.forEach(function(v) {
|
||||
this.array.push(v * Math.PI);
|
||||
}, this);
|
||||
})
|
||||
loopTests.addTestCase('Array.map(function(v, i) { ... })')
|
||||
.run(function () {
|
||||
this.array = input1.map(function (v) {
|
||||
return v * Math.PI;
|
||||
}, this);
|
||||
});
|
||||
loopTests.runAllTestsWithIterations([10, 100, 1000], 1e3, 10);
|
||||
|
||||
|
||||
// Test iteration on object keys
|
||||
|
||||
// http://stackoverflow.com/questions/10726909/random-alpha-numeric-string-in-javascript
|
||||
function makeRandomString(length, chars) {
|
||||
var result = '';
|
||||
for (var i = length; i > 0; --i) result += chars[Math.round(Math.random() * (chars.length - 1))];
|
||||
return result;
|
||||
}
|
||||
function randomString () {
|
||||
var n = Math.floor(Math.random() * 18) + 12;
|
||||
return makeRandomString(n, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
|
||||
}
|
||||
|
||||
var obj = {}, numKeys = 1000;
|
||||
while (numKeys --> 0) {
|
||||
obj[randomString()] = Math.floor(Math.random() * 255);
|
||||
}
|
||||
print("Object iter tests (object has " + Object.keys(obj).length + " keys)");
|
||||
var iterTests = new TestRunner();
|
||||
iterTests.addTestCase('for (var k in obj) { foo(obj[k]); }')
|
||||
.before(function () {
|
||||
this.x = 0;
|
||||
})
|
||||
.run(function () {
|
||||
for (var k in obj) {
|
||||
this.x = (this.x + obj[k]) % 256;
|
||||
}
|
||||
});
|
||||
iterTests.addTestCase('for (var k in obj) { if (Object.hasOwnProperty(obj, k)) { foo(obj[k]); } }')
|
||||
.before(function () {
|
||||
this.x = 0;
|
||||
})
|
||||
.run(function () {
|
||||
for (var k in obj) {
|
||||
if (Object.hasOwnProperty(obj, k)) {
|
||||
this.x = (this.x + obj[k]) % 256;
|
||||
}
|
||||
}
|
||||
})
|
||||
iterTests.addTestCase('Object.keys(obj).forEach(function(k) { foo(obj[k]); }')
|
||||
.before(function () {
|
||||
this.x = 0;
|
||||
})
|
||||
.run(function () {
|
||||
Object.keys(obj).forEach(function (k) {
|
||||
this.x = (this.x + obj[k]) % 256;
|
||||
})
|
||||
})
|
||||
|
||||
iterTests.runAllTestsWithIterations([10, 100, 1000], 1e3, 10);
|
||||
})();
|
||||
|
127
examples/utilities/tests/mathPerfTest.js
Normal file
127
examples/utilities/tests/mathPerfTest.js
Normal file
|
@ -0,0 +1,127 @@
|
|||
//
|
||||
// Created by Seiji Emery on 9/4/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
|
||||
//
|
||||
|
||||
Script.include("perfTest.js");
|
||||
|
||||
// Native vec3 (for comparison)
|
||||
var Native = {};
|
||||
(function () {
|
||||
Native.Vec3 = function (x, y, z) {
|
||||
this.x = x || 0.0;
|
||||
this.y = y || 0.0;
|
||||
this.z = z || 0.0;
|
||||
}
|
||||
Native.Vec3.prototype.add = function (other) {
|
||||
this.x += other.x;
|
||||
this.y += other.y;
|
||||
this.z += other.z;
|
||||
}
|
||||
Native.Vec3.prototype.distance = function (other) {
|
||||
var rx = this.x - other.x;
|
||||
var ry = this.y - other.y;
|
||||
var rz = this.z - other.z;
|
||||
return Math.sqrt(rx * rx + ry * ry + rz * rz);
|
||||
}
|
||||
Native.Vec3.prototype.dist2 = function (other) {
|
||||
var rx = this.x - other.x;
|
||||
var ry = this.y - other.y;
|
||||
var rz = this.z - other.z;
|
||||
return rx * rx + ry * ry + rz * rz;
|
||||
}
|
||||
|
||||
Native.Quaternion = function (x, y, z, w) {
|
||||
this.x = x || 0.0;
|
||||
this.y = y || 0.0;
|
||||
this.z = z || 0.0;
|
||||
this.w = w || 0.0;
|
||||
}
|
||||
// Pulled from THREE.js
|
||||
Native.Quaternion.prototype.multiply = function(quat2) {
|
||||
var qax = this.x, qay = this.y, qaz = this.z, qaw = this.w,
|
||||
qbx = quat2.x, qby = quat2.y, qbz = quat2.z, qbw = quat2.w;
|
||||
this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
|
||||
this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
|
||||
this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
|
||||
this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
|
||||
return this;
|
||||
}
|
||||
})();
|
||||
|
||||
// Create + run tests
|
||||
(function () {
|
||||
var mathTests = new TestRunner();
|
||||
var foo;
|
||||
|
||||
print("math tests:");
|
||||
var iterations = [ 1000, 10000, 100000, 1000000 ];
|
||||
|
||||
print("builtin Vec3 + Quat (wrapped glm::vec3 + glm::quat)");
|
||||
var builtinTests = new TestRunner();
|
||||
builtinTests.addTestCase('Vec3.sum')
|
||||
.run(function () {
|
||||
foo = Vec3.sum({x: 10, y: 12, z: 3}, {x: 1, y: 2, z: 4});
|
||||
})
|
||||
builtinTests.addTestCase('Vec3.distance')
|
||||
.run(function () {
|
||||
foo = Vec3.distance({x: 1209, y: 298, z: 238}, {x: 239, y: 20, z: 23})
|
||||
})
|
||||
builtinTests.addTestCase('Quat.multiply')
|
||||
.run(function () {
|
||||
foo = Quat.multiply({x: 2190.0, y: 2109.0, z: 1209.0, w: 829.0}, {x: -1293.0, y: 1029.1, z: 2190.1, w: 129.0})
|
||||
});
|
||||
builtinTests.runAllTestsWithIterations([ 1e3, 1e4, 1e5 ], 1e3, 10);
|
||||
|
||||
print("");
|
||||
print("native JS Vec3 + Quaternion");
|
||||
var nativeTests = new TestRunner();
|
||||
nativeTests.addTestCase('Native Vec3.sum')
|
||||
.run(function () {
|
||||
foo = new Native.Vec3(10, 12, 3).add(new Native.Vec3(1, 2, 4));
|
||||
})
|
||||
nativeTests.addTestCase('Native Vec3.distance')
|
||||
.run(function () {
|
||||
foo = new Native.Vec3(1209, 298, 238).distance(new Native.Vec3(239, 20, 23));
|
||||
})
|
||||
nativeTests.addTestCase('Native Vec3.dist2')
|
||||
.run(function () {
|
||||
foo = new Native.Vec3(1209, 298, 238).dist2(new Native.Vec3(239, 20, 23));
|
||||
})
|
||||
nativeTests.addTestCase('Native Quat.multiply')
|
||||
.run(function () {
|
||||
foo = new Native.Quaternion(2190.0, 2109.0, 1209.0, 829.0).multiply(new Native.Quaternion(-1293.0, 1029.1, 2190.1, 129.0));
|
||||
});
|
||||
nativeTests.runAllTestsWithIterations([ 1e3, 1e4, 1e5, 1e6 ], 1e6, 10);
|
||||
|
||||
print("");
|
||||
print("no-ops (for test assignment / construction overhead)")
|
||||
mathTests.addTestCase('no-op')
|
||||
.run(function(){});
|
||||
mathTests.addTestCase('assign null')
|
||||
.run(function () {
|
||||
foo = null;
|
||||
});
|
||||
mathTests.addTestCase('assign object')
|
||||
.run(function () {
|
||||
foo = { x: 1902, y: 129, z: 21 };
|
||||
});
|
||||
mathTests.addTestCase('Native Vec3.construct -- 3 args')
|
||||
.run(function () {
|
||||
foo = new Native.Vec3(1209, 298, 238);
|
||||
});
|
||||
mathTests.addTestCase('Native Vec3.construct -- 2 args')
|
||||
.run(function () {
|
||||
foo = new Native.Vec3(1209, 298);
|
||||
});
|
||||
mathTests.addTestCase('Native Vec3.construct -- no args')
|
||||
.run(function() {
|
||||
foo = new Native.Vec3();
|
||||
});
|
||||
|
||||
mathTests.runAllTestsWithIterations([1e3, 1e4, 1e5, 1e6], 1e6, 10);
|
||||
mathTests.writeResultsToLog();
|
||||
})();
|
155
examples/utilities/tests/perfTest.js
Normal file
155
examples/utilities/tests/perfTest.js
Normal file
|
@ -0,0 +1,155 @@
|
|||
//
|
||||
// Created by Seiji Emery on 9/4/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
|
||||
//
|
||||
// Simple benchmarking library. See the test scripts for example usage.
|
||||
//
|
||||
|
||||
(function () {
|
||||
// Runs multiple 'test cases' (benchmarks that get invoked w/ varying iteration counts)
|
||||
function TestRunner () {
|
||||
this._testCases = {};
|
||||
this._testResults = [];
|
||||
}
|
||||
this.TestRunner = TestRunner;
|
||||
|
||||
// Add a test case. Define behavior by declaratively calling .before, .after, and .run w/ impls.
|
||||
TestRunner.prototype.addTestCase = function (name) {
|
||||
var testcase = new TestCase(name);
|
||||
this._testCases[name] = testcase;
|
||||
return testcase;
|
||||
}
|
||||
|
||||
// Runs a function n times. Uses context object so it runs sandboxed.
|
||||
function runTimedWithIterations (f, context, numIterations) {
|
||||
var start = new Date().getTime();
|
||||
while (numIterations --> 0) {
|
||||
f.apply(context);
|
||||
}
|
||||
var end = new Date().getTime();
|
||||
return end - start;
|
||||
}
|
||||
|
||||
function fmtSecs (secs) {
|
||||
if (secs >= 1.0) {
|
||||
return ""+secs.toFixed(3)+" secs";
|
||||
} else if (secs >= 1e-3) {
|
||||
return ""+(secs * 1e3).toFixed(3)+" ms";
|
||||
} else if (secs >= 1e-6) {
|
||||
return ""+(secs * 1e6).toFixed(3)+" µs";
|
||||
} else {
|
||||
return ""+(secs * 1e9).toFixed(3)+" ns";
|
||||
}
|
||||
}
|
||||
function avg(samples) {
|
||||
return samples.length ?
|
||||
samples.reduce(function(a, b){return a+b;}, 0.0) / samples.length : 0.0;
|
||||
}
|
||||
|
||||
// Runs a named performance test for multiple iterations, and optionally calculates an average.
|
||||
// @param name: the test name registered with addTest
|
||||
// @param iterations: a list of iteration sequences. eg. [10, 100, 1000] => runs for 10, then 100, then 1000 iterations
|
||||
// and prints the timing info for each (in ms)
|
||||
// @param iterationsForAvg: optional
|
||||
// @param samplesForAvg: optional
|
||||
// After running iterations, will compute an average if iterationsForAvg and samplesForAvg are both set:
|
||||
// average :=
|
||||
// collects n samples by running the testcase n times with i iterations
|
||||
// where n = samplesForAvg, i = iterationsForAvg
|
||||
// we then average the samples, and print that.
|
||||
//
|
||||
TestRunner.prototype.runPerfTestWithIterations = function (name, iterations, iterationsForAvg, samplesForAvg) {
|
||||
if (!this._testCases[name]) {
|
||||
print("No test case with name '" + name + "'!");
|
||||
}
|
||||
var testcase = this._testCases[name];
|
||||
|
||||
var runAverages = []; // secs
|
||||
|
||||
var noErrors = true;
|
||||
iterations.forEach(function(n, i) {
|
||||
var sandbox = {};
|
||||
try {
|
||||
if (testcase.setupFunction) {
|
||||
testcase.setupFunction.apply(sandbox);
|
||||
}
|
||||
|
||||
var dt = runTimedWithIterations(testcase.runFunction, sandbox, n);
|
||||
|
||||
if (testcase.teardownFunction) {
|
||||
testcase.teardownFunction.apply(sandbox);
|
||||
}
|
||||
|
||||
this._testResults.push(""+name+" with "+n+" iterations: "+dt+" ms");
|
||||
} catch (e) {
|
||||
this._testResults.push("Testcase '"+name+"':"+i+" ("+n+") failed with error: "+e);
|
||||
noErrors = false;
|
||||
}
|
||||
}, this);
|
||||
this.writeResultsToLog();
|
||||
if (noErrors && iterationsForAvg && samplesForAvg) {
|
||||
try {
|
||||
var samples = [];
|
||||
for (var n = samplesForAvg; n --> 0; ) {
|
||||
var sandbox = {};
|
||||
if (testcase.setupFunction) {
|
||||
testcase.setupFunction.apply(sandbox);
|
||||
}
|
||||
|
||||
var dt = runTimedWithIterations(testcase.runFunction, sandbox, iterationsForAvg);
|
||||
|
||||
if (testcase.teardownFunction) {
|
||||
testcase.teardownFunction.apply(sandbox);
|
||||
}
|
||||
samples.push(dt / iterationsForAvg * 1e-3); // dt in ms
|
||||
}
|
||||
print(" average: " + ((avg(samples) * 1e6).toFixed(3)) + " µs")
|
||||
// print("\t(" + samplesForAvg + " samples with " + iterationsForAvg + " iterations)");
|
||||
} catch (e) {
|
||||
print("Error while calculating average: " + e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Runs all registered tests w/ iteration + average parameters
|
||||
TestRunner.prototype.runAllTestsWithIterations = function (iterations, iterationsForAvg, samplesForAvg) {
|
||||
Object.keys(this._testCases).forEach(function(name) {
|
||||
this.runPerfTestWithIterations(name, iterations, iterationsForAvg, samplesForAvg);
|
||||
}, this);
|
||||
}
|
||||
|
||||
// Dump results to the debug log. You don't need to call this.
|
||||
TestRunner.prototype.writeResultsToLog = function () {
|
||||
var s = ' ' + this._testResults.join('\n ');
|
||||
this._testResults = [];
|
||||
// print(s);
|
||||
s.split('\n').forEach(function(line) {
|
||||
print(line);
|
||||
});
|
||||
}
|
||||
|
||||
// Implements a benchmark test case, that has optional setup = teardown code, and a (non-optional) run function.
|
||||
// setup + teardown get called once, and run gets called for n sequential iterations (see TestRunner.runTestWithIterations)
|
||||
// setup, run, and teardown all get applied to the same sandboxed this object, so use that for storing test data for each run.
|
||||
function TestCase (name) {
|
||||
this.name = name;
|
||||
this.setupFunction = null;
|
||||
this.runFunction = null;
|
||||
this.teardownFunction = null;
|
||||
}
|
||||
this.TestCase = TestCase;
|
||||
TestCase.prototype.before = function (f) {
|
||||
this.setupFunction = f;
|
||||
return this;
|
||||
}
|
||||
TestCase.prototype.after = function (f) {
|
||||
this.teardownFunction = f;
|
||||
return this;
|
||||
}
|
||||
TestCase.prototype.run = function (f) {
|
||||
this.runFunction = f;
|
||||
}
|
||||
})();
|
|
@ -113,7 +113,7 @@ endif()
|
|||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
|
||||
# link required hifi libraries
|
||||
link_hifi_libraries(shared octree environment gpu model render fbx networking entities avatars
|
||||
link_hifi_libraries(shared octree environment gpu gpu-networking procedural model render fbx networking entities avatars
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer ui auto-updater
|
||||
plugins display-plugins input-plugins)
|
||||
|
|
|
@ -26,4 +26,4 @@ find_package(PolyVox REQUIRED)
|
|||
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES})
|
||||
|
||||
link_hifi_libraries(shared gpu script-engine render render-utils)
|
||||
link_hifi_libraries(shared gpu gpu-networking procedural script-engine render render-utils)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <PerfStat.h>
|
||||
#include <SceneScriptingInterface.h>
|
||||
#include <ScriptEngine.h>
|
||||
#include <procedural/Procedural.h>
|
||||
#include <TextureCache.h>
|
||||
|
||||
#include "EntityTreeRenderer.h"
|
||||
|
@ -455,13 +456,24 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
_viewState->endOverrideEnvironmentData();
|
||||
auto stage = scene->getSkyStage();
|
||||
if (zone->getBackgroundMode() == BACKGROUND_MODE_SKYBOX) {
|
||||
stage->getSkybox()->setColor(zone->getSkyboxProperties().getColorVec3());
|
||||
auto skybox = stage->getSkybox();
|
||||
skybox->setColor(zone->getSkyboxProperties().getColorVec3());
|
||||
static QString userData;
|
||||
if (userData != zone->getUserData()) {
|
||||
userData = zone->getUserData();
|
||||
QSharedPointer<Procedural> procedural(new Procedural(userData));
|
||||
if (procedural->_enabled) {
|
||||
skybox->setProcedural(procedural);
|
||||
} else {
|
||||
skybox->setProcedural(QSharedPointer<Procedural>());
|
||||
}
|
||||
}
|
||||
if (zone->getSkyboxProperties().getURL().isEmpty()) {
|
||||
stage->getSkybox()->setCubemap(gpu::TexturePointer());
|
||||
skybox->setCubemap(gpu::TexturePointer());
|
||||
} else {
|
||||
// Update the Texture of the Skybox with the one pointed by this zone
|
||||
auto cubeMap = DependencyManager::get<TextureCache>()->getTexture(zone->getSkyboxProperties().getURL(), CUBE_TEXTURE);
|
||||
stage->getSkybox()->setCubemap(cubeMap->getGPUTexture());
|
||||
skybox->setCubemap(cubeMap->getGPUTexture());
|
||||
}
|
||||
stage->setBackgroundMode(model::SunSkyStage::SKY_BOX);
|
||||
} else {
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <PerfStat.h>
|
||||
|
||||
#include "RenderableDebugableEntityItem.h"
|
||||
#include "../render-utils/simple_vert.h"
|
||||
#include "../render-utils/simple_frag.h"
|
||||
|
||||
EntityItemPointer RenderableBoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
return std::make_shared<RenderableBoxEntityItem>(entityID, properties);
|
||||
|
@ -42,11 +44,18 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
|
|||
glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha());
|
||||
|
||||
if (!_procedural) {
|
||||
_procedural.reset(new ProceduralInfo(this));
|
||||
_procedural.reset(new Procedural(this->getUserData()));
|
||||
_procedural->_vertexSource = simple_vert;
|
||||
_procedural->_fragmentSource = simple_frag;
|
||||
_procedural->_state->setCullMode(gpu::State::CULL_NONE);
|
||||
_procedural->_state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
_procedural->_state->setBlendFunction(false,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
}
|
||||
|
||||
if (_procedural->ready()) {
|
||||
_procedural->prepare(batch);
|
||||
_procedural->prepare(batch, this->getDimensions());
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(batch, 1.0f, _procedural->getColor(cubeColor));
|
||||
} else {
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(batch, 1.0f, cubeColor);
|
||||
|
|
|
@ -13,10 +13,11 @@
|
|||
#define hifi_RenderableBoxEntityItem_h
|
||||
|
||||
#include <BoxEntityItem.h>
|
||||
#include "RenderableEntityItem.h"
|
||||
#include "RenderableProceduralItem.h"
|
||||
#include <procedural/Procedural.h>
|
||||
|
||||
class RenderableBoxEntityItem : public BoxEntityItem, RenderableProceduralItem {
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
class RenderableBoxEntityItem : public BoxEntityItem {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
|
@ -28,6 +29,8 @@ public:
|
|||
virtual void setUserData(const QString& value);
|
||||
|
||||
SIMPLE_RENDERABLE()
|
||||
private:
|
||||
QSharedPointer<Procedural> _procedural;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -168,50 +168,59 @@ void RenderableParticleEffectEntityItem::update(const quint64& now) {
|
|||
updateRenderItem();
|
||||
}
|
||||
|
||||
static glm::vec3 zSortAxis;
|
||||
static bool zSort(const glm::vec3& rhs, const glm::vec3& lhs) {
|
||||
return glm::dot(rhs, ::zSortAxis) > glm::dot(lhs, ::zSortAxis);
|
||||
}
|
||||
|
||||
uint32_t toRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||
return ((uint32_t)r | (uint32_t)g << 8 | (uint32_t)b << 16 | (uint32_t)a << 24);
|
||||
}
|
||||
|
||||
class ParticleDetails {
|
||||
public:
|
||||
ParticleDetails(glm::vec3 position, float radius, uint32_t rgba) : position(position), radius(radius), rgba(rgba) { }
|
||||
|
||||
glm::vec3 position;
|
||||
float radius;
|
||||
uint32_t rgba;
|
||||
};
|
||||
|
||||
static glm::vec3 zSortAxis;
|
||||
static bool zSort(const ParticleDetails& rhs, const ParticleDetails& lhs) {
|
||||
return glm::dot(rhs.position, ::zSortAxis) > glm::dot(lhs.position, ::zSortAxis);
|
||||
}
|
||||
|
||||
void RenderableParticleEffectEntityItem::updateRenderItem() {
|
||||
if (!_scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
float particleRadius = getParticleRadius();
|
||||
auto xcolor = getXColor();
|
||||
auto alpha = (uint8_t)(glm::clamp(getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f);
|
||||
auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha);
|
||||
|
||||
// make a copy of each particle position
|
||||
std::vector<glm::vec3> positions;
|
||||
positions.reserve(getLivingParticleCount());
|
||||
// make a copy of each particle's details
|
||||
std::vector<ParticleDetails> particleDetails;
|
||||
particleDetails.reserve(getLivingParticleCount());
|
||||
for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) {
|
||||
positions.push_back(_particlePositions[i]);
|
||||
auto xcolor = _particleColors[i];
|
||||
auto alpha = (uint8_t)(glm::clamp(_particleAlphas[i] * getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f);
|
||||
auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha);
|
||||
particleDetails.push_back(ParticleDetails(_particlePositions[i], _particleRadiuses[i], rgba));
|
||||
}
|
||||
|
||||
// sort particles back to front
|
||||
// NOTE: this is view frustum might be one frame out of date.
|
||||
auto frustum = AbstractViewStateInterface::instance()->getCurrentViewFrustum();
|
||||
::zSortAxis = frustum->getDirection();
|
||||
qSort(positions.begin(), positions.end(), zSort);
|
||||
qSort(particleDetails.begin(), particleDetails.end(), zSort);
|
||||
|
||||
// allocate vertices
|
||||
_vertices.clear();
|
||||
|
||||
// build vertices from particle positions
|
||||
const glm::vec3 upOffset = frustum->getUp() * particleRadius;
|
||||
const glm::vec3 rightOffset = frustum->getRight() * particleRadius;
|
||||
for (auto&& pos : positions) {
|
||||
// build vertices from particle positions and radiuses
|
||||
const glm::vec3 up = frustum->getUp();
|
||||
const glm::vec3 right = frustum->getRight();
|
||||
for (auto&& particle : particleDetails) {
|
||||
glm::vec3 upOffset = up * particle.radius;
|
||||
glm::vec3 rightOffset = right * particle.radius;
|
||||
// generate corners of quad aligned to face the camera.
|
||||
_vertices.emplace_back(pos + rightOffset + upOffset, glm::vec2(1.0f, 1.0f), rgba);
|
||||
_vertices.emplace_back(pos - rightOffset + upOffset, glm::vec2(0.0f, 1.0f), rgba);
|
||||
_vertices.emplace_back(pos - rightOffset - upOffset, glm::vec2(0.0f, 0.0f), rgba);
|
||||
_vertices.emplace_back(pos + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), rgba);
|
||||
_vertices.emplace_back(particle.position + rightOffset + upOffset, glm::vec2(1.0f, 1.0f), particle.rgba);
|
||||
_vertices.emplace_back(particle.position - rightOffset + upOffset, glm::vec2(0.0f, 1.0f), particle.rgba);
|
||||
_vertices.emplace_back(particle.position - rightOffset - upOffset, glm::vec2(0.0f, 0.0f), particle.rgba);
|
||||
_vertices.emplace_back(particle.position + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), particle.rgba);
|
||||
}
|
||||
|
||||
render::PendingChanges pendingChanges;
|
||||
|
@ -219,6 +228,14 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
|
|||
// update vertex buffer
|
||||
auto vertexBuffer = payload.getVertexBuffer();
|
||||
size_t numBytes = sizeof(Vertex) * _vertices.size();
|
||||
|
||||
if (numBytes == 0) {
|
||||
vertexBuffer->resize(0);
|
||||
auto indexBuffer = payload.getIndexBuffer();
|
||||
indexBuffer->resize(0);
|
||||
return;
|
||||
}
|
||||
|
||||
vertexBuffer->resize(numBytes);
|
||||
gpu::Byte* data = vertexBuffer->editData();
|
||||
memcpy(data, &(_vertices[0]), numBytes);
|
||||
|
@ -284,7 +301,7 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
|
|||
payload.setPipeline(_untexturedPipeline);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
_scene->enqueuePendingChanges(pendingChanges);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/09/05
|
||||
// Copyright 2013-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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_RenderableProcedrualItem_h
|
||||
#define hifi_RenderableProcedrualItem_h
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QJsonObject>
|
||||
|
||||
#include <ShaderCache.h>
|
||||
#include <gpu/Shader.h>
|
||||
#include <gpu/Pipeline.h>
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
class EntityItem;
|
||||
class QJsonObject;
|
||||
|
||||
class RenderableProceduralItem {
|
||||
protected:
|
||||
// FIXME better encapsulation
|
||||
// FIXME better mechanism for extending to things rendered using shaders other than simple.slv
|
||||
struct ProceduralInfo {
|
||||
ProceduralInfo(EntityItem* entity);
|
||||
void parse();
|
||||
void parse(const QJsonObject&);
|
||||
bool ready();
|
||||
void prepare(gpu::Batch& batch);
|
||||
glm::vec4 getColor(const glm::vec4& entityColor);
|
||||
|
||||
bool _enabled{ false };
|
||||
uint8_t _version{ 1 };
|
||||
gpu::PipelinePointer _pipeline;
|
||||
gpu::ShaderPointer _vertexShader;
|
||||
gpu::ShaderPointer _fragmentShader;
|
||||
gpu::ShaderPointer _shader;
|
||||
QString _shaderSource;
|
||||
QString _shaderPath;
|
||||
QUrl _shaderUrl;
|
||||
quint64 _shaderModified{ 0 };
|
||||
bool _pipelineDirty{ true };
|
||||
int32_t _timeSlot{ gpu::Shader::INVALID_LOCATION };
|
||||
int32_t _scaleSlot{ gpu::Shader::INVALID_LOCATION };
|
||||
uint64_t _start{ 0 };
|
||||
NetworkShaderPointer _networkShader;
|
||||
EntityItem* _entity;
|
||||
QJsonObject _uniforms;
|
||||
};
|
||||
|
||||
QSharedPointer<ProceduralInfo> _procedural;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -21,6 +21,8 @@
|
|||
#include <PerfStat.h>
|
||||
|
||||
#include "RenderableDebugableEntityItem.h"
|
||||
#include "../render-utils/simple_vert.h"
|
||||
#include "../render-utils/simple_frag.h"
|
||||
|
||||
EntityItemPointer RenderableSphereEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
return std::make_shared<RenderableSphereEntityItem>(entityID, properties);
|
||||
|
@ -47,12 +49,19 @@ void RenderableSphereEntityItem::render(RenderArgs* args) {
|
|||
static const int SLICES = 15, STACKS = 15;
|
||||
|
||||
if (!_procedural) {
|
||||
_procedural.reset(new ProceduralInfo(this));
|
||||
_procedural.reset(new Procedural(getUserData()));
|
||||
_procedural->_vertexSource = simple_vert;
|
||||
_procedural->_fragmentSource = simple_frag;
|
||||
_procedural->_state->setCullMode(gpu::State::CULL_NONE);
|
||||
_procedural->_state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
_procedural->_state->setBlendFunction(false,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
}
|
||||
|
||||
glm::vec4 sphereColor(toGlm(getXColor()), getLocalRenderAlpha());
|
||||
if (_procedural->ready()) {
|
||||
_procedural->prepare(batch);
|
||||
_procedural->prepare(batch, getDimensions());
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(batch, 0.5f, SLICES, STACKS, _procedural->getColor(sphereColor));
|
||||
} else {
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, 0.5f, SLICES, STACKS, sphereColor);
|
||||
|
|
|
@ -13,10 +13,11 @@
|
|||
#define hifi_RenderableSphereEntityItem_h
|
||||
|
||||
#include <SphereEntityItem.h>
|
||||
#include "RenderableEntityItem.h"
|
||||
#include "RenderableProceduralItem.h"
|
||||
#include <procedural/Procedural.h>
|
||||
|
||||
class RenderableSphereEntityItem : public SphereEntityItem, RenderableProceduralItem {
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
class RenderableSphereEntityItem : public SphereEntityItem {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
|
@ -28,6 +29,9 @@ public:
|
|||
virtual void setUserData(const QString& value);
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
||||
private:
|
||||
QSharedPointer<Procedural> _procedural;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -55,6 +55,13 @@ CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
|
|||
CONSTRUCT_PROPERTY(scriptTimestamp, ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP),
|
||||
CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL),
|
||||
CONSTRUCT_PROPERTY(color, ),
|
||||
CONSTRUCT_PROPERTY(colorSpread, ParticleEffectEntityItem::DEFAULT_COLOR_SPREAD),
|
||||
CONSTRUCT_PROPERTY(colorStart, ParticleEffectEntityItem::DEFAULT_COLOR),
|
||||
CONSTRUCT_PROPERTY(colorFinish, ParticleEffectEntityItem::DEFAULT_COLOR),
|
||||
CONSTRUCT_PROPERTY(alpha, ENTITY_ITEM_DEFAULT_ALPHA),
|
||||
CONSTRUCT_PROPERTY(alphaSpread, ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD),
|
||||
CONSTRUCT_PROPERTY(alphaStart, ParticleEffectEntityItem::DEFAULT_ALPHA_START),
|
||||
CONSTRUCT_PROPERTY(alphaFinish, ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH),
|
||||
CONSTRUCT_PROPERTY(modelURL, ""),
|
||||
CONSTRUCT_PROPERTY(compoundShapeURL, ""),
|
||||
CONSTRUCT_PROPERTY(animationURL, ""),
|
||||
|
@ -89,6 +96,9 @@ CONSTRUCT_PROPERTY(velocitySpread, ParticleEffectEntityItem::DEFAULT_VELOCITY_SP
|
|||
CONSTRUCT_PROPERTY(emitAcceleration, ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION),
|
||||
CONSTRUCT_PROPERTY(accelerationSpread, ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD),
|
||||
CONSTRUCT_PROPERTY(particleRadius, ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS),
|
||||
CONSTRUCT_PROPERTY(radiusSpread, ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD),
|
||||
CONSTRUCT_PROPERTY(radiusStart, ParticleEffectEntityItem::DEFAULT_RADIUS_START),
|
||||
CONSTRUCT_PROPERTY(radiusFinish, ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH),
|
||||
CONSTRUCT_PROPERTY(marketplaceID, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID),
|
||||
CONSTRUCT_PROPERTY(keyLightColor, ZoneEntityItem::DEFAULT_KEYLIGHT_COLOR),
|
||||
CONSTRUCT_PROPERTY(keyLightIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_INTENSITY),
|
||||
|
@ -328,6 +338,13 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLLISION_SOUND_URL, collisionSoundURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLOR, color);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLOR_SPREAD, colorSpread);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLOR_START, colorStart);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLOR_FINISH, colorFinish);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ALPHA_SPREAD, alphaSpread);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ALPHA_START, alphaStart);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ALPHA_FINISH, alphaFinish);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL);
|
||||
|
@ -362,6 +379,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_EMIT_ACCELERATION, emitAcceleration);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ACCELERATION_SPREAD, accelerationSpread);
|
||||
CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius);
|
||||
CHECK_PROPERTY_CHANGE(PROP_RADIUS_SPREAD, radiusSpread);
|
||||
CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart);
|
||||
CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID);
|
||||
CHECK_PROPERTY_CHANGE(PROP_NAME, name);
|
||||
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_COLOR, keyLightColor);
|
||||
|
@ -439,6 +459,13 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(angularDamping);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(visible);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(color);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(colorSpread);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(colorStart);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(colorFinish);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(alpha);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(alphaSpread);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(alphaStart);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(alphaFinish);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL);
|
||||
|
@ -471,6 +498,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(emitAcceleration);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(accelerationSpread);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(radiusSpread);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(radiusStart);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(radiusFinish);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(name);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionSoundURL);
|
||||
|
@ -569,6 +599,13 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(angularDamping, float, setAngularDamping);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(color, xColor, setColor);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(colorSpread, xColor, setColorSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(colorStart, xColor, setColorStart);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(colorFinish, xColor, setColorFinish);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaSpread, float, setAlphaSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaStart, float, setAlphaStart);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaFinish, float, setAlphaFinish);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(animationURL, QString, setAnimationURL);
|
||||
|
@ -600,6 +637,9 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitAcceleration, glmVec3, setEmitAcceleration);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(accelerationSpread, glmVec3, setAccelerationSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(particleRadius, float, setParticleRadius);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusSpread, float, setRadiusSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusStart, float, setRadiusStart);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(marketplaceID, QString, setMarketplaceID);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionSoundURL, QString, setCollisionSoundURL);
|
||||
|
@ -850,7 +890,15 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent
|
|||
APPEND_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, properties.getEmitAcceleration());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, properties.getAccelerationSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, properties.getParticleRadius());
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, properties.getRadiusSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, properties.getRadiusStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, properties.getRadiusFinish());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, properties.getColorSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR_START, properties.getColorStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, properties.getColorFinish());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, properties.getAlphaSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, properties.getAlphaStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, properties.getAlphaFinish());
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Zone) {
|
||||
|
@ -901,11 +949,11 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent
|
|||
APPEND_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, properties.getStrokeWidths());
|
||||
}
|
||||
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
|
||||
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha());
|
||||
}
|
||||
if (propertyCount > 0) {
|
||||
int endOfEntityItemData = packetData->getUncompressedByteOffset();
|
||||
|
@ -1126,6 +1174,15 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_SPREAD, float, setRadiusSpread);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_START, float, setRadiusStart);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_FINISH, float, setRadiusFinish);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_SPREAD, xColor, setColorSpread);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_START, xColor, setColorStart);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_FINISH, xColor, setColorFinish);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish);
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Zone) {
|
||||
|
@ -1175,6 +1232,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
@ -1231,6 +1289,7 @@ void EntityItemProperties::markAllChanged() {
|
|||
_nameChanged = true;
|
||||
_visibleChanged = true;
|
||||
_colorChanged = true;
|
||||
_alphaChanged = true;
|
||||
_modelURLChanged = true;
|
||||
_compoundShapeURLChanged = true;
|
||||
_animationURLChanged = true;
|
||||
|
@ -1264,6 +1323,15 @@ void EntityItemProperties::markAllChanged() {
|
|||
_emitAccelerationChanged = true;
|
||||
_accelerationSpreadChanged = true;
|
||||
_particleRadiusChanged = true;
|
||||
_radiusSpreadChanged = true;
|
||||
_radiusStartChanged = true;
|
||||
_radiusFinishChanged = true;
|
||||
_colorSpreadChanged = true;
|
||||
_colorStartChanged = true;
|
||||
_colorFinishChanged = true;
|
||||
_alphaSpreadChanged = true;
|
||||
_alphaStartChanged = true;
|
||||
_alphaFinishChanged = true;
|
||||
|
||||
_marketplaceIDChanged = true;
|
||||
|
||||
|
|
|
@ -103,6 +103,13 @@ public:
|
|||
DEFINE_PROPERTY(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64);
|
||||
DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR_SPREAD, ColorSpread, colorSpread, xColor);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR_START, ColorStart, colorStart, xColor);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR_FINISH, ColorFinish, colorFinish, xColor);
|
||||
DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float);
|
||||
DEFINE_PROPERTY(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float);
|
||||
DEFINE_PROPERTY(PROP_ALPHA_START, AlphaStart, alphaStart, float);
|
||||
DEFINE_PROPERTY(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float);
|
||||
DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString);
|
||||
|
@ -136,6 +143,9 @@ public:
|
|||
DEFINE_PROPERTY(PROP_EMIT_ACCELERATION, EmitAcceleration, emitAcceleration, glm::vec3);
|
||||
DEFINE_PROPERTY(PROP_ACCELERATION_SPREAD, AccelerationSpread, accelerationSpread, glm::vec3);
|
||||
DEFINE_PROPERTY(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float);
|
||||
DEFINE_PROPERTY(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float);
|
||||
DEFINE_PROPERTY(PROP_RADIUS_START, RadiusStart, radiusStart, float);
|
||||
DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float);
|
||||
DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor);
|
||||
DEFINE_PROPERTY(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float);
|
||||
|
@ -291,6 +301,13 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
|||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ScriptTimestamp, scriptTimestamp, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionSoundURL, collisionSoundURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorSpread, colorSpread, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorStart, colorStart, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorFinish, colorFinish, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Alpha, alpha, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaSpread, alphaSpread, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaStart, alphaStart, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaFinish, alphaFinish, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CompoundShapeURL, compoundShapeURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, "");
|
||||
|
@ -322,6 +339,9 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
|||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitAcceleration, emitAcceleration, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AccelerationSpread, accelerationSpread, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusSpread, radiusSpread, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusStart, radiusStart, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusFinish, radiusFinish, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundMode, backgroundMode, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelVolumeSize, voxelVolumeSize, "");
|
||||
|
|
|
@ -27,6 +27,7 @@ const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString("");
|
|||
const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString("");
|
||||
const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid();
|
||||
|
||||
const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f;
|
||||
const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f;
|
||||
const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f;
|
||||
const bool ENTITY_ITEM_DEFAULT_VISIBLE = true;
|
||||
|
|
|
@ -146,6 +146,21 @@ enum EntityPropertyList {
|
|||
PROP_Y_P_NEIGHBOR_ID, // used by PolyVox
|
||||
PROP_Z_P_NEIGHBOR_ID, // used by PolyVox
|
||||
|
||||
// Used by particles
|
||||
PROP_RADIUS_SPREAD,
|
||||
PROP_RADIUS_START,
|
||||
PROP_RADIUS_FINISH,
|
||||
|
||||
PROP_ALPHA, // Supported by some derived classes
|
||||
|
||||
//Used by particles
|
||||
PROP_COLOR_SPREAD,
|
||||
PROP_COLOR_START,
|
||||
PROP_COLOR_FINISH,
|
||||
PROP_ALPHA_SPREAD,
|
||||
PROP_ALPHA_START,
|
||||
PROP_ALPHA_FINISH,
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ATTENTION: add new properties to end of list just ABOVE this line
|
||||
PROP_AFTER_LAST_ITEM,
|
||||
|
|
|
@ -43,6 +43,11 @@
|
|||
#include "ParticleEffectEntityItem.h"
|
||||
|
||||
const xColor ParticleEffectEntityItem::DEFAULT_COLOR = { 255, 255, 255 };
|
||||
const xColor ParticleEffectEntityItem::DEFAULT_COLOR_SPREAD = { 0, 0, 0 };
|
||||
const float ParticleEffectEntityItem::DEFAULT_ALPHA = 1.0f;
|
||||
const float ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD = 0.0f;
|
||||
const float ParticleEffectEntityItem::DEFAULT_ALPHA_START = DEFAULT_ALPHA;
|
||||
const float ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH = DEFAULT_ALPHA;
|
||||
const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f;
|
||||
const bool ParticleEffectEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false;
|
||||
const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FPS = 30.0f;
|
||||
|
@ -54,6 +59,9 @@ const glm::vec3 ParticleEffectEntityItem::DEFAULT_VELOCITY_SPREAD(3.0f, 0.0f, 3.
|
|||
const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION(0.0f, -9.8f, 0.0f);
|
||||
const glm::vec3 ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD(0.0f, 0.0f, 0.0f);
|
||||
const float ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS = 0.025f;
|
||||
const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f;
|
||||
const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = DEFAULT_PARTICLE_RADIUS;
|
||||
const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = DEFAULT_PARTICLE_RADIUS;
|
||||
const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = "";
|
||||
|
||||
|
||||
|
@ -72,16 +80,42 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte
|
|||
_emitAcceleration(DEFAULT_EMIT_ACCELERATION),
|
||||
_accelerationSpread(DEFAULT_ACCELERATION_SPREAD),
|
||||
_particleRadius(DEFAULT_PARTICLE_RADIUS),
|
||||
_radiusSpread(DEFAULT_RADIUS_SPREAD),
|
||||
_radiusStart(DEFAULT_RADIUS_START),
|
||||
_radiusFinish(DEFAULT_RADIUS_FINISH),
|
||||
_lastAnimated(usecTimestampNow()),
|
||||
_animationLoop(),
|
||||
_animationSettings(),
|
||||
_textures(DEFAULT_TEXTURES),
|
||||
_texturesChangedFlag(false),
|
||||
_shapeType(SHAPE_TYPE_NONE),
|
||||
_colorSpread(DEFAULT_COLOR_SPREAD),
|
||||
_colorStart(DEFAULT_COLOR),
|
||||
_colorFinish(DEFAULT_COLOR),
|
||||
_isColorStartInitialized(false),
|
||||
_isColorFinishInitialized(false),
|
||||
_alpha(DEFAULT_ALPHA),
|
||||
_alphaSpread(DEFAULT_ALPHA_SPREAD),
|
||||
_alphaStart(DEFAULT_ALPHA_START),
|
||||
_alphaFinish(DEFAULT_ALPHA_FINISH),
|
||||
_isAlphaStartInitialized(false),
|
||||
_isAlphaFinishInitialized(false),
|
||||
_particleLifetimes(DEFAULT_MAX_PARTICLES, 0.0f),
|
||||
_particlePositions(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)),
|
||||
_particleVelocities(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)),
|
||||
_particleAccelerations(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)),
|
||||
_particleRadiuses(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS),
|
||||
_radiusStarts(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS),
|
||||
_radiusMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS),
|
||||
_radiusFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS),
|
||||
_particleColors(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR),
|
||||
_colorStarts(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR),
|
||||
_colorMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR),
|
||||
_colorFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR),
|
||||
_particleAlphas(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA),
|
||||
_alphaStarts(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA),
|
||||
_alphaMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA),
|
||||
_alphaFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA),
|
||||
_timeUntilNextEmit(0.0f),
|
||||
_particleHeadIndex(0),
|
||||
_particleTailIndex(0),
|
||||
|
@ -97,10 +131,6 @@ ParticleEffectEntityItem::~ParticleEffectEntityItem() {
|
|||
}
|
||||
|
||||
|
||||
void ParticleEffectEntityItem::setLifespan(float lifespan) {
|
||||
_lifespan = lifespan;
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setEmitVelocity(const glm::vec3& emitVelocity) {
|
||||
_emitVelocity = emitVelocity;
|
||||
computeAndUpdateDimensions();
|
||||
|
@ -111,7 +141,6 @@ void ParticleEffectEntityItem::setVelocitySpread(const glm::vec3& velocitySpread
|
|||
computeAndUpdateDimensions();
|
||||
}
|
||||
|
||||
|
||||
void ParticleEffectEntityItem::setEmitAcceleration(const glm::vec3& emitAcceleration) {
|
||||
_emitAcceleration = emitAcceleration;
|
||||
computeAndUpdateDimensions();
|
||||
|
@ -122,10 +151,6 @@ void ParticleEffectEntityItem::setAccelerationSpread(const glm::vec3& accelerati
|
|||
computeAndUpdateDimensions();
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setParticleRadius(float particleRadius) {
|
||||
_particleRadius = particleRadius;
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::computeAndUpdateDimensions() {
|
||||
const float time = _lifespan * 1.1f; // add 10% extra time to account for incremental timer accumulation error
|
||||
|
||||
|
@ -153,6 +178,7 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const {
|
|||
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationIsPlaying, getAnimationIsPlaying);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFPS, getAnimationFPS);
|
||||
|
@ -163,9 +189,19 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const {
|
|||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifespan, getLifespan);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitRate, getEmitRate);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitVelocity, getEmitVelocity);
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(velocitySpread, getVelocitySpread);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitAcceleration, getEmitAcceleration);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(accelerationSpread, getAccelerationSpread);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(particleRadius, getParticleRadius);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusSpread, getRadiusSpread);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusStart, getRadiusStart);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusFinish, getRadiusFinish);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorSpread, getColorSpread);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorStart, getColorStart);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorFinish, getColorFinish);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaSpread, getAlphaSpread);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaStart, getAlphaStart);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaFinish, getAlphaFinish);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
|
||||
|
||||
return properties;
|
||||
|
@ -175,6 +211,7 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
|
|||
bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFPS, setAnimationFPS);
|
||||
|
@ -185,11 +222,20 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifespan, setLifespan);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitRate, setEmitRate);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitVelocity, setEmitVelocity);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocitySpread, setVelocitySpread);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitAcceleration, setEmitAcceleration);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(accelerationSpread, setAccelerationSpread);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(particleRadius, setParticleRadius);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusSpread, setRadiusSpread);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusStart, setRadiusStart);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusFinish, setRadiusFinish);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorSpread, setColorSpread);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorStart, setColorStart);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorFinish, setColorFinish);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaSpread, setAlphaSpread);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaStart, setAlphaStart);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaFinish, setAlphaFinish);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocitySpread, setVelocitySpread);
|
||||
|
||||
if (somethingChanged) {
|
||||
bool wantDebug = false;
|
||||
|
@ -257,6 +303,22 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
|
|||
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
|
||||
}
|
||||
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES) {
|
||||
READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart);
|
||||
READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish);
|
||||
}
|
||||
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES) {
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, xColor, setColorSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_START, xColor, setColorStart);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, xColor, setColorFinish);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA_FINISH, float, setAlphaFinish);
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
|
@ -280,6 +342,16 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea
|
|||
requestedProperties += PROP_PARTICLE_RADIUS;
|
||||
requestedProperties += PROP_TEXTURES;
|
||||
requestedProperties += PROP_VELOCITY_SPREAD;
|
||||
requestedProperties += PROP_RADIUS_SPREAD;
|
||||
requestedProperties += PROP_RADIUS_START;
|
||||
requestedProperties += PROP_RADIUS_FINISH;
|
||||
requestedProperties += PROP_COLOR_SPREAD;
|
||||
requestedProperties += PROP_COLOR_START;
|
||||
requestedProperties += PROP_COLOR_FINISH;
|
||||
requestedProperties += PROP_ALPHA;
|
||||
requestedProperties += PROP_ALPHA_SPREAD;
|
||||
requestedProperties += PROP_ALPHA_START;
|
||||
requestedProperties += PROP_ALPHA_FINISH;
|
||||
|
||||
return requestedProperties;
|
||||
}
|
||||
|
@ -308,6 +380,16 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData,
|
|||
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, getParticleRadius());
|
||||
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures());
|
||||
APPEND_ENTITY_PROPERTY(PROP_VELOCITY_SPREAD, getVelocitySpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, getRadiusSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, getRadiusStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, getRadiusFinish());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, getColorSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR_START, getColorStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, getColorFinish());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, getAlphaSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, getAlphaStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, getAlphaFinish());
|
||||
}
|
||||
|
||||
bool ParticleEffectEntityItem::isAnimatingSomething() const {
|
||||
|
@ -477,6 +559,27 @@ QString ParticleEffectEntityItem::getAnimationSettings() const {
|
|||
return jsonByteString;
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::updateRadius(quint32 index, float age) {
|
||||
_particleRadiuses[index] = interpolate(_radiusStarts[index], _radiusMiddles[index], _radiusFinishes[index], age);
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::updateColor(quint32 index, float age) {
|
||||
_particleColors[index].red =
|
||||
(int)glm::clamp(interpolate(_colorStarts[index].red, _colorMiddles[index].red, _colorFinishes[index].red, age),
|
||||
0.0f, 255.0f);
|
||||
_particleColors[index].green =
|
||||
(int)glm::clamp(interpolate(_colorStarts[index].green, _colorMiddles[index].green, _colorFinishes[index].green, age),
|
||||
0.0f, 255.0f);
|
||||
_particleColors[index].blue =
|
||||
(int)glm::clamp(interpolate(_colorStarts[index].blue, _colorMiddles[index].blue, _colorFinishes[index].blue, age),
|
||||
0.0f, 255.0f);
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::updateAlpha(quint32 index, float age) {
|
||||
_particleAlphas[index] = glm::clamp(interpolate(_alphaStarts[index], _alphaMiddles[index], _alphaFinishes[index], age),
|
||||
0.0f, 1.0f);
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::extendBounds(const glm::vec3& point) {
|
||||
_particleMinBound.x = glm::min(_particleMinBound.x, point.x);
|
||||
_particleMinBound.y = glm::min(_particleMinBound.y, point.y);
|
||||
|
@ -509,12 +612,16 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
|
|||
_particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles;
|
||||
}
|
||||
else {
|
||||
float age = (1.0f - _particleLifetimes[i] / _lifespan); // 0.0 .. 1.0
|
||||
updateRadius(i, age);
|
||||
updateColor(i, age);
|
||||
updateAlpha(i, age);
|
||||
integrateParticle(i, deltaTime);
|
||||
extendBounds(_particlePositions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// emit new particles, but only if animaiton is playing
|
||||
// emit new particles, but only if animation is playing
|
||||
if (getAnimationIsPlaying()) {
|
||||
|
||||
float timeLeftInFrame = deltaTime;
|
||||
|
@ -527,12 +634,24 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
|
|||
quint32 i = _particleTailIndex;
|
||||
_particleLifetimes[i] = _lifespan;
|
||||
|
||||
|
||||
// Radius
|
||||
if (_radiusSpread == 0.0f) {
|
||||
_radiusStarts[i] = getRadiusStart();
|
||||
_radiusMiddles[i] =_particleRadius;
|
||||
_radiusFinishes[i] = getRadiusFinish();
|
||||
} else {
|
||||
float spreadMultiplier = 1.0f + (2.0f * randFloat() - 1) * _radiusSpread / _particleRadius;
|
||||
_radiusStarts[i] = spreadMultiplier * getRadiusStart();
|
||||
_radiusMiddles[i] = spreadMultiplier * _particleRadius;
|
||||
_radiusFinishes[i] = spreadMultiplier * getRadiusFinish();
|
||||
}
|
||||
updateRadius(i, 0.0f);
|
||||
|
||||
// Velocity and acceleration
|
||||
glm::vec3 spreadOffset;
|
||||
spreadOffset.x = -_velocitySpread.x + randFloat() * (_velocitySpread.x * 2.0f);
|
||||
spreadOffset.y = -_velocitySpread.y + randFloat() * (_velocitySpread.y * 2.0f);
|
||||
spreadOffset.z = -_velocitySpread.z + randFloat() * (_velocitySpread.z * 2.0f);
|
||||
|
||||
|
||||
// set initial conditions
|
||||
_particlePositions[i] = getPosition();
|
||||
|
@ -547,6 +666,48 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
|
|||
integrateParticle(i, timeLeftInFrame);
|
||||
extendBounds(_particlePositions[i]);
|
||||
|
||||
// Color
|
||||
if (_colorSpread == xColor{ 0, 0, 0 }) {
|
||||
_colorStarts[i] = getColorStart();
|
||||
_colorMiddles[i] = getXColor();
|
||||
_colorFinishes[i] = getColorFinish();
|
||||
} else {
|
||||
xColor startColor = getColorStart();
|
||||
xColor middleColor = getXColor();
|
||||
xColor finishColor = getColorFinish();
|
||||
|
||||
float spread = 2.0f * randFloat() - 1.0f;
|
||||
float spreadMultiplierRed = 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red;
|
||||
float spreadMultiplierGreen = 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green;
|
||||
float spreadMultiplierBlue = 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue;
|
||||
|
||||
_colorStarts[i].red = (int)glm::clamp(spreadMultiplierRed * (float)startColor.red, 0.0f, 255.0f);
|
||||
_colorStarts[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)startColor.green, 0.0f, 255.0f);
|
||||
_colorStarts[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)startColor.blue, 0.0f, 255.0f);
|
||||
|
||||
_colorMiddles[i].red = (int)glm::clamp(spreadMultiplierRed * (float)middleColor.red, 0.0f, 255.0f);
|
||||
_colorMiddles[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)middleColor.green, 0.0f, 255.0f);
|
||||
_colorMiddles[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)middleColor.blue, 0.0f, 255.0f);
|
||||
|
||||
_colorFinishes[i].red = (int)glm::clamp(spreadMultiplierRed * (float)finishColor.red, 0.0f, 255.0f);
|
||||
_colorFinishes[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)finishColor.green, 0.0f, 255.0f);
|
||||
_colorFinishes[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)finishColor.blue, 0.0f, 255.0f);
|
||||
}
|
||||
updateColor(i, 0.0f);
|
||||
|
||||
// Alpha
|
||||
if (_alphaSpread == 0.0f) {
|
||||
_alphaStarts[i] = getAlphaStart();
|
||||
_alphaMiddles[i] = _alpha;
|
||||
_alphaFinishes[i] = getAlphaFinish();
|
||||
} else {
|
||||
float spreadMultiplier = 1.0f + (2.0f * randFloat() - 1) * _alphaSpread / _alpha;
|
||||
_alphaStarts[i] = spreadMultiplier * getAlphaStart();
|
||||
_alphaMiddles[i] = spreadMultiplier * _alpha;
|
||||
_alphaFinishes[i] = spreadMultiplier * getAlphaFinish();
|
||||
}
|
||||
updateAlpha(i, 0.0f);
|
||||
|
||||
_particleTailIndex = (_particleTailIndex + 1) % _maxParticles;
|
||||
|
||||
// overflow! move head forward by one.
|
||||
|
@ -571,8 +732,20 @@ void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) {
|
|||
_particleLifetimes.resize(_maxParticles);
|
||||
_particlePositions.resize(_maxParticles);
|
||||
_particleVelocities.resize(_maxParticles);
|
||||
_particleRadiuses.resize(_maxParticles);
|
||||
_radiusStarts.resize(_maxParticles);
|
||||
_radiusMiddles.resize(_maxParticles);
|
||||
_radiusFinishes.resize(_maxParticles);
|
||||
_particleColors.resize(_maxParticles);
|
||||
_colorStarts.resize(_maxParticles);
|
||||
_colorMiddles.resize(_maxParticles);
|
||||
_colorFinishes.resize(_maxParticles);
|
||||
_particleAlphas.resize(_maxParticles);
|
||||
_alphaStarts.resize(_maxParticles);
|
||||
_alphaMiddles.resize(_maxParticles);
|
||||
_alphaFinishes.resize(_maxParticles);
|
||||
|
||||
// effectivly clear all particles and start emitting new ones from scratch.
|
||||
// effectively clear all particles and start emitting new ones from scratch.
|
||||
_particleHeadIndex = 0;
|
||||
_particleTailIndex = 0;
|
||||
_timeUntilNextEmit = 0.0f;
|
||||
|
@ -587,3 +760,42 @@ quint32 ParticleEffectEntityItem::getLivingParticleCount() const {
|
|||
return (_maxParticles - _particleHeadIndex) + _particleTailIndex;
|
||||
}
|
||||
}
|
||||
|
||||
float ParticleEffectEntityItem::cubicInterpolate(float y0, float y1, float y2, float y3, float u) {
|
||||
float a0, a1, a2, a3, uu;
|
||||
uu = u * u;
|
||||
a0 = y3 - y2 - y0 + y1;
|
||||
a1 = y0 - y1 - a0;
|
||||
a2 = y2 - y0;
|
||||
a3 = y1;
|
||||
|
||||
return (a0 * u * uu + a1 * uu + a2 * u + a3);
|
||||
}
|
||||
|
||||
float ParticleEffectEntityItem::interpolate(float start, float middle, float finish, float age) {
|
||||
float y0, y1, y2, y3, u;
|
||||
|
||||
if (age <= 0.5f) {
|
||||
if (start == middle) {
|
||||
return middle;
|
||||
}
|
||||
|
||||
y1 = start;
|
||||
y2 = middle;
|
||||
y3 = finish;
|
||||
y0 = 2.0f * y1 - y2;
|
||||
u = 2.0f * age;
|
||||
} else {
|
||||
if (middle == finish) {
|
||||
return middle;
|
||||
}
|
||||
|
||||
y0 = start;
|
||||
y1 = middle;
|
||||
y2 = finish;
|
||||
y3 = 2.0f * y2 - y1;
|
||||
u = 2.0f * age - 1.0f;
|
||||
}
|
||||
|
||||
return cubicInterpolate(y0, y1, y2, y3, u);
|
||||
}
|
||||
|
|
|
@ -56,6 +56,36 @@ public:
|
|||
_color[BLUE_INDEX] = value.blue;
|
||||
}
|
||||
|
||||
bool _isColorStartInitialized;
|
||||
void setColorStart(const xColor& colorStart) { _colorStart = colorStart; _isColorStartInitialized = true; }
|
||||
xColor getColorStart() const { return _isColorStartInitialized ? _colorStart : getXColor(); }
|
||||
|
||||
bool _isColorFinishInitialized;
|
||||
void setColorFinish(const xColor& colorFinish) { _colorFinish = colorFinish; _isColorFinishInitialized = true; }
|
||||
xColor getColorFinish() const { return _isColorFinishInitialized ? _colorFinish : getXColor(); }
|
||||
|
||||
static const xColor DEFAULT_COLOR_SPREAD;
|
||||
void setColorSpread(const xColor& colorSpread) { _colorSpread = colorSpread; }
|
||||
xColor getColorSpread() const { return _colorSpread; }
|
||||
|
||||
static const float DEFAULT_ALPHA;
|
||||
void setAlpha(float alpha) { _alpha = alpha; }
|
||||
float getAlpha() const { return _alpha; }
|
||||
|
||||
static const float DEFAULT_ALPHA_START;
|
||||
bool _isAlphaStartInitialized;
|
||||
void setAlphaStart(float alphaStart) { _alphaStart = alphaStart; _isAlphaStartInitialized = true; }
|
||||
float getAlphaStart() const { return _isAlphaStartInitialized ? _alphaStart : _alpha; }
|
||||
|
||||
static const float DEFAULT_ALPHA_FINISH;
|
||||
bool _isAlphaFinishInitialized;
|
||||
void setAlphaFinish(float alphaFinish) { _alphaFinish = alphaFinish; _isAlphaFinishInitialized = true; }
|
||||
float getAlphaFinish() const { return _isAlphaFinishInitialized ? _alphaFinish : _alpha; }
|
||||
|
||||
static const float DEFAULT_ALPHA_SPREAD;
|
||||
void setAlphaSpread(float alphaSpread) { _alphaSpread = alphaSpread; }
|
||||
float getAlphaSpread() const { return _alphaSpread; }
|
||||
|
||||
void updateShapeType(ShapeType type);
|
||||
virtual ShapeType getShapeType() const { return _shapeType; }
|
||||
|
||||
|
@ -91,7 +121,7 @@ public:
|
|||
quint32 getMaxParticles() const { return _maxParticles; }
|
||||
|
||||
static const float DEFAULT_LIFESPAN;
|
||||
void setLifespan(float lifespan);
|
||||
void setLifespan(float lifespan) { _lifespan = lifespan; }
|
||||
float getLifespan() const { return _lifespan; }
|
||||
|
||||
static const float DEFAULT_EMIT_RATE;
|
||||
|
@ -102,12 +132,10 @@ public:
|
|||
void setEmitVelocity(const glm::vec3& emitVelocity);
|
||||
const glm::vec3& getEmitVelocity() const { return _emitVelocity; }
|
||||
|
||||
|
||||
static const glm::vec3 DEFAULT_VELOCITY_SPREAD;
|
||||
void setVelocitySpread(const glm::vec3& velocitySpread);
|
||||
const glm::vec3& getVelocitySpread() const { return _velocitySpread; }
|
||||
|
||||
|
||||
static const glm::vec3 DEFAULT_EMIT_ACCELERATION;
|
||||
void setEmitAcceleration(const glm::vec3& emitAcceleration);
|
||||
const glm::vec3& getEmitAcceleration() const { return _emitAcceleration; }
|
||||
|
@ -117,9 +145,23 @@ public:
|
|||
const glm::vec3& getAccelerationSpread() const { return _accelerationSpread; }
|
||||
|
||||
static const float DEFAULT_PARTICLE_RADIUS;
|
||||
void setParticleRadius(float particleRadius);
|
||||
void setParticleRadius(float particleRadius) { _particleRadius = particleRadius; }
|
||||
float getParticleRadius() const { return _particleRadius; }
|
||||
|
||||
|
||||
static const float DEFAULT_RADIUS_START;
|
||||
bool _isRadiusStartInitialized;
|
||||
void setRadiusStart(float radiusStart) { _radiusStart = radiusStart; _isRadiusStartInitialized = true; }
|
||||
float getRadiusStart() const { return _isRadiusStartInitialized ? _radiusStart : _particleRadius; }
|
||||
|
||||
static const float DEFAULT_RADIUS_FINISH;
|
||||
bool _isRadiusFinishInitialized;
|
||||
void setRadiusFinish(float radiusFinish) { _radiusFinish = radiusFinish; _isRadiusFinishInitialized = true; }
|
||||
float getRadiusFinish() const { return _isRadiusFinishInitialized ? _radiusFinish : _particleRadius; }
|
||||
|
||||
static const float DEFAULT_RADIUS_SPREAD;
|
||||
void setRadiusSpread(float radiusSpread) { _radiusSpread = radiusSpread; }
|
||||
float getRadiusSpread() const { return _radiusSpread; }
|
||||
|
||||
void computeAndUpdateDimensions();
|
||||
|
||||
|
||||
|
@ -141,12 +183,22 @@ protected:
|
|||
|
||||
bool isAnimatingSomething() const;
|
||||
void stepSimulation(float deltaTime);
|
||||
void updateRadius(quint32 index, float age);
|
||||
void updateColor(quint32 index, float age);
|
||||
void updateAlpha(quint32 index, float age);
|
||||
void extendBounds(const glm::vec3& point);
|
||||
void integrateParticle(quint32 index, float deltaTime);
|
||||
quint32 getLivingParticleCount() const;
|
||||
|
||||
// the properties of this entity
|
||||
rgbColor _color;
|
||||
xColor _colorStart;
|
||||
xColor _colorFinish;
|
||||
xColor _colorSpread;
|
||||
float _alpha;
|
||||
float _alphaStart;
|
||||
float _alphaFinish;
|
||||
float _alphaSpread;
|
||||
quint32 _maxParticles;
|
||||
float _lifespan;
|
||||
float _emitRate;
|
||||
|
@ -155,6 +207,9 @@ protected:
|
|||
glm::vec3 _emitAcceleration;
|
||||
glm::vec3 _accelerationSpread;
|
||||
float _particleRadius;
|
||||
float _radiusStart;
|
||||
float _radiusFinish;
|
||||
float _radiusSpread;
|
||||
quint64 _lastAnimated;
|
||||
AnimationLoop _animationLoop;
|
||||
QString _animationSettings;
|
||||
|
@ -167,9 +222,22 @@ protected:
|
|||
QVector<glm::vec3> _particlePositions;
|
||||
QVector<glm::vec3> _particleVelocities;
|
||||
QVector<glm::vec3> _particleAccelerations;
|
||||
QVector<float> _particleRadiuses;
|
||||
QVector<float> _radiusStarts;
|
||||
QVector<float> _radiusMiddles;
|
||||
QVector<float> _radiusFinishes;
|
||||
QVector<xColor> _particleColors;
|
||||
QVector<xColor> _colorStarts;
|
||||
QVector<xColor> _colorMiddles;
|
||||
QVector<xColor> _colorFinishes;
|
||||
QVector<float> _particleAlphas;
|
||||
QVector<float> _alphaStarts;
|
||||
QVector<float> _alphaMiddles;
|
||||
QVector<float> _alphaFinishes;
|
||||
|
||||
float _timeUntilNextEmit;
|
||||
|
||||
// particle arrays are a ring buffer, use these indicies
|
||||
// particle arrays are a ring buffer, use these indices
|
||||
// to keep track of the living particles.
|
||||
quint32 _particleHeadIndex;
|
||||
quint32 _particleTailIndex;
|
||||
|
@ -177,6 +245,10 @@ protected:
|
|||
// bounding volume
|
||||
glm::vec3 _particleMaxBound;
|
||||
glm::vec3 _particleMinBound;
|
||||
|
||||
private:
|
||||
float cubicInterpolate(float y0, float y1, float y2, float y3, float u);
|
||||
float interpolate(float start, float middle, float finish, float age);
|
||||
};
|
||||
|
||||
#endif // hifi_ParticleEffectEntityItem_h
|
||||
|
|
11
libraries/gpu-networking/CMakeLists.txt
Normal file
11
libraries/gpu-networking/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
set(TARGET_NAME gpu-networking)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library()
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared networking gpu)
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/08/07
|
||||
// Copyright 2013-2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "GpuNetworkingLogging.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(gpunetwork, "hifi.gpu-network")
|
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/08/07
|
||||
// Copyright 2013-2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QLoggingCategory>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(gpunetwork)
|
|
@ -1,7 +1,4 @@
|
|||
//
|
||||
// TextureCache.cpp
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Andrzej Kapolka on 8/6/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
|
@ -21,13 +18,11 @@
|
|||
#include <QRunnable>
|
||||
#include <QThreadPool>
|
||||
#include <qimagereader.h>
|
||||
#include "PathUtils.h"
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
|
||||
|
||||
#include "RenderUtilsLogging.h"
|
||||
#include "GpuNetworkingLogging.h"
|
||||
|
||||
TextureCache::TextureCache() {
|
||||
const qint64 TEXTURE_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE;
|
||||
|
@ -255,7 +250,7 @@ void listSupportedImageFormats() {
|
|||
foreach(const QByteArray& f, supportedFormats) {
|
||||
formats += QString(f) + ",";
|
||||
}
|
||||
qCDebug(renderutils) << "List of supported Image formats:" << formats;
|
||||
qCDebug(gpunetwork) << "List of supported Image formats:" << formats;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -323,9 +318,9 @@ void ImageReader::run() {
|
|||
|
||||
if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) {
|
||||
if (filenameExtension.empty()) {
|
||||
qCDebug(renderutils) << "QImage failed to create from content, no file extension:" << _url;
|
||||
qCDebug(gpunetwork) << "QImage failed to create from content, no file extension:" << _url;
|
||||
} else {
|
||||
qCDebug(renderutils) << "QImage failed to create from content" << _url;
|
||||
qCDebug(gpunetwork) << "QImage failed to create from content" << _url;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -333,7 +328,7 @@ void ImageReader::run() {
|
|||
int imageArea = image.width() * image.height();
|
||||
auto ntex = dynamic_cast<NetworkTexture*>(&*texture);
|
||||
if (ntex && (ntex->getType() == CUBE_TEXTURE)) {
|
||||
qCDebug(renderutils) << "Cube map size:" << _url << image.width() << image.height();
|
||||
qCDebug(gpunetwork) << "Cube map size:" << _url << image.width() << image.height();
|
||||
}
|
||||
|
||||
int opaquePixels = 0;
|
||||
|
@ -384,7 +379,7 @@ void ImageReader::run() {
|
|||
}
|
||||
}
|
||||
if (opaquePixels == imageArea) {
|
||||
qCDebug(renderutils) << "Image with alpha channel is completely opaque:" << _url;
|
||||
qCDebug(gpunetwork) << "Image with alpha channel is completely opaque:" << _url;
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
|
@ -532,7 +527,7 @@ void ImageReader::run() {
|
|||
faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror));
|
||||
faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror));
|
||||
} else {
|
||||
qCDebug(renderutils) << "Failed to find a known cube map layout from this image:" << _url;
|
||||
qCDebug(gpunetwork) << "Failed to find a known cube map layout from this image:" << _url;
|
||||
return;
|
||||
}
|
||||
|
167
libraries/gpu-networking/src/gpu-networking/TextureCache.h
Normal file
167
libraries/gpu-networking/src/gpu-networking/TextureCache.h
Normal file
|
@ -0,0 +1,167 @@
|
|||
//
|
||||
// Created by Andrzej Kapolka on 8/6/13.
|
||||
// Copyright 2013 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_TextureCache_h
|
||||
#define hifi_TextureCache_h
|
||||
|
||||
#include <gpu/Texture.h>
|
||||
|
||||
#include <QImage>
|
||||
#include <QMap>
|
||||
#include <QColor>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <ResourceCache.h>
|
||||
|
||||
namespace gpu {
|
||||
class Batch;
|
||||
}
|
||||
class NetworkTexture;
|
||||
|
||||
typedef QSharedPointer<NetworkTexture> NetworkTexturePointer;
|
||||
|
||||
enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, SPLAT_TEXTURE, CUBE_TEXTURE };
|
||||
|
||||
/// Stores cached textures, including render-to-texture targets.
|
||||
class TextureCache : public ResourceCache, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
/// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture
|
||||
/// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and
|
||||
/// the second, a set of random unit vectors to be used as noise gradients.
|
||||
const gpu::TexturePointer& getPermutationNormalTexture();
|
||||
|
||||
/// Returns an opaque white texture (useful for a default).
|
||||
const gpu::TexturePointer& getWhiteTexture();
|
||||
|
||||
/// Returns an opaque gray texture (useful for a default).
|
||||
const gpu::TexturePointer& getGrayTexture();
|
||||
|
||||
/// Returns the a pale blue texture (useful for a normal map).
|
||||
const gpu::TexturePointer& getBlueTexture();
|
||||
|
||||
/// Returns the a black texture (useful for a default).
|
||||
const gpu::TexturePointer& getBlackTexture();
|
||||
|
||||
// Returns a map used to compress the normals through a fitting scale algorithm
|
||||
const gpu::TexturePointer& getNormalFittingTexture();
|
||||
|
||||
/// Returns a texture version of an image file
|
||||
static gpu::TexturePointer getImageTexture(const QString& path);
|
||||
|
||||
/// Loads a texture from the specified URL.
|
||||
NetworkTexturePointer getTexture(const QUrl& url, TextureType type = DEFAULT_TEXTURE, bool dilatable = false,
|
||||
const QByteArray& content = QByteArray());
|
||||
|
||||
protected:
|
||||
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url,
|
||||
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra);
|
||||
|
||||
private:
|
||||
TextureCache();
|
||||
virtual ~TextureCache();
|
||||
friend class DilatableNetworkTexture;
|
||||
|
||||
gpu::TexturePointer _permutationNormalTexture;
|
||||
gpu::TexturePointer _whiteTexture;
|
||||
gpu::TexturePointer _grayTexture;
|
||||
gpu::TexturePointer _blueTexture;
|
||||
gpu::TexturePointer _blackTexture;
|
||||
gpu::TexturePointer _normalFittingTexture;
|
||||
|
||||
QHash<QUrl, QWeakPointer<NetworkTexture> > _dilatableNetworkTextures;
|
||||
};
|
||||
|
||||
/// A simple object wrapper for an OpenGL texture.
|
||||
class Texture {
|
||||
public:
|
||||
friend class TextureCache;
|
||||
friend class DilatableNetworkTexture;
|
||||
Texture();
|
||||
~Texture();
|
||||
|
||||
const gpu::TexturePointer& getGPUTexture() const { return _gpuTexture; }
|
||||
|
||||
protected:
|
||||
gpu::TexturePointer _gpuTexture;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
/// A texture loaded from the network.
|
||||
|
||||
class NetworkTexture : public Resource, public Texture {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content);
|
||||
|
||||
/// Checks whether it "looks like" this texture is translucent
|
||||
/// (majority of pixels neither fully opaque or fully transparent).
|
||||
bool isTranslucent() const { return _translucent; }
|
||||
|
||||
/// Returns the lazily-computed average texture color.
|
||||
const QColor& getAverageColor() const { return _averageColor; }
|
||||
|
||||
int getOriginalWidth() const { return _originalWidth; }
|
||||
int getOriginalHeight() const { return _originalHeight; }
|
||||
int getWidth() const { return _width; }
|
||||
int getHeight() const { return _height; }
|
||||
TextureType getType() const { return _type; }
|
||||
protected:
|
||||
|
||||
virtual void downloadFinished(QNetworkReply* reply);
|
||||
|
||||
Q_INVOKABLE void loadContent(const QByteArray& content);
|
||||
// FIXME: This void* should be a gpu::Texture* but i cannot get it to work for now, moving on...
|
||||
Q_INVOKABLE void setImage(const QImage& image, void* texture, bool translucent, const QColor& averageColor, int originalWidth,
|
||||
int originalHeight);
|
||||
|
||||
virtual void imageLoaded(const QImage& image);
|
||||
|
||||
TextureType _type;
|
||||
|
||||
private:
|
||||
bool _translucent;
|
||||
QColor _averageColor;
|
||||
int _originalWidth;
|
||||
int _originalHeight;
|
||||
int _width;
|
||||
int _height;
|
||||
};
|
||||
|
||||
/// Caches derived, dilated textures.
|
||||
class DilatableNetworkTexture : public NetworkTexture {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
DilatableNetworkTexture(const QUrl& url, const QByteArray& content);
|
||||
|
||||
/// Returns a pointer to a texture with the requested amount of dilation.
|
||||
QSharedPointer<Texture> getDilatedTexture(float dilation);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void imageLoaded(const QImage& image);
|
||||
virtual void reinsert();
|
||||
|
||||
private:
|
||||
|
||||
QImage _image;
|
||||
int _innerRadius;
|
||||
int _outerRadius;
|
||||
|
||||
QMap<float, QWeakPointer<Texture> > _dilatedTextures;
|
||||
};
|
||||
|
||||
#endif // hifi_TextureCache_h
|
|
@ -7,6 +7,10 @@ setup_hifi_library()
|
|||
|
||||
link_hifi_libraries(shared)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
add_dependency_external_projects(glew)
|
||||
find_package(GLEW REQUIRED)
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
|
|
|
@ -9,4 +9,4 @@ add_dependency_external_projects(glm)
|
|||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared gpu octree)
|
||||
link_hifi_libraries(shared networking gpu gpu-networking procedural octree)
|
||||
|
|
|
@ -10,10 +10,12 @@
|
|||
//
|
||||
#include "Skybox.h"
|
||||
|
||||
#include "gpu/Batch.h"
|
||||
#include "gpu/Context.h"
|
||||
|
||||
#include "ViewFrustum.h"
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Context.h>
|
||||
#include <procedural/Procedural.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include "Skybox_vert.h"
|
||||
#include "Skybox_frag.h"
|
||||
|
||||
|
@ -38,19 +40,54 @@ void Skybox::setColor(const Color& color) {
|
|||
_color = color;
|
||||
}
|
||||
|
||||
void Skybox::setProcedural(QSharedPointer<Procedural> procedural) {
|
||||
_procedural = procedural;
|
||||
if (_procedural) {
|
||||
_procedural->_vertexSource = Skybox_vert;
|
||||
_procedural->_fragmentSource = Skybox_frag;
|
||||
// No pipeline state customization
|
||||
}
|
||||
}
|
||||
|
||||
void Skybox::setCubemap(const gpu::TexturePointer& cubemap) {
|
||||
_cubemap = cubemap;
|
||||
}
|
||||
|
||||
|
||||
void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Skybox& skybox) {
|
||||
static gpu::BufferPointer theBuffer;
|
||||
static gpu::Stream::FormatPointer theFormat;
|
||||
|
||||
if (skybox.getCubemap()) {
|
||||
if (skybox.getCubemap()->isDefined()) {
|
||||
if (skybox._procedural || skybox.getCubemap()) {
|
||||
if (!theBuffer) {
|
||||
const float CLIP = 1.0f;
|
||||
const glm::vec2 vertices[4] = { { -CLIP, -CLIP }, { CLIP, -CLIP }, { -CLIP, CLIP }, { CLIP, CLIP } };
|
||||
theBuffer = std::make_shared<gpu::Buffer>(sizeof(vertices), (const gpu::Byte*) vertices);
|
||||
theFormat = std::make_shared<gpu::Stream::Format>();
|
||||
theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ));
|
||||
}
|
||||
|
||||
static gpu::PipelinePointer thePipeline;
|
||||
static gpu::BufferPointer theBuffer;
|
||||
static gpu::Stream::FormatPointer theFormat;
|
||||
glm::mat4 projMat;
|
||||
viewFrustum.evalProjectionMatrix(projMat);
|
||||
|
||||
Transform viewTransform;
|
||||
viewFrustum.evalViewTransform(viewTransform);
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewTransform);
|
||||
batch.setModelTransform(Transform()); // only for Mac
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8);
|
||||
batch.setInputFormat(theFormat);
|
||||
|
||||
if (skybox._procedural && skybox._procedural->_enabled && skybox._procedural->ready()) {
|
||||
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
|
||||
batch.setResourceTexture(0, skybox.getCubemap());
|
||||
}
|
||||
|
||||
skybox._procedural->prepare(batch, glm::vec3(1));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
} else if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
|
||||
static gpu::BufferPointer theConstants;
|
||||
static gpu::PipelinePointer thePipeline;
|
||||
static int SKYBOX_CONSTANTS_SLOT = 0; // need to be defined by the compilation of the shader
|
||||
if (!thePipeline) {
|
||||
auto skyVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(Skybox_vert)));
|
||||
|
@ -72,23 +109,10 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
|
|||
|
||||
thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState));
|
||||
|
||||
const float CLIP = 1.0f;
|
||||
const glm::vec2 vertices[4] = { {-CLIP, -CLIP}, {CLIP, -CLIP}, {-CLIP, CLIP}, {CLIP, CLIP}};
|
||||
theBuffer = std::make_shared<gpu::Buffer>(sizeof(vertices), (const gpu::Byte*) vertices);
|
||||
|
||||
theFormat = std::make_shared<gpu::Stream::Format>();
|
||||
theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ));
|
||||
|
||||
auto color = glm::vec4(1.0f);
|
||||
theConstants = std::make_shared<gpu::Buffer>(sizeof(color), (const gpu::Byte*) &color);
|
||||
}
|
||||
|
||||
glm::mat4 projMat;
|
||||
viewFrustum.evalProjectionMatrix(projMat);
|
||||
|
||||
Transform viewTransform;
|
||||
viewFrustum.evalViewTransform(viewTransform);
|
||||
|
||||
if (glm::all(glm::equal(skybox.getColor(), glm::vec3(0.0f)))) {
|
||||
auto color = glm::vec4(1.0f);
|
||||
theConstants->setSubData(0, sizeof(color), (const gpu::Byte*) &color);
|
||||
|
@ -96,13 +120,8 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
|
|||
theConstants->setSubData(0, sizeof(Color), (const gpu::Byte*) &skybox.getColor());
|
||||
}
|
||||
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewTransform);
|
||||
batch.setModelTransform(Transform()); // only for Mac
|
||||
batch.setPipeline(thePipeline);
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8);
|
||||
batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, theConstants, 0, theConstants->getSize());
|
||||
batch.setInputFormat(theFormat);
|
||||
batch.setResourceTexture(0, skybox.getCubemap());
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
|
|
|
@ -11,12 +11,13 @@
|
|||
#ifndef hifi_model_Skybox_h
|
||||
#define hifi_model_Skybox_h
|
||||
|
||||
#include "gpu/Texture.h"
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <gpu/Texture.h>
|
||||
|
||||
#include "Light.h"
|
||||
|
||||
class ViewFrustum;
|
||||
//class Transform;
|
||||
struct Procedural;
|
||||
namespace gpu { class Batch; }
|
||||
|
||||
namespace model {
|
||||
|
@ -35,11 +36,13 @@ public:
|
|||
void setCubemap(const gpu::TexturePointer& cubemap);
|
||||
const gpu::TexturePointer& getCubemap() const { return _cubemap; }
|
||||
|
||||
void setProcedural(QSharedPointer<Procedural> procedural);
|
||||
|
||||
static void render(gpu::Batch& batch, const ViewFrustum& frustum, const Skybox& skybox);
|
||||
|
||||
protected:
|
||||
gpu::TexturePointer _cubemap;
|
||||
|
||||
QSharedPointer<Procedural> _procedural;
|
||||
Color _color{1.0f, 1.0f, 1.0f};
|
||||
};
|
||||
typedef std::shared_ptr< Skybox > SkyboxPointer;
|
||||
|
|
|
@ -22,13 +22,29 @@ uniform skyboxBuffer {
|
|||
};
|
||||
|
||||
in vec3 _normal;
|
||||
|
||||
out vec4 _fragColor;
|
||||
|
||||
//PROCEDURAL_COMMON_BLOCK
|
||||
|
||||
#line 1001
|
||||
//PROCEDURAL_BLOCK
|
||||
|
||||
#line 2033
|
||||
void main(void) {
|
||||
|
||||
#ifdef PROCEDURAL
|
||||
|
||||
vec3 color = getSkyboxColor();
|
||||
_fragColor = vec4(color, 0.0);
|
||||
|
||||
#else
|
||||
|
||||
vec3 coord = normalize(_normal);
|
||||
vec3 texel = texture(cubeMap, coord).rgb;
|
||||
vec3 color = texel * _skybox._color.rgb;
|
||||
vec3 pixel = pow(color, vec3(1.0/2.2)); // manual Gamma correction
|
||||
_fragColor = vec4(pixel, 0.0);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) {
|
|||
case EntityAdd:
|
||||
case EntityEdit:
|
||||
case EntityData:
|
||||
return VERSION_ENTITIES_POLYVOX_NEIGHBORS;
|
||||
return VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES;
|
||||
case AvatarData:
|
||||
return 13;
|
||||
default:
|
||||
|
|
|
@ -145,5 +145,7 @@ const PacketVersion VERSION_ENTITIES_POLYLINE = 37;
|
|||
const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38;
|
||||
const PacketVersion VERSION_ENTITIES_PARTICLE_MODIFICATIONS = 39;
|
||||
const PacketVersion VERSION_ENTITIES_POLYVOX_NEIGHBORS = 40;
|
||||
const PacketVersion VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES = 41;
|
||||
const PacketVersion VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES = 42;
|
||||
|
||||
#endif // hifi_PacketHeaders_h
|
||||
|
|
10
libraries/procedural/CMakeLists.txt
Normal file
10
libraries/procedural/CMakeLists.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
set(TARGET_NAME procedural)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library()
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared gpu networking gpu-networking)
|
|
@ -6,7 +6,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "RenderableProceduralItem.h"
|
||||
#include "Procedural.h"
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
@ -14,14 +14,12 @@
|
|||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
|
||||
#include <ShaderCache.h>
|
||||
#include <EntityItem.h>
|
||||
#include <TextureCache.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <gpu-networking/ShaderCache.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
#include "RenderableProceduralItemShader.h"
|
||||
#include "../render-utils/simple_vert.h"
|
||||
#include "ProceduralShaders.h"
|
||||
|
||||
static const char* const UNIFORM_TIME_NAME= "iGlobalTime";
|
||||
static const char* const UNIFORM_SCALE_NAME = "iWorldScale";
|
||||
|
@ -30,43 +28,46 @@ static const QString PROCEDURAL_USER_DATA_KEY = "ProceduralEntity";
|
|||
static const QString URL_KEY = "shaderUrl";
|
||||
static const QString VERSION_KEY = "version";
|
||||
static const QString UNIFORMS_KEY = "uniforms";
|
||||
static const std::string PROCEDURAL_BLOCK = "//PROCEDURAL_BLOCK";
|
||||
static const std::string PROCEDURAL_COMMON_BLOCK = "//PROCEDURAL_COMMON_BLOCK";
|
||||
static const std::string PROCEDURAL_VERSION = "//PROCEDURAL_VERSION";
|
||||
|
||||
RenderableProceduralItem::ProceduralInfo::ProceduralInfo(EntityItem* entity) : _entity(entity) {
|
||||
parse();
|
||||
|
||||
// Example
|
||||
//{
|
||||
// "ProceduralEntity": {
|
||||
// "shaderUrl": "file:///C:/Users/bdavis/Git/hifi/examples/shaders/test.fs",
|
||||
// }
|
||||
//}
|
||||
QJsonValue Procedural::getProceduralData(const QString& proceduralJson) {
|
||||
if (proceduralJson.isEmpty()) {
|
||||
return QJsonValue();
|
||||
}
|
||||
|
||||
QJsonParseError parseError;
|
||||
auto doc = QJsonDocument::fromJson(proceduralJson.toUtf8(), &parseError);
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
return QJsonValue();
|
||||
}
|
||||
|
||||
return doc.object()[PROCEDURAL_USER_DATA_KEY];
|
||||
}
|
||||
|
||||
void RenderableProceduralItem::ProceduralInfo::parse() {
|
||||
|
||||
Procedural::Procedural(const QString& userDataJson) {
|
||||
parse(userDataJson);
|
||||
_state = std::make_shared<gpu::State>();
|
||||
}
|
||||
|
||||
void Procedural::parse(const QString& userDataJson) {
|
||||
_enabled = false;
|
||||
QJsonObject userData;
|
||||
{
|
||||
const QString& userDataJson = _entity->getUserData();
|
||||
if (userDataJson.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QJsonParseError parseError;
|
||||
auto doc = QJsonDocument::fromJson(userDataJson.toUtf8(), &parseError);
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
return;
|
||||
}
|
||||
userData = doc.object();
|
||||
auto proceduralData = getProceduralData(userDataJson);
|
||||
if (proceduralData.isObject()) {
|
||||
parse(proceduralData.toObject());
|
||||
}
|
||||
|
||||
// Example
|
||||
//{
|
||||
// "ProceduralEntity": {
|
||||
// "shaderUrl": "file:///C:/Users/bdavis/Git/hifi/examples/shaders/test.fs",
|
||||
// "color" : "#FFFFFF"
|
||||
// }
|
||||
//}
|
||||
auto proceduralData = userData[PROCEDURAL_USER_DATA_KEY];
|
||||
if (proceduralData.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
parse(proceduralData.toObject());
|
||||
}
|
||||
|
||||
void RenderableProceduralItem::ProceduralInfo::parse(const QJsonObject& proceduralData) {
|
||||
void Procedural::parse(const QJsonObject& proceduralData) {
|
||||
// grab the version number
|
||||
{
|
||||
auto version = proceduralData[VERSION_KEY];
|
||||
|
@ -106,7 +107,7 @@ void RenderableProceduralItem::ProceduralInfo::parse(const QJsonObject& procedur
|
|||
_enabled = true;
|
||||
}
|
||||
|
||||
bool RenderableProceduralItem::ProceduralInfo::ready() {
|
||||
bool Procedural::ready() {
|
||||
if (!_enabled) {
|
||||
return false;
|
||||
}
|
||||
|
@ -122,7 +123,7 @@ bool RenderableProceduralItem::ProceduralInfo::ready() {
|
|||
return false;
|
||||
}
|
||||
|
||||
void RenderableProceduralItem::ProceduralInfo::prepare(gpu::Batch& batch) {
|
||||
void Procedural::prepare(gpu::Batch& batch, const glm::vec3& size) {
|
||||
if (_shaderUrl.isLocalFile()) {
|
||||
auto lastModified = QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch();
|
||||
if (lastModified > _shaderModified) {
|
||||
|
@ -139,31 +140,33 @@ void RenderableProceduralItem::ProceduralInfo::prepare(gpu::Batch& batch) {
|
|||
if (!_pipeline || _pipelineDirty) {
|
||||
_pipelineDirty = true;
|
||||
if (!_vertexShader) {
|
||||
_vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert)));
|
||||
_vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(_vertexSource));
|
||||
}
|
||||
QString framentShaderSource;
|
||||
switch (_version) {
|
||||
case 1:
|
||||
framentShaderSource = SHADER_TEMPLATE_V1.arg(_shaderSource);
|
||||
break;
|
||||
|
||||
default:
|
||||
case 2:
|
||||
framentShaderSource = SHADER_TEMPLATE_V2.arg(_shaderSource);
|
||||
break;
|
||||
// Build the fragment shader
|
||||
std::string fragmentShaderSource = _fragmentSource;
|
||||
size_t replaceIndex = fragmentShaderSource.find(PROCEDURAL_COMMON_BLOCK);
|
||||
if (replaceIndex != std::string::npos) {
|
||||
fragmentShaderSource.replace(replaceIndex, PROCEDURAL_COMMON_BLOCK.size(), SHADER_COMMON);
|
||||
}
|
||||
_fragmentShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(framentShaderSource.toLocal8Bit().data())));
|
||||
|
||||
replaceIndex = fragmentShaderSource.find(PROCEDURAL_VERSION);
|
||||
if (replaceIndex != std::string::npos) {
|
||||
if (_version == 1) {
|
||||
fragmentShaderSource.replace(replaceIndex, PROCEDURAL_VERSION.size(), "#define PROCEDURAL_V1 1");
|
||||
} else if (_version == 2) {
|
||||
fragmentShaderSource.replace(replaceIndex, PROCEDURAL_VERSION.size(), "#define PROCEDURAL_V2 1");
|
||||
}
|
||||
}
|
||||
replaceIndex = fragmentShaderSource.find(PROCEDURAL_BLOCK);
|
||||
if (replaceIndex != std::string::npos) {
|
||||
fragmentShaderSource.replace(replaceIndex, PROCEDURAL_BLOCK.size(), _shaderSource.toLocal8Bit().data());
|
||||
}
|
||||
qDebug() << "FragmentShader:\n" << fragmentShaderSource.c_str();
|
||||
_fragmentShader = gpu::ShaderPointer(gpu::Shader::createPixel(fragmentShaderSource));
|
||||
_shader = gpu::ShaderPointer(gpu::Shader::createProgram(_vertexShader, _fragmentShader));
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT));
|
||||
gpu::Shader::makeProgram(*_shader, slotBindings);
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_NONE);
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
state->setBlendFunction(false,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
_pipeline = gpu::PipelinePointer(gpu::Pipeline::create(_shader, state));
|
||||
gpu::Shader::makeProgram(*_shader);
|
||||
_pipeline = gpu::PipelinePointer(gpu::Pipeline::create(_shader, _state));
|
||||
_timeSlot = _shader->getUniforms().findLocation(UNIFORM_TIME_NAME);
|
||||
_scaleSlot = _shader->getUniforms().findLocation(UNIFORM_SCALE_NAME);
|
||||
_start = usecTimestampNow();
|
||||
|
@ -221,15 +224,12 @@ void RenderableProceduralItem::ProceduralInfo::prepare(gpu::Batch& batch) {
|
|||
// Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds
|
||||
float time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND;
|
||||
batch._glUniform1f(_timeSlot, time);
|
||||
|
||||
// FIXME move into the 'set once' section, since this doesn't change over time
|
||||
auto scale = _entity->getDimensions();
|
||||
batch._glUniform3f(_scaleSlot, scale.x, scale.y, scale.z);
|
||||
batch.setResourceTexture(DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT, DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
batch._glUniform3f(_scaleSlot, size.x, size.y, size.z);
|
||||
}
|
||||
|
||||
|
||||
glm::vec4 RenderableProceduralItem::ProceduralInfo::getColor(const glm::vec4& entityColor) {
|
||||
glm::vec4 Procedural::getColor(const glm::vec4& entityColor) {
|
||||
if (_version == 1) {
|
||||
return glm::vec4(1);
|
||||
}
|
60
libraries/procedural/src/procedural/Procedural.h
Normal file
60
libraries/procedural/src/procedural/Procedural.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/09/05
|
||||
// Copyright 2013-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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_RenderableProcedrualItem_h
|
||||
#define hifi_RenderableProcedrualItem_h
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QJsonObject>
|
||||
|
||||
#include <gpu/Shader.h>
|
||||
#include <gpu/Pipeline.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu-networking/ShaderCache.h>
|
||||
|
||||
|
||||
// FIXME better encapsulation
|
||||
// FIXME better mechanism for extending to things rendered using shaders other than simple.slv
|
||||
struct Procedural {
|
||||
static QJsonValue getProceduralData(const QString& proceduralJson);
|
||||
|
||||
Procedural(const QString& userDataJson);
|
||||
void parse(const QString& userDataJson);
|
||||
void parse(const QJsonObject&);
|
||||
bool ready();
|
||||
void prepare(gpu::Batch& batch, const glm::vec3& size);
|
||||
glm::vec4 getColor(const glm::vec4& entityColor);
|
||||
|
||||
bool _enabled{ false };
|
||||
uint8_t _version{ 1 };
|
||||
|
||||
std::string _vertexSource;
|
||||
std::string _fragmentSource;
|
||||
|
||||
QString _shaderSource;
|
||||
QString _shaderPath;
|
||||
QUrl _shaderUrl;
|
||||
quint64 _shaderModified{ 0 };
|
||||
bool _pipelineDirty{ true };
|
||||
int32_t _timeSlot{ gpu::Shader::INVALID_LOCATION };
|
||||
int32_t _scaleSlot{ gpu::Shader::INVALID_LOCATION };
|
||||
uint64_t _start{ 0 };
|
||||
NetworkShaderPointer _networkShader;
|
||||
QJsonObject _uniforms;
|
||||
|
||||
gpu::PipelinePointer _pipeline;
|
||||
gpu::ShaderPointer _vertexShader;
|
||||
gpu::ShaderPointer _fragmentShader;
|
||||
gpu::ShaderPointer _shader;
|
||||
gpu::StatePointer _state;
|
||||
};
|
||||
|
||||
#endif
|
276
libraries/procedural/src/procedural/ProceduralShaders.h
Normal file
276
libraries/procedural/src/procedural/ProceduralShaders.h
Normal file
|
@ -0,0 +1,276 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/09/05
|
||||
// Copyright 2013-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
|
||||
//
|
||||
|
||||
// Shader includes portions of webgl-noise:
|
||||
// Description : Array and textureless GLSL 2D/3D/4D simplex
|
||||
// noise functions.
|
||||
// Author : Ian McEwan, Ashima Arts.
|
||||
// Maintainer : ijm
|
||||
// Lastmod : 20110822 (ijm)
|
||||
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
|
||||
// Distributed under the MIT License. See LICENSE file.
|
||||
// https://github.com/ashima/webgl-noise
|
||||
//
|
||||
|
||||
|
||||
const std::string SHADER_COMMON = R"SHADER(
|
||||
|
||||
float mod289(float x) {
|
||||
return x - floor(x * (1.0 / 289.0)) * 289.0;
|
||||
}
|
||||
|
||||
vec2 mod289(vec2 x) {
|
||||
return x - floor(x * (1.0 / 289.0)) * 289.0;
|
||||
}
|
||||
|
||||
vec3 mod289(vec3 x) {
|
||||
return x - floor(x * (1.0 / 289.0)) * 289.0;
|
||||
}
|
||||
|
||||
vec4 mod289(vec4 x) {
|
||||
return x - floor(x * (1.0 / 289.0)) * 289.0;
|
||||
}
|
||||
|
||||
float permute(float x) {
|
||||
return mod289(((x*34.0)+1.0)*x);
|
||||
}
|
||||
|
||||
vec3 permute(vec3 x) {
|
||||
return mod289(((x*34.0)+1.0)*x);
|
||||
}
|
||||
|
||||
vec4 permute(vec4 x) {
|
||||
return mod289(((x*34.0)+1.0)*x);
|
||||
}
|
||||
|
||||
float taylorInvSqrt(float r) {
|
||||
return 1.79284291400159 - 0.85373472095314 * r;
|
||||
}
|
||||
|
||||
vec4 taylorInvSqrt(vec4 r) {
|
||||
return 1.79284291400159 - 0.85373472095314 * r;
|
||||
}
|
||||
|
||||
vec4 grad4(float j, vec4 ip) {
|
||||
const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0);
|
||||
vec4 p, s;
|
||||
|
||||
p.xyz = floor(fract(vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0;
|
||||
p.w = 1.5 - dot(abs(p.xyz), ones.xyz);
|
||||
s = vec4(lessThan(p, vec4(0.0)));
|
||||
p.xyz = p.xyz + (s.xyz * 2.0 - 1.0) * s.www;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// (sqrt(5) - 1)/4 = F4, used once below
|
||||
#define F4 0.309016994374947451
|
||||
|
||||
float snoise(vec4 v) {
|
||||
const vec4 C = vec4(0.138196601125011, // (5 - sqrt(5))/20 G4
|
||||
0.276393202250021, // 2 * G4
|
||||
0.414589803375032, // 3 * G4
|
||||
-0.447213595499958); // -1 + 4 * G4
|
||||
|
||||
// First corner
|
||||
vec4 i = floor(v + dot(v, vec4(F4)));
|
||||
vec4 x0 = v - i + dot(i, C.xxxx);
|
||||
|
||||
// Other corners
|
||||
|
||||
// Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI)
|
||||
vec4 i0;
|
||||
vec3 isX = step(x0.yzw, x0.xxx);
|
||||
vec3 isYZ = step(x0.zww, x0.yyz);
|
||||
i0.x = isX.x + isX.y + isX.z;
|
||||
i0.yzw = 1.0 - isX;
|
||||
i0.y += isYZ.x + isYZ.y;
|
||||
i0.zw += 1.0 - isYZ.xy;
|
||||
i0.z += isYZ.z;
|
||||
i0.w += 1.0 - isYZ.z;
|
||||
|
||||
// i0 now contains the unique values 0,1,2,3 in each channel
|
||||
vec4 i3 = clamp(i0, 0.0, 1.0);
|
||||
vec4 i2 = clamp(i0 - 1.0, 0.0, 1.0);
|
||||
vec4 i1 = clamp(i0 - 2.0, 0.0, 1.0);
|
||||
|
||||
vec4 x1 = x0 - i1 + C.xxxx;
|
||||
vec4 x2 = x0 - i2 + C.yyyy;
|
||||
vec4 x3 = x0 - i3 + C.zzzz;
|
||||
vec4 x4 = x0 + C.wwww;
|
||||
|
||||
// Permutations
|
||||
i = mod289(i);
|
||||
float j0 = permute(permute(permute(permute(i.w) + i.z) + i.y) + i.x);
|
||||
vec4 j1 = permute(
|
||||
permute(
|
||||
permute(
|
||||
permute(i.w + vec4(i1.w, i2.w, i3.w, 1.0)) + i.z
|
||||
+ vec4(i1.z, i2.z, i3.z, 1.0)) + i.y
|
||||
+ vec4(i1.y, i2.y, i3.y, 1.0)) + i.x
|
||||
+ vec4(i1.x, i2.x, i3.x, 1.0));
|
||||
|
||||
// Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope
|
||||
// 7*7*6 = 294, which is close to the ring size 17*17 = 289.
|
||||
vec4 ip = vec4(1.0 / 294.0, 1.0 / 49.0, 1.0 / 7.0, 0.0);
|
||||
|
||||
vec4 p0 = grad4(j0, ip);
|
||||
vec4 p1 = grad4(j1.x, ip);
|
||||
vec4 p2 = grad4(j1.y, ip);
|
||||
vec4 p3 = grad4(j1.z, ip);
|
||||
vec4 p4 = grad4(j1.w, ip);
|
||||
|
||||
// Normalise gradients
|
||||
vec4 norm = taylorInvSqrt(
|
||||
vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
|
||||
p0 *= norm.x;
|
||||
p1 *= norm.y;
|
||||
p2 *= norm.z;
|
||||
p3 *= norm.w;
|
||||
p4 *= taylorInvSqrt(dot(p4, p4));
|
||||
|
||||
// Mix contributions from the five corners
|
||||
vec3 m0 = max(0.6 - vec3(dot(x0, x0), dot(x1, x1), dot(x2, x2)), 0.0);
|
||||
vec2 m1 = max(0.6 - vec2(dot(x3, x3), dot(x4, x4)), 0.0);
|
||||
m0 = m0 * m0;
|
||||
m1 = m1 * m1;
|
||||
return 49.0
|
||||
* (dot(m0 * m0, vec3(dot(p0, x0), dot(p1, x1), dot(p2, x2)))
|
||||
+ dot(m1 * m1, vec2(dot(p3, x3), dot(p4, x4))));
|
||||
|
||||
}
|
||||
|
||||
float snoise(vec3 v) {
|
||||
const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0);
|
||||
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
|
||||
|
||||
// First corner
|
||||
vec3 i = floor(v + dot(v, C.yyy));
|
||||
vec3 x0 = v - i + dot(i, C.xxx);
|
||||
|
||||
// Other corners
|
||||
vec3 g = step(x0.yzx, x0.xyz);
|
||||
vec3 l = 1.0 - g;
|
||||
vec3 i1 = min(g.xyz, l.zxy);
|
||||
vec3 i2 = max(g.xyz, l.zxy);
|
||||
|
||||
vec3 x1 = x0 - i1 + C.xxx;
|
||||
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
|
||||
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
|
||||
|
||||
// Permutations
|
||||
i = mod289(i);
|
||||
vec4 p = permute(
|
||||
permute(
|
||||
permute(i.z + vec4(0.0, i1.z, i2.z, 1.0)) + i.y
|
||||
+ vec4(0.0, i1.y, i2.y, 1.0)) + i.x
|
||||
+ vec4(0.0, i1.x, i2.x, 1.0));
|
||||
|
||||
// Gradients: 7x7 points over a square, mapped onto an octahedron.
|
||||
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
|
||||
float n_ = 0.142857142857; // 1.0/7.0
|
||||
vec3 ns = n_ * D.wyz - D.xzx;
|
||||
|
||||
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
|
||||
|
||||
vec4 x_ = floor(j * ns.z);
|
||||
vec4 y_ = floor(j - 7.0 * x_); // mod(j,N)
|
||||
|
||||
vec4 x = x_ * ns.x + ns.yyyy;
|
||||
vec4 y = y_ * ns.x + ns.yyyy;
|
||||
vec4 h = 1.0 - abs(x) - abs(y);
|
||||
|
||||
vec4 b0 = vec4(x.xy, y.xy);
|
||||
vec4 b1 = vec4(x.zw, y.zw);
|
||||
|
||||
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
|
||||
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
|
||||
vec4 s0 = floor(b0) * 2.0 + 1.0;
|
||||
vec4 s1 = floor(b1) * 2.0 + 1.0;
|
||||
vec4 sh = -step(h, vec4(0.0));
|
||||
|
||||
vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
|
||||
vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
|
||||
|
||||
vec3 p0 = vec3(a0.xy, h.x);
|
||||
vec3 p1 = vec3(a0.zw, h.y);
|
||||
vec3 p2 = vec3(a1.xy, h.z);
|
||||
vec3 p3 = vec3(a1.zw, h.w);
|
||||
|
||||
//Normalise gradients
|
||||
vec4 norm = taylorInvSqrt(
|
||||
vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
|
||||
p0 *= norm.x;
|
||||
p1 *= norm.y;
|
||||
p2 *= norm.z;
|
||||
p3 *= norm.w;
|
||||
|
||||
// Mix final noise value
|
||||
vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)),
|
||||
0.0);
|
||||
m = m * m;
|
||||
return 42.0
|
||||
* dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));
|
||||
}
|
||||
|
||||
float snoise(vec2 v) {
|
||||
const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0
|
||||
0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
|
||||
-0.577350269189626, // -1.0 + 2.0 * C.x
|
||||
0.024390243902439); // 1.0 / 41.0
|
||||
// First corner
|
||||
vec2 i = floor(v + dot(v, C.yy));
|
||||
vec2 x0 = v - i + dot(i, C.xx);
|
||||
|
||||
// Other corners
|
||||
vec2 i1;
|
||||
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
|
||||
vec4 x12 = x0.xyxy + C.xxzz;
|
||||
x12.xy -= i1;
|
||||
|
||||
// Permutations
|
||||
i = mod289(i); // Avoid truncation effects in permutation
|
||||
vec3 p = permute(
|
||||
permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0));
|
||||
|
||||
vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)),
|
||||
0.0);
|
||||
m = m * m;
|
||||
m = m * m;
|
||||
|
||||
// Gradients: 41 points uniformly over a line, mapped onto a diamond.
|
||||
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
|
||||
|
||||
vec3 x = 2.0 * fract(p * C.www) - 1.0;
|
||||
vec3 h = abs(x) - 0.5;
|
||||
vec3 ox = floor(x + 0.5);
|
||||
vec3 a0 = x - ox;
|
||||
|
||||
// Normalise gradients implicitly by scaling m
|
||||
// Approximation of: m *= inversesqrt( a0*a0 + h*h );
|
||||
m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);
|
||||
|
||||
// Compute final noise value at P
|
||||
vec3 g;
|
||||
g.x = a0.x * x0.x + h.x * x0.y;
|
||||
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
|
||||
return 130.0 * dot(m, g);
|
||||
}
|
||||
|
||||
// TODO add more uniforms
|
||||
uniform float iGlobalTime; // shader playback time (in seconds)
|
||||
uniform vec3 iWorldScale; // the dimensions of the object being rendered
|
||||
|
||||
// TODO add support for textures
|
||||
// TODO document available inputs other than the uniforms
|
||||
// TODO provide world scale in addition to the untransformed position
|
||||
|
||||
#define PROCEDURAL 1
|
||||
|
||||
//PROCEDURAL_VERSION
|
||||
)SHADER";
|
|
@ -40,4 +40,4 @@ add_dependency_external_projects(oglplus)
|
|||
find_package(OGLPLUS REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(animation fbx shared gpu model render environment)
|
||||
link_hifi_libraries(shared gpu gpu-networking procedural model render environment animation fbx)
|
||||
|
|
|
@ -1,171 +1,2 @@
|
|||
//
|
||||
// TextureCache.h
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Andrzej Kapolka on 8/6/13.
|
||||
// Copyright 2013 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_TextureCache_h
|
||||
#define hifi_TextureCache_h
|
||||
|
||||
#include <gpu/Texture.h>
|
||||
#include <model/Light.h>
|
||||
|
||||
#include <QImage>
|
||||
#include <QMap>
|
||||
#include <QColor>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <ResourceCache.h>
|
||||
|
||||
namespace gpu {
|
||||
class Batch;
|
||||
}
|
||||
class NetworkTexture;
|
||||
|
||||
typedef QSharedPointer<NetworkTexture> NetworkTexturePointer;
|
||||
|
||||
enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, SPLAT_TEXTURE, CUBE_TEXTURE };
|
||||
|
||||
/// Stores cached textures, including render-to-texture targets.
|
||||
class TextureCache : public ResourceCache, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
/// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture
|
||||
/// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and
|
||||
/// the second, a set of random unit vectors to be used as noise gradients.
|
||||
const gpu::TexturePointer& getPermutationNormalTexture();
|
||||
|
||||
/// Returns an opaque white texture (useful for a default).
|
||||
const gpu::TexturePointer& getWhiteTexture();
|
||||
|
||||
/// Returns an opaque gray texture (useful for a default).
|
||||
const gpu::TexturePointer& getGrayTexture();
|
||||
|
||||
/// Returns the a pale blue texture (useful for a normal map).
|
||||
const gpu::TexturePointer& getBlueTexture();
|
||||
|
||||
/// Returns the a black texture (useful for a default).
|
||||
const gpu::TexturePointer& getBlackTexture();
|
||||
|
||||
// Returns a map used to compress the normals through a fitting scale algorithm
|
||||
const gpu::TexturePointer& getNormalFittingTexture();
|
||||
|
||||
/// Returns a texture version of an image file
|
||||
static gpu::TexturePointer getImageTexture(const QString& path);
|
||||
|
||||
/// Loads a texture from the specified URL.
|
||||
NetworkTexturePointer getTexture(const QUrl& url, TextureType type = DEFAULT_TEXTURE, bool dilatable = false,
|
||||
const QByteArray& content = QByteArray());
|
||||
|
||||
protected:
|
||||
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url,
|
||||
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra);
|
||||
|
||||
private:
|
||||
TextureCache();
|
||||
virtual ~TextureCache();
|
||||
friend class DilatableNetworkTexture;
|
||||
|
||||
gpu::TexturePointer _permutationNormalTexture;
|
||||
gpu::TexturePointer _whiteTexture;
|
||||
gpu::TexturePointer _grayTexture;
|
||||
gpu::TexturePointer _blueTexture;
|
||||
gpu::TexturePointer _blackTexture;
|
||||
gpu::TexturePointer _normalFittingTexture;
|
||||
|
||||
QHash<QUrl, QWeakPointer<NetworkTexture> > _dilatableNetworkTextures;
|
||||
};
|
||||
|
||||
/// A simple object wrapper for an OpenGL texture.
|
||||
class Texture {
|
||||
public:
|
||||
friend class TextureCache;
|
||||
friend class DilatableNetworkTexture;
|
||||
Texture();
|
||||
~Texture();
|
||||
|
||||
const gpu::TexturePointer& getGPUTexture() const { return _gpuTexture; }
|
||||
|
||||
protected:
|
||||
gpu::TexturePointer _gpuTexture;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
/// A texture loaded from the network.
|
||||
|
||||
class NetworkTexture : public Resource, public Texture {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
NetworkTexture(const QUrl& url, TextureType type, const QByteArray& content);
|
||||
|
||||
/// Checks whether it "looks like" this texture is translucent
|
||||
/// (majority of pixels neither fully opaque or fully transparent).
|
||||
bool isTranslucent() const { return _translucent; }
|
||||
|
||||
/// Returns the lazily-computed average texture color.
|
||||
const QColor& getAverageColor() const { return _averageColor; }
|
||||
|
||||
int getOriginalWidth() const { return _originalWidth; }
|
||||
int getOriginalHeight() const { return _originalHeight; }
|
||||
int getWidth() const { return _width; }
|
||||
int getHeight() const { return _height; }
|
||||
TextureType getType() const { return _type; }
|
||||
protected:
|
||||
|
||||
virtual void downloadFinished(QNetworkReply* reply);
|
||||
|
||||
Q_INVOKABLE void loadContent(const QByteArray& content);
|
||||
// FIXME: This void* should be a gpu::Texture* but i cannot get it to work for now, moving on...
|
||||
Q_INVOKABLE void setImage(const QImage& image, void* texture, bool translucent, const QColor& averageColor, int originalWidth,
|
||||
int originalHeight);
|
||||
|
||||
virtual void imageLoaded(const QImage& image);
|
||||
|
||||
TextureType _type;
|
||||
|
||||
private:
|
||||
bool _translucent;
|
||||
QColor _averageColor;
|
||||
int _originalWidth;
|
||||
int _originalHeight;
|
||||
int _width;
|
||||
int _height;
|
||||
};
|
||||
|
||||
/// Caches derived, dilated textures.
|
||||
class DilatableNetworkTexture : public NetworkTexture {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
DilatableNetworkTexture(const QUrl& url, const QByteArray& content);
|
||||
|
||||
/// Returns a pointer to a texture with the requested amount of dilation.
|
||||
QSharedPointer<Texture> getDilatedTexture(float dilation);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void imageLoaded(const QImage& image);
|
||||
virtual void reinsert();
|
||||
|
||||
private:
|
||||
|
||||
QImage _image;
|
||||
int _innerRadius;
|
||||
int _outerRadius;
|
||||
|
||||
QMap<float, QWeakPointer<Texture> > _dilatedTextures;
|
||||
};
|
||||
|
||||
#endif // hifi_TextureCache_h
|
||||
// Compatibility
|
||||
#include <gpu-networking/TextureCache.h>
|
||||
|
|
|
@ -18,12 +18,39 @@
|
|||
// the interpolated normal
|
||||
in vec3 _normal;
|
||||
in vec3 _color;
|
||||
in vec2 _texCoord0;
|
||||
in vec4 _position;
|
||||
|
||||
//PROCEDURAL_COMMON_BLOCK
|
||||
|
||||
#line 1001
|
||||
//PROCEDURAL_BLOCK
|
||||
|
||||
#line 2030
|
||||
void main(void) {
|
||||
Material material = getMaterial();
|
||||
packDeferredFragment(
|
||||
normalize(_normal.xyz),
|
||||
glowIntensity,
|
||||
_color.rgb,
|
||||
DEFAULT_SPECULAR, DEFAULT_SHININESS);
|
||||
vec3 normal = normalize(_normal.xyz);
|
||||
vec3 diffuse = _color.rgb;
|
||||
vec3 specular = DEFAULT_SPECULAR;
|
||||
float shininess = DEFAULT_SHININESS;
|
||||
float emissiveAmount = 0.0;
|
||||
|
||||
#ifdef PROCEDURAL
|
||||
|
||||
#ifdef PROCEDURAL_V1
|
||||
specular = getProceduralColor().rgb;
|
||||
emissiveAmount = 1.0;
|
||||
#else
|
||||
emissiveAmount = getProceduralColors(diffuse, specular, shininess);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
if (emissiveAmount > 0.0) {
|
||||
packDeferredFragmentLightmap(
|
||||
normal, glowIntensity, diffuse, specular, shininess, specular);
|
||||
} else {
|
||||
packDeferredFragment(
|
||||
normal, glowIntensity, diffuse, specular, shininess);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,4 +7,4 @@ add_dependency_external_projects(glm)
|
|||
find_package(GLM REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared octree gpu model fbx entities animation audio physics)
|
||||
link_hifi_libraries(shared networking octree gpu gpu-networking procedural model fbx entities animation audio physics)
|
||||
|
|
|
@ -10,6 +10,6 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
|||
#include_oglplus()
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(render-utils gpu shared networking fbx model animation script-engine)
|
||||
link_hifi_libraries(networking gpu gpu-networking procedural shared fbx model animation script-engine render-utils )
|
||||
|
||||
copy_dlls_beside_windows_executable()
|
Loading…
Reference in a new issue