Merge branch 'master' into menu

This commit is contained in:
Brad Davis 2015-05-12 14:58:42 -07:00
commit f42e0c696a
31 changed files with 1674 additions and 424 deletions

93
examples/ajt-test.js Normal file
View file

@ -0,0 +1,93 @@
(function () {
var spawnPoint = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation())));
// constructor
function TestBox() {
this.entity = Entities.addEntity({ type: "Box",
position: spawnPoint,
dimentions: { x: 1, y: 1, z: 1 },
color: { red: 100, green: 100, blue: 255 },
gravity: { x: 0, y: 0, z: 0 },
visible: true,
locked: false,
lifetime: 6000 });
var self = this;
this.timer = Script.setInterval(function () {
var colorProp = { color: { red: Math.random() * 255,
green: Math.random() * 255,
blue: Math.random() * 255 } };
Entities.editEntity(self.entity, colorProp);
}, 1000);
}
TestBox.prototype.Destroy = function () {
Script.clearInterval(this.timer);
Entities.editEntity(this.entity, { locked: false });
Entities.deleteEntity(this.entity);
}
// constructor
function TestFx(color, emitDirection, emitRate, emitStrength, blinkRate) {
var animationSettings = JSON.stringify({ fps: 30,
frameIndex: 0,
running: true,
firstFrame: 0,
lastFrame: 30,
loop: true });
this.entity = Entities.addEntity({ type: "ParticleEffect",
animationSettings: animationSettings,
position: spawnPoint,
textures: "http://www.hyperlogic.org/images/particle.png",
emitRate: emitRate,
emitStrength: emitStrength,
emitDirection: emitDirection,
color: color,
visible: true,
locked: false });
this.isPlaying = true;
var self = this;
this.timer = Script.setInterval(function () {
// flip is playing state
self.isPlaying = !self.isPlaying;
var animProp = { animationIsPlaying: self.isPlaying };
Entities.editEntity(self.entity, animProp);
}, (1 / blinkRate) * 1000);
}
TestFx.prototype.Destroy = function () {
Script.clearInterval(this.timer);
Entities.editEntity(this.entity, { locked: false });
Entities.deleteEntity(this.entity);
}
var objs = [];
function Init() {
objs.push(new TestBox());
objs.push(new TestFx({ red: 255, blue: 0, green: 0 },
{ x: 0.5, y: 1.0, z: 0.0 },
100, 3, 1));
objs.push(new TestFx({ red: 0, blue: 255, green: 0 },
{ x: 0, y: 1, z: 0 },
1000, 5, 0.5));
objs.push(new TestFx({ red: 0, blue: 0, green: 255 },
{ x: -0.5, y: 1, z: 0 },
100, 3, 1));
}
function ShutDown() {
var i, len = objs.length;
for (i = 0; i < len; i++) {
objs[i].Destroy();
}
objs = [];
}
Init();
Script.scriptEnding.connect(ShutDown);
})();

View file

@ -28,7 +28,6 @@ Script.include([
"libraries/gridTool.js",
"libraries/entityList.js",
"libraries/lightOverlayManager.js",
"libraries/zoneOverlayManager.js",
]);
var selectionDisplay = SelectionDisplay;
@ -36,7 +35,6 @@ var selectionManager = SelectionManager;
var entityPropertyDialogBox = EntityPropertyDialogBox;
var lightOverlayManager = new LightOverlayManager();
var zoneOverlayManager = new ZoneOverlayManager();
var cameraManager = new CameraManager();
@ -49,7 +47,6 @@ var entityListTool = EntityListTool();
selectionManager.addEventListener(function() {
selectionDisplay.updateHandles();
lightOverlayManager.updatePositions();
zoneOverlayManager.updatePositions();
});
var windowDimensions = Controller.getViewportDimensions();
@ -246,7 +243,7 @@ var toolBar = (function () {
}
toolBar.selectTool(activeButton, isActive);
lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE));
zoneOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
Entities.setDrawZoneBoundaries(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
};
// Sets visibility of tool buttons, excluding the power button
@ -1000,7 +997,7 @@ function handeMenuEvent(menuItem) {
} else if (menuItem == MENU_SHOW_LIGHTS_IN_EDIT_MODE) {
lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE));
} else if (menuItem == MENU_SHOW_ZONES_IN_EDIT_MODE) {
zoneOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
Entities.setDrawZoneBoundaries(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
}
tooltip.show(false);
}
@ -1030,8 +1027,11 @@ function importSVO(importURL) {
var success = Clipboard.importEntities(importURL);
if (success) {
var position = getPositionToCreateEntity();
var VERY_LARGE = 10000;
var position = { x: 0, y: 0, z: 0};
if (Clipboard.getClipboardContentsLargestDimension() < VERY_LARGE) {
position = getPositionToCreateEntity();
}
var pastedEntityIDs = Clipboard.pasteEntities(position);
if (isActive) {
@ -1295,6 +1295,25 @@ PropertiesTool = function(opts) {
pushCommandForSelections();
selectionManager._update();
}
} else if (data.action == "centerAtmosphereToZone") {
if (selectionManager.hasSelection()) {
selectionManager.saveProperties();
for (var i = 0; i < selectionManager.selections.length; i++) {
var properties = selectionManager.savedProperties[selectionManager.selections[i].id];
if (properties.type == "Zone") {
var centerOfZone = properties.boundingBox.center;
var atmosphereCenter = { x: centerOfZone.x,
y: centerOfZone.y - properties.atmosphere.innerRadius,
z: centerOfZone.z };
Entities.editEntity(selectionManager.selections[i], {
atmosphere: { center: atmosphereCenter },
});
}
}
pushCommandForSelections();
selectionManager._update();
}
}
}
});

520
examples/html/colpick.js Normal file
View file

@ -0,0 +1,520 @@
/*
colpick Color Picker
Copyright 2013 Jose Vargas. Licensed under GPL license. Based on Stefan Petre's Color Picker www.eyecon.ro, dual licensed under the MIT and GPL licenses
For usage and examples: colpick.com/plugin
*/
(function ($) {
var colpick = function () {
var
tpl = '<div class="colpick"><div class="colpick_color"><div class="colpick_color_overlay1"><div class="colpick_color_overlay2"><div class="colpick_selector_outer"><div class="colpick_selector_inner"></div></div></div></div></div><div class="colpick_hue"><div class="colpick_hue_arrs"><div class="colpick_hue_larr"></div><div class="colpick_hue_rarr"></div></div></div><div class="colpick_new_color"></div><div class="colpick_current_color"></div><div class="colpick_hex_field"><div class="colpick_field_letter">#</div><input type="text" maxlength="6" size="6" /></div><div class="colpick_rgb_r colpick_field"><div class="colpick_field_letter">R</div><input type="text" maxlength="3" size="3" /><div class="colpick_field_arrs"><div class="colpick_field_uarr"></div><div class="colpick_field_darr"></div></div></div><div class="colpick_rgb_g colpick_field"><div class="colpick_field_letter">G</div><input type="text" maxlength="3" size="3" /><div class="colpick_field_arrs"><div class="colpick_field_uarr"></div><div class="colpick_field_darr"></div></div></div><div class="colpick_rgb_b colpick_field"><div class="colpick_field_letter">B</div><input type="text" maxlength="3" size="3" /><div class="colpick_field_arrs"><div class="colpick_field_uarr"></div><div class="colpick_field_darr"></div></div></div><div class="colpick_hsb_h colpick_field"><div class="colpick_field_letter">H</div><input type="text" maxlength="3" size="3" /><div class="colpick_field_arrs"><div class="colpick_field_uarr"></div><div class="colpick_field_darr"></div></div></div><div class="colpick_hsb_s colpick_field"><div class="colpick_field_letter">S</div><input type="text" maxlength="3" size="3" /><div class="colpick_field_arrs"><div class="colpick_field_uarr"></div><div class="colpick_field_darr"></div></div></div><div class="colpick_hsb_b colpick_field"><div class="colpick_field_letter">B</div><input type="text" maxlength="3" size="3" /><div class="colpick_field_arrs"><div class="colpick_field_uarr"></div><div class="colpick_field_darr"></div></div></div><div class="colpick_submit"></div></div>',
defaults = {
showEvent: 'click',
onShow: function () {},
onBeforeShow: function(){},
onHide: function () {},
onChange: function () {},
onSubmit: function () {},
colorScheme: 'light',
color: '3289c7',
livePreview: true,
flat: false,
layout: 'full',
submit: 1,
submitText: 'OK',
height: 156
},
//Fill the inputs of the plugin
fillRGBFields = function (hsb, cal) {
var rgb = hsbToRgb(hsb);
$(cal).data('colpick').fields
.eq(1).val(rgb.r).end()
.eq(2).val(rgb.g).end()
.eq(3).val(rgb.b).end();
},
fillHSBFields = function (hsb, cal) {
$(cal).data('colpick').fields
.eq(4).val(Math.round(hsb.h)).end()
.eq(5).val(Math.round(hsb.s)).end()
.eq(6).val(Math.round(hsb.b)).end();
},
fillHexFields = function (hsb, cal) {
$(cal).data('colpick').fields.eq(0).val(hsbToHex(hsb));
},
//Set the round selector position
setSelector = function (hsb, cal) {
$(cal).data('colpick').selector.css('backgroundColor', '#' + hsbToHex({h: hsb.h, s: 100, b: 100}));
$(cal).data('colpick').selectorIndic.css({
left: parseInt($(cal).data('colpick').height * hsb.s/100, 10),
top: parseInt($(cal).data('colpick').height * (100-hsb.b)/100, 10)
});
},
//Set the hue selector position
setHue = function (hsb, cal) {
$(cal).data('colpick').hue.css('top', parseInt($(cal).data('colpick').height - $(cal).data('colpick').height * hsb.h/360, 10));
},
//Set current and new colors
setCurrentColor = function (hsb, cal) {
$(cal).data('colpick').currentColor.css('backgroundColor', '#' + hsbToHex(hsb));
},
setNewColor = function (hsb, cal) {
$(cal).data('colpick').newColor.css('backgroundColor', '#' + hsbToHex(hsb));
},
//Called when the new color is changed
change = function (ev) {
var cal = $(this).parent().parent(), col;
if (this.parentNode.className.indexOf('_hex') > 0) {
cal.data('colpick').color = col = hexToHsb(fixHex(this.value));
fillRGBFields(col, cal.get(0));
fillHSBFields(col, cal.get(0));
} else if (this.parentNode.className.indexOf('_hsb') > 0) {
cal.data('colpick').color = col = fixHSB({
h: parseInt(cal.data('colpick').fields.eq(4).val(), 10),
s: parseInt(cal.data('colpick').fields.eq(5).val(), 10),
b: parseInt(cal.data('colpick').fields.eq(6).val(), 10)
});
fillRGBFields(col, cal.get(0));
fillHexFields(col, cal.get(0));
} else {
cal.data('colpick').color = col = rgbToHsb(fixRGB({
r: parseInt(cal.data('colpick').fields.eq(1).val(), 10),
g: parseInt(cal.data('colpick').fields.eq(2).val(), 10),
b: parseInt(cal.data('colpick').fields.eq(3).val(), 10)
}));
fillHexFields(col, cal.get(0));
fillHSBFields(col, cal.get(0));
}
setSelector(col, cal.get(0));
setHue(col, cal.get(0));
setNewColor(col, cal.get(0));
cal.data('colpick').onChange.apply(cal.parent(), [col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el, 0]);
},
//Change style on blur and on focus of inputs
blur = function (ev) {
$(this).parent().removeClass('colpick_focus');
},
focus = function () {
$(this).parent().parent().data('colpick').fields.parent().removeClass('colpick_focus');
$(this).parent().addClass('colpick_focus');
},
//Increment/decrement arrows functions
downIncrement = function (ev) {
ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
var field = $(this).parent().find('input').focus();
var current = {
el: $(this).parent().addClass('colpick_slider'),
max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255),
y: ev.pageY,
field: field,
val: parseInt(field.val(), 10),
preview: $(this).parent().parent().data('colpick').livePreview
};
$(document).mouseup(current, upIncrement);
$(document).mousemove(current, moveIncrement);
},
moveIncrement = function (ev) {
ev.data.field.val(Math.max(0, Math.min(ev.data.max, parseInt(ev.data.val - ev.pageY + ev.data.y, 10))));
if (ev.data.preview) {
change.apply(ev.data.field.get(0), [true]);
}
return false;
},
upIncrement = function (ev) {
change.apply(ev.data.field.get(0), [true]);
ev.data.el.removeClass('colpick_slider').find('input').focus();
$(document).off('mouseup', upIncrement);
$(document).off('mousemove', moveIncrement);
return false;
},
//Hue slider functions
downHue = function (ev) {
ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
var current = {
cal: $(this).parent(),
y: $(this).offset().top
};
$(document).on('mouseup touchend',current,upHue);
$(document).on('mousemove touchmove',current,moveHue);
var pageY = ((ev.type == 'touchstart') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY );
change.apply(
current.cal.data('colpick')
.fields.eq(4).val(parseInt(360*(current.cal.data('colpick').height - (pageY - current.y))/current.cal.data('colpick').height, 10))
.get(0),
[current.cal.data('colpick').livePreview]
);
return false;
},
moveHue = function (ev) {
var pageY = ((ev.type == 'touchmove') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY );
change.apply(
ev.data.cal.data('colpick')
.fields.eq(4).val(parseInt(360*(ev.data.cal.data('colpick').height - Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageY - ev.data.y))))/ev.data.cal.data('colpick').height, 10))
.get(0),
[ev.data.preview]
);
return false;
},
upHue = function (ev) {
fillRGBFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0));
fillHexFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0));
$(document).off('mouseup touchend',upHue);
$(document).off('mousemove touchmove',moveHue);
return false;
},
//Color selector functions
downSelector = function (ev) {
ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
var current = {
cal: $(this).parent(),
pos: $(this).offset()
};
current.preview = current.cal.data('colpick').livePreview;
$(document).on('mouseup touchend',current,upSelector);
$(document).on('mousemove touchmove',current,moveSelector);
var payeX,pageY;
if(ev.type == 'touchstart') {
pageX = ev.originalEvent.changedTouches[0].pageX,
pageY = ev.originalEvent.changedTouches[0].pageY;
} else {
pageX = ev.pageX;
pageY = ev.pageY;
}
change.apply(
current.cal.data('colpick').fields
.eq(6).val(parseInt(100*(current.cal.data('colpick').height - (pageY - current.pos.top))/current.cal.data('colpick').height, 10)).end()
.eq(5).val(parseInt(100*(pageX - current.pos.left)/current.cal.data('colpick').height, 10))
.get(0),
[current.preview]
);
return false;
},
moveSelector = function (ev) {
var payeX,pageY;
if(ev.type == 'touchmove') {
pageX = ev.originalEvent.changedTouches[0].pageX,
pageY = ev.originalEvent.changedTouches[0].pageY;
} else {
pageX = ev.pageX;
pageY = ev.pageY;
}
change.apply(
ev.data.cal.data('colpick').fields
.eq(6).val(parseInt(100*(ev.data.cal.data('colpick').height - Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageY - ev.data.pos.top))))/ev.data.cal.data('colpick').height, 10)).end()
.eq(5).val(parseInt(100*(Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageX - ev.data.pos.left))))/ev.data.cal.data('colpick').height, 10))
.get(0),
[ev.data.preview]
);
return false;
},
upSelector = function (ev) {
fillRGBFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0));
fillHexFields(ev.data.cal.data('colpick').color, ev.data.cal.get(0));
$(document).off('mouseup touchend',upSelector);
$(document).off('mousemove touchmove',moveSelector);
return false;
},
//Submit button
clickSubmit = function (ev) {
var cal = $(this).parent();
var col = cal.data('colpick').color;
cal.data('colpick').origColor = col;
setCurrentColor(col, cal.get(0));
cal.data('colpick').onSubmit(col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el);
},
//Show/hide the color picker
show = function (ev) {
// Prevent the trigger of any direct parent
ev.stopPropagation();
var cal = $('#' + $(this).data('colpickId'));
cal.data('colpick').onBeforeShow.apply(this, [cal.get(0)]);
var pos = $(this).offset();
var top = pos.top + this.offsetHeight;
var left = pos.left;
var viewPort = getViewport();
var calW = cal.width();
if (left + calW > viewPort.l + viewPort.w) {
left -= calW;
}
cal.css({left: left + 'px', top: top + 'px'});
if (cal.data('colpick').onShow.apply(this, [cal.get(0)]) != false) {
cal.show();
}
//Hide when user clicks outside
$('html').mousedown({cal:cal}, hide);
cal.mousedown(function(ev){ev.stopPropagation();})
},
hide = function (ev) {
if (ev.data.cal.data('colpick').onHide.apply(this, [ev.data.cal.get(0)]) != false) {
ev.data.cal.hide();
}
$('html').off('mousedown', hide);
},
getViewport = function () {
var m = document.compatMode == 'CSS1Compat';
return {
l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),
w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth)
};
},
//Fix the values if the user enters a negative or high value
fixHSB = function (hsb) {
return {
h: Math.min(360, Math.max(0, hsb.h)),
s: Math.min(100, Math.max(0, hsb.s)),
b: Math.min(100, Math.max(0, hsb.b))
};
},
fixRGB = function (rgb) {
return {
r: Math.min(255, Math.max(0, rgb.r)),
g: Math.min(255, Math.max(0, rgb.g)),
b: Math.min(255, Math.max(0, rgb.b))
};
},
fixHex = function (hex) {
var len = 6 - hex.length;
if (len > 0) {
var o = [];
for (var i=0; i<len; i++) {
o.push('0');
}
o.push(hex);
hex = o.join('');
}
return hex;
},
restoreOriginal = function () {
var cal = $(this).parent();
var col = cal.data('colpick').origColor;
cal.data('colpick').color = col;
fillRGBFields(col, cal.get(0));
fillHexFields(col, cal.get(0));
fillHSBFields(col, cal.get(0));
setSelector(col, cal.get(0));
setHue(col, cal.get(0));
setNewColor(col, cal.get(0));
};
return {
init: function (opt) {
opt = $.extend({}, defaults, opt||{});
//Set color
if (typeof opt.color == 'string') {
opt.color = hexToHsb(opt.color);
} else if (opt.color.r != undefined && opt.color.g != undefined && opt.color.b != undefined) {
opt.color = rgbToHsb(opt.color);
} else if (opt.color.h != undefined && opt.color.s != undefined && opt.color.b != undefined) {
opt.color = fixHSB(opt.color);
} else {
return this;
}
//For each selected DOM element
return this.each(function () {
//If the element does not have an ID
if (!$(this).data('colpickId')) {
var options = $.extend({}, opt);
options.origColor = opt.color;
//Generate and assign a random ID
var id = 'collorpicker_' + parseInt(Math.random() * 1000);
$(this).data('colpickId', id);
//Set the tpl's ID and get the HTML
var cal = $(tpl).attr('id', id);
//Add class according to layout
cal.addClass('colpick_'+options.layout+(options.submit?'':' colpick_'+options.layout+'_ns'));
//Add class if the color scheme is not default
if(options.colorScheme != 'light') {
cal.addClass('colpick_'+options.colorScheme);
}
//Setup submit button
cal.find('div.colpick_submit').html(options.submitText).click(clickSubmit);
//Setup input fields
options.fields = cal.find('input').change(change).blur(blur).focus(focus);
cal.find('div.colpick_field_arrs').mousedown(downIncrement).end().find('div.colpick_current_color').click(restoreOriginal);
//Setup hue selector
options.selector = cal.find('div.colpick_color').on('mousedown touchstart',downSelector);
options.selectorIndic = options.selector.find('div.colpick_selector_outer');
//Store parts of the plugin
options.el = this;
options.hue = cal.find('div.colpick_hue_arrs');
huebar = options.hue.parent();
//Paint the hue bar
var UA = navigator.userAgent.toLowerCase();
var isIE = navigator.appName === 'Microsoft Internet Explorer';
var IEver = isIE ? parseFloat( UA.match( /msie ([0-9]{1,}[\.0-9]{0,})/ )[1] ) : 0;
var ngIE = ( isIE && IEver < 10 );
var stops = ['#ff0000','#ff0080','#ff00ff','#8000ff','#0000ff','#0080ff','#00ffff','#00ff80','#00ff00','#80ff00','#ffff00','#ff8000','#ff0000'];
if(ngIE) {
var i, div;
for(i=0; i<=11; i++) {
div = $('<div></div>').attr('style','height:8.333333%; filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='+stops[i]+', endColorstr='+stops[i+1]+'); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='+stops[i]+', endColorstr='+stops[i+1]+')";');
huebar.append(div);
}
} else {
stopList = stops.join(',');
huebar.attr('style','background:-webkit-linear-gradient(top,'+stopList+'); background: -o-linear-gradient(top,'+stopList+'); background: -ms-linear-gradient(top,'+stopList+'); background:-moz-linear-gradient(top,'+stopList+'); -webkit-linear-gradient(top,'+stopList+'); background:linear-gradient(to bottom,'+stopList+'); ');
}
cal.find('div.colpick_hue').on('mousedown touchstart',downHue);
options.newColor = cal.find('div.colpick_new_color');
options.currentColor = cal.find('div.colpick_current_color');
//Store options and fill with default color
cal.data('colpick', options);
fillRGBFields(options.color, cal.get(0));
fillHSBFields(options.color, cal.get(0));
fillHexFields(options.color, cal.get(0));
setHue(options.color, cal.get(0));
setSelector(options.color, cal.get(0));
setCurrentColor(options.color, cal.get(0));
setNewColor(options.color, cal.get(0));
//Append to body if flat=false, else show in place
if (options.flat) {
cal.appendTo(this).show();
cal.css({
position: 'relative',
display: 'block'
});
} else {
cal.appendTo(document.body);
$(this).on(options.showEvent, show);
cal.css({
position:'absolute'
});
}
}
});
},
//Shows the picker
showPicker: function() {
return this.each( function () {
if ($(this).data('colpickId')) {
show.apply(this);
}
});
},
//Hides the picker
hidePicker: function() {
return this.each( function () {
if ($(this).data('colpickId')) {
$('#' + $(this).data('colpickId')).hide();
}
});
},
//Sets a color as new and current (default)
setColor: function(col, setCurrent) {
setCurrent = (typeof setCurrent === "undefined") ? 1 : setCurrent;
if (typeof col == 'string') {
col = hexToHsb(col);
} else if (col.r != undefined && col.g != undefined && col.b != undefined) {
col = rgbToHsb(col);
} else if (col.h != undefined && col.s != undefined && col.b != undefined) {
col = fixHSB(col);
} else {
return this;
}
return this.each(function(){
if ($(this).data('colpickId')) {
var cal = $('#' + $(this).data('colpickId'));
cal.data('colpick').color = col;
cal.data('colpick').origColor = col;
fillRGBFields(col, cal.get(0));
fillHSBFields(col, cal.get(0));
fillHexFields(col, cal.get(0));
setHue(col, cal.get(0));
setSelector(col, cal.get(0));
setNewColor(col, cal.get(0));
cal.data('colpick').onChange.apply(cal.parent(), [col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el, 1]);
if(setCurrent) {
setCurrentColor(col, cal.get(0));
}
}
});
}
};
}();
//Color space convertions
var hexToRgb = function (hex) {
var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);
return {r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF)};
};
var hexToHsb = function (hex) {
return rgbToHsb(hexToRgb(hex));
};
var rgbToHsb = function (rgb) {
var hsb = {h: 0, s: 0, b: 0};
var min = Math.min(rgb.r, rgb.g, rgb.b);
var max = Math.max(rgb.r, rgb.g, rgb.b);
var delta = max - min;
hsb.b = max;
hsb.s = max != 0 ? 255 * delta / max : 0;
if (hsb.s != 0) {
if (rgb.r == max) hsb.h = (rgb.g - rgb.b) / delta;
else if (rgb.g == max) hsb.h = 2 + (rgb.b - rgb.r) / delta;
else hsb.h = 4 + (rgb.r - rgb.g) / delta;
} else hsb.h = -1;
hsb.h *= 60;
if (hsb.h < 0) hsb.h += 360;
hsb.s *= 100/255;
hsb.b *= 100/255;
return hsb;
};
var hsbToRgb = function (hsb) {
var rgb = {};
var h = hsb.h;
var s = hsb.s*255/100;
var v = hsb.b*255/100;
if(s == 0) {
rgb.r = rgb.g = rgb.b = v;
} else {
var t1 = v;
var t2 = (255-s)*v/255;
var t3 = (t1-t2)*(h%60)/60;
if(h==360) h = 0;
if(h<60) {rgb.r=t1; rgb.b=t2; rgb.g=t2+t3}
else if(h<120) {rgb.g=t1; rgb.b=t2; rgb.r=t1-t3}
else if(h<180) {rgb.g=t1; rgb.r=t2; rgb.b=t2+t3}
else if(h<240) {rgb.b=t1; rgb.r=t2; rgb.g=t1-t3}
else if(h<300) {rgb.b=t1; rgb.g=t2; rgb.r=t2+t3}
else if(h<360) {rgb.r=t1; rgb.g=t2; rgb.b=t1-t3}
else {rgb.r=0; rgb.g=0; rgb.b=0}
}
return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)};
};
var rgbToHex = function (rgb) {
var hex = [
rgb.r.toString(16),
rgb.g.toString(16),
rgb.b.toString(16)
];
$.each(hex, function (nr, val) {
if (val.length == 1) {
hex[nr] = '0' + val;
}
});
return hex.join('');
};
var hsbToHex = function (hsb) {
return rgbToHex(hsbToRgb(hsb));
};
$.fn.extend({
colpick: colpick.init,
colpickHide: colpick.hidePicker,
colpickShow: colpick.showPicker,
colpickSetColor: colpick.setColor
});
$.extend({
colpick:{
rgbToHex: rgbToHex,
rgbToHsb: rgbToHsb,
hsbToHex: hsbToHex,
hsbToRgb: hsbToRgb,
hexToHsb: hexToHsb,
hexToRgb: hexToRgb
}
});
})(jQuery);

View file

@ -0,0 +1,420 @@
/*
colpick Color Picker / colpick.com
*/
/*Main container*/
.colpick {
position: absolute;
width: 346px;
height: 170px;
overflow: hidden;
display: none;
font-family: Arial, Helvetica, sans-serif;
background:#ebebeb;
border: 1px solid #bbb;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
/*Prevents selecting text when dragging the selectors*/
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
}
/*Color selection box with gradients*/
.colpick_color {
position: absolute;
left: 7px;
top: 7px;
width: 156px;
height: 156px;
overflow: hidden;
outline: 1px solid #aaa;
cursor: crosshair;
}
.colpick_color_overlay1 {
position: absolute;
left:0;
top:0;
width: 156px;
height: 156px;
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr='#ffffff', endColorstr='#00ffffff')"; /* IE8 */
background: -moz-linear-gradient(left, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(255,255,255,1)), color-stop(100%,rgba(255,255,255,0))); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(left, rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(left, rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(left, rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); /* IE10+ */
background: linear-gradient(to right, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%);
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr='#ffffff', endColorstr='#00ffffff'); /* IE6 & IE7 */
}
.colpick_color_overlay2 {
position: absolute;
left:0;
top:0;
width: 156px;
height: 156px;
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#00000000', endColorstr='#000000')"; /* IE8 */
background: -moz-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(0,0,0,0)), color-stop(100%,rgba(0,0,0,1))); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* IE10+ */
background: linear-gradient(to bottom, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00000000', endColorstr='#000000',GradientType=0 ); /* IE6-9 */
}
/*Circular color selector*/
.colpick_selector_outer {
background:none;
position: absolute;
width: 11px;
height: 11px;
margin: -6px 0 0 -6px;
border: 1px solid black;
border-radius: 50%;
}
.colpick_selector_inner{
position: absolute;
width: 9px;
height: 9px;
border: 1px solid white;
border-radius: 50%;
}
/*Vertical hue bar*/
.colpick_hue {
position: absolute;
top: 6px;
left: 175px;
width: 19px;
height: 156px;
border: 1px solid #aaa;
cursor: n-resize;
}
/*Hue bar sliding indicator*/
.colpick_hue_arrs {
position: absolute;
left: -8px;
width: 35px;
height: 7px;
margin: -7px 0 0 0;
}
.colpick_hue_larr {
position:absolute;
width: 0;
height: 0;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
border-left: 7px solid #858585;
}
.colpick_hue_rarr {
position:absolute;
right:0;
width: 0;
height: 0;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
border-right: 7px solid #858585;
}
/*New color box*/
.colpick_new_color {
position: absolute;
left: 207px;
top: 6px;
width: 60px;
height: 27px;
background: #f00;
border: 1px solid #8f8f8f;
}
/*Current color box*/
.colpick_current_color {
position: absolute;
left: 277px;
top: 6px;
width: 60px;
height: 27px;
background: #f00;
border: 1px solid #8f8f8f;
}
/*Input field containers*/
.colpick_field, .colpick_hex_field {
position: absolute;
height: 20px;
width: 60px;
overflow:hidden;
background:#f3f3f3;
color:#b8b8b8;
font-size:12px;
border:1px solid #bdbdbd;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
.colpick_rgb_r {
top: 40px;
left: 207px;
}
.colpick_rgb_g {
top: 67px;
left: 207px;
}
.colpick_rgb_b {
top: 94px;
left: 207px;
}
.colpick_hsb_h {
top: 40px;
left: 277px;
}
.colpick_hsb_s {
top: 67px;
left: 277px;
}
.colpick_hsb_b {
top: 94px;
left: 277px;
}
.colpick_hex_field {
width: 68px;
left: 207px;
top: 121px;
}
/*Text field container on focus*/
.colpick_focus {
border-color: #999;
}
/*Field label container*/
.colpick_field_letter {
position: absolute;
width: 12px;
height: 20px;
line-height: 20px;
padding-left: 4px;
background: #efefef;
border-right: 1px solid #bdbdbd;
font-weight: bold;
color:#777;
}
/*Text inputs*/
.colpick_field input, .colpick_hex_field input {
position: absolute;
right: 11px;
margin: 0;
padding: 0;
height: 20px;
line-height: 20px;
background: transparent;
border: none;
font-size: 12px;
font-family: Arial, Helvetica, sans-serif;
color: #555;
text-align: right;
outline: none;
}
.colpick_hex_field input {
right: 4px;
}
/*Field up/down arrows*/
.colpick_field_arrs {
position: absolute;
top: 0;
right: 0;
width: 9px;
height: 21px;
cursor: n-resize;
}
.colpick_field_uarr {
position: absolute;
top: 5px;
width: 0;
height: 0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-bottom: 4px solid #959595;
}
.colpick_field_darr {
position: absolute;
bottom:5px;
width: 0;
height: 0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid #959595;
}
/*Submit/Select button*/
.colpick_submit {
position: absolute;
left: 207px;
top: 149px;
width: 130px;
height: 22px;
line-height:22px;
background: #efefef;
text-align: center;
color: #555;
font-size: 12px;
font-weight:bold;
border: 1px solid #bdbdbd;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
.colpick_submit:hover {
background:#f3f3f3;
border-color:#999;
cursor: pointer;
}
/*full layout with no submit button*/
.colpick_full_ns .colpick_submit, .colpick_full_ns .colpick_current_color{
display:none;
}
.colpick_full_ns .colpick_new_color {
width: 130px;
height: 25px;
}
.colpick_full_ns .colpick_rgb_r, .colpick_full_ns .colpick_hsb_h {
top: 42px;
}
.colpick_full_ns .colpick_rgb_g, .colpick_full_ns .colpick_hsb_s {
top: 73px;
}
.colpick_full_ns .colpick_rgb_b, .colpick_full_ns .colpick_hsb_b {
top: 104px;
}
.colpick_full_ns .colpick_hex_field {
top: 135px;
}
/*rgbhex layout*/
.colpick_rgbhex .colpick_hsb_h, .colpick_rgbhex .colpick_hsb_s, .colpick_rgbhex .colpick_hsb_b {
display:none;
}
.colpick_rgbhex {
width:282px;
}
.colpick_rgbhex .colpick_field, .colpick_rgbhex .colpick_submit {
width:68px;
}
.colpick_rgbhex .colpick_new_color {
width:34px;
border-right:none;
}
.colpick_rgbhex .colpick_current_color {
width:34px;
left:240px;
border-left:none;
}
/*rgbhex layout, no submit button*/
.colpick_rgbhex_ns .colpick_submit, .colpick_rgbhex_ns .colpick_current_color{
display:none;
}
.colpick_rgbhex_ns .colpick_new_color{
width:68px;
border: 1px solid #8f8f8f;
}
.colpick_rgbhex_ns .colpick_rgb_r {
top: 42px;
}
.colpick_rgbhex_ns .colpick_rgb_g {
top: 73px;
}
.colpick_rgbhex_ns .colpick_rgb_b {
top: 104px;
}
.colpick_rgbhex_ns .colpick_hex_field {
top: 135px;
}
/*hex layout*/
.colpick_hex .colpick_hsb_h, .colpick_hex .colpick_hsb_s, .colpick_hex .colpick_hsb_b, .colpick_hex .colpick_rgb_r, .colpick_hex .colpick_rgb_g, .colpick_hex .colpick_rgb_b {
display:none;
}
.colpick_hex {
width:206px;
height:201px;
}
.colpick_hex .colpick_hex_field {
width:72px;
height:25px;
top:168px;
left:80px;
}
.colpick_hex .colpick_hex_field div, .colpick_hex .colpick_hex_field input {
height: 25px;
line-height: 25px;
}
.colpick_hex .colpick_new_color {
left:9px;
top:168px;
width:30px;
border-right:none;
}
.colpick_hex .colpick_current_color {
left:39px;
top:168px;
width:30px;
border-left:none;
}
.colpick_hex .colpick_submit {
left:164px;
top: 168px;
width:30px;
height:25px;
line-height: 25px;
}
/*hex layout, no submit button*/
.colpick_hex_ns .colpick_submit, .colpick_hex_ns .colpick_current_color {
display:none;
}
.colpick_hex_ns .colpick_hex_field {
width:80px;
}
.colpick_hex_ns .colpick_new_color{
width:60px;
border: 1px solid #8f8f8f;
}
/*Dark color scheme*/
.colpick_dark {
background: #161616;
border-color: #2a2a2a;
}
.colpick_dark .colpick_color {
outline-color: #333;
}
.colpick_dark .colpick_hue {
border-color: #555;
}
.colpick_dark .colpick_field, .colpick_dark .colpick_hex_field {
background: #101010;
border-color: #2d2d2d;
}
.colpick_dark .colpick_field_letter {
background: #131313;
border-color: #2d2d2d;
color: #696969;
}
.colpick_dark .colpick_field input, .colpick_dark .colpick_hex_field input {
color: #7a7a7a;
}
.colpick_dark .colpick_field_uarr {
border-bottom-color:#696969;
}
.colpick_dark .colpick_field_darr {
border-top-color:#696969;
}
.colpick_dark .colpick_focus {
border-color:#444;
}
.colpick_dark .colpick_submit {
background: #131313;
border-color:#2d2d2d;
color:#7a7a7a;
}
.colpick_dark .colpick_submit:hover {
background-color:#101010;
border-color:#444;
}

View file

@ -1,6 +1,9 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<link rel="stylesheet" type="text/css" href="css/colpick.css">
<script src="jquery-2.1.4.min.js"></script>
<script src="colpick.js"></script>
<script>
var PI = 3.14159265358979;
var DEGREES_TO_RADIANS = PI / 180.0;
@ -146,20 +149,34 @@
function createEmitColorPropertyUpdateFunction(property, elRed, elGreen, elBlue) {
return function() {
emitColorPropertyUpdate(property, elRed.value, elGreen.value, elBlue.value);
}
};
function emitColorPropertyUpdate(property, red, green, blue, group) {
var data = {
type: "update",
properties: {
}
};
data.properties[property] = {
red: elRed.value,
green: elGreen.value,
blue: elBlue.value,
};
if (group) {
data.properties[group] = { };
data.properties[group][property] = {
red: red,
green: green,
blue: blue,
};
} else {
data.properties[property] = {
red: red,
green: green,
blue: blue,
};
}
EventBridge.emitWebEvent(JSON.stringify(data));
}
};
function createEmitGroupColorPropertyUpdateFunction(group, property, elRed, elGreen, elBlue) {
return function() {
var data = {
@ -232,6 +249,7 @@
var elUserData = document.getElementById("property-user-data");
var elColorSection = document.getElementById("color-section");
var elColor = document.getElementById("property-color");
var elColorRed = document.getElementById("property-color-red");
var elColorGreen = document.getElementById("property-color-green");
var elColorBlue = document.getElementById("property-color-blue");
@ -239,6 +257,7 @@
var elLightSections = document.querySelectorAll(".light-section");
allSections.push(elLightSections);
var elLightSpotLight = document.getElementById("property-light-spot-light");
var elLightColor = document.getElementById("property-light-color");
var elLightColorRed = document.getElementById("property-light-color-red");
var elLightColorGreen = document.getElementById("property-light-color-green");
var elLightColorBlue = document.getElementById("property-light-color-blue");
@ -264,9 +283,11 @@
allSections.push(elTextSections);
var elTextText = document.getElementById("property-text-text");
var elTextLineHeight = document.getElementById("property-text-line-height");
var elTextTextColor = document.getElementById("property-text-text-color");
var elTextTextColorRed = document.getElementById("property-text-text-color-red");
var elTextTextColorGreen = document.getElementById("property-text-text-color-green");
var elTextTextColorBlue = document.getElementById("property-text-text-color-blue");
var elTextBackgroundColor = document.getElementById("property-text-background-color");
var elTextBackgroundColorRed = document.getElementById("property-text-background-color-red");
var elTextBackgroundColorGreen = document.getElementById("property-text-background-color-green");
var elTextBackgroundColorBlue = document.getElementById("property-text-background-color-blue");
@ -274,6 +295,7 @@
var elZoneSections = document.querySelectorAll(".zone-section");
allSections.push(elZoneSections);
var elZoneStageSunModelEnabled = document.getElementById("property-zone-stage-sun-model-enabled");
var elZoneKeyLightColor = document.getElementById("property-zone-key-light-color");
var elZoneKeyLightColorRed = document.getElementById("property-zone-key-light-color-red");
var elZoneKeyLightColorGreen = document.getElementById("property-zone-key-light-color-green");
var elZoneKeyLightColorBlue = document.getElementById("property-zone-key-light-color-blue");
@ -292,6 +314,7 @@
var elZoneBackgroundMode = document.getElementById("property-zone-background-mode");
var elZoneSkyboxColor = document.getElementById("property-zone-skybox-color");
var elZoneSkyboxColorRed = document.getElementById("property-zone-skybox-color-red");
var elZoneSkyboxColorGreen = document.getElementById("property-zone-skybox-color-green");
var elZoneSkyboxColorBlue = document.getElementById("property-zone-skybox-color-blue");
@ -300,6 +323,8 @@
var elZoneAtmosphereCenterX = document.getElementById("property-zone-atmosphere-center-x");
var elZoneAtmosphereCenterY = document.getElementById("property-zone-atmosphere-center-y");
var elZoneAtmosphereCenterZ = document.getElementById("property-zone-atmosphere-center-z");
var elCenterAtmosphereToZone = document.getElementById("center-atmosphere-in-zone");
var elZoneAtmosphereInnerRadius = document.getElementById("property-zone-atmosphere-inner-radius");
var elZoneAtmosphereOuterRadius = document.getElementById("property-zone-atmosphere-outer-radius");
var elZoneAtmosphereMieScattering = document.getElementById("property-zone-atmosphere-mie-scattering");
@ -423,6 +448,7 @@
elColorRed.value = properties.color.red;
elColorGreen.value = properties.color.green;
elColorBlue.value = properties.color.blue;
elColor.style.backgroundColor = "rgb(" + properties.color.red + "," + properties.color.green + "," + properties.color.blue + ")";
} else {
elColorSection.style.display = 'none';
}
@ -449,6 +475,7 @@
elTextText.value = properties.text;
elTextLineHeight.value = properties.lineHeight.toFixed(4);
elTextTextColor.style.backgroundColor = "rgb(" + properties.textColor.red + "," + properties.textColor.green + "," + properties.textColor.blue + ")";
elTextTextColorRed.value = properties.textColor.red;
elTextTextColorGreen.value = properties.textColor.green;
elTextTextColorBlue.value = properties.textColor.blue;
@ -462,6 +489,7 @@
elLightSpotLight.checked = properties.isSpotlight;
elLightColor.style.backgroundColor = "rgb(" + properties.color.red + "," + properties.color.green + "," + properties.color.blue + ")";
elLightColorRed.value = properties.color.red;
elLightColorGreen.value = properties.color.green;
elLightColorBlue.value = properties.color.blue;
@ -475,6 +503,7 @@
}
elZoneStageSunModelEnabled.checked = properties.stage.sunModelEnabled;
elZoneKeyLightColor.style.backgroundColor = "rgb(" + properties.keyLightColor.red + "," + properties.keyLightColor.green + "," + properties.keyLightColor.blue + ")";
elZoneKeyLightColorRed.value = properties.keyLightColor.red;
elZoneKeyLightColorGreen.value = properties.keyLightColor.green;
elZoneKeyLightColorBlue.value = properties.keyLightColor.blue;
@ -495,6 +524,7 @@
elZoneBackgroundMode.value = properties.backgroundMode;
elZoneSkyboxColor.style.backgroundColor = "rgb(" + properties.skybox.color.red + "," + properties.skybox.color.green + "," + properties.skybox.color.blue + ")";
elZoneSkyboxColorRed.value = properties.skybox.color.red;
elZoneSkyboxColorGreen.value = properties.skybox.color.green;
elZoneSkyboxColorBlue.value = properties.skybox.color.blue;
@ -591,6 +621,16 @@
elColorRed.addEventListener('change', colorChangeFunction);
elColorGreen.addEventListener('change', colorChangeFunction);
elColorBlue.addEventListener('change', colorChangeFunction);
$('#property-color').colpick({
colorScheme:'dark',
layout:'rgbhex',
color:'000000',
onSubmit: function(hsb, hex, rgb, el) {
$(el).css('background-color', '#'+hex);
$(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
}
})
elLightSpotLight.addEventListener('change', createEmitCheckedPropertyUpdateFunction('isSpotlight'));
@ -599,6 +639,16 @@
elLightColorRed.addEventListener('change', lightColorChangeFunction);
elLightColorGreen.addEventListener('change', lightColorChangeFunction);
elLightColorBlue.addEventListener('change', lightColorChangeFunction);
$('#property-light-color').colpick({
colorScheme:'dark',
layout:'rgbhex',
color:'000000',
onSubmit: function(hsb, hex, rgb, el) {
$(el).css('background-color', '#'+hex);
$(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
}
})
elLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('intensity'));
elLightExponent.addEventListener('change', createEmitNumberPropertyUpdateFunction('exponent'));
@ -622,14 +672,44 @@
elTextTextColorRed.addEventListener('change', textTextColorChangeFunction);
elTextTextColorGreen.addEventListener('change', textTextColorChangeFunction);
elTextTextColorBlue.addEventListener('change', textTextColorChangeFunction);
$('#property-text-text-color').colpick({
colorScheme:'dark',
layout:'rgbhex',
color:'000000',
onSubmit: function(hsb, hex, rgb, el) {
$(el).css('background-color', '#'+hex);
$(el).colpickHide();
emitColorPropertyUpdate('textColor', rgb.r, rgb.g, rgb.b);
}
});
var textBackgroundColorChangeFunction = createEmitColorPropertyUpdateFunction(
'backgroundColor', elTextBackgroundColorRed, elTextBackgroundColorGreen, elTextBackgroundColorBlue);
elTextBackgroundColorRed.addEventListener('change', textBackgroundColorChangeFunction);
elTextBackgroundColorGreen.addEventListener('change', textBackgroundColorChangeFunction);
elTextBackgroundColorBlue.addEventListener('change', textBackgroundColorChangeFunction);
$('#property-text-background-color').colpick({
colorScheme:'dark',
layout:'rgbhex',
color:'000000',
onSubmit: function(hsb, hex, rgb, el) {
$(el).css('background-color', '#'+hex);
$(el).colpickHide();
emitColorPropertyUpdate('backgroundColor', rgb.r, rgb.g, rgb.b);
}
});
elZoneStageSunModelEnabled.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('stage','sunModelEnabled'));
$('#property-zone-key-light-color').colpick({
colorScheme:'dark',
layout:'rgbhex',
color:'000000',
onSubmit: function(hsb, hex, rgb, el) {
$(el).css('background-color', '#'+hex);
$(el).colpickHide();
emitColorPropertyUpdate('keyLightColor', rgb.r, rgb.g, rgb.b);
}
});
var zoneKeyLightColorChangeFunction = createEmitColorPropertyUpdateFunction(
'keyLightColor', elZoneKeyLightColorRed, elZoneKeyLightColorGreen, elZoneKeyLightColorBlue);
elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction);
@ -657,6 +737,16 @@
elZoneSkyboxColorRed.addEventListener('change', zoneSkyboxColorChangeFunction);
elZoneSkyboxColorGreen.addEventListener('change', zoneSkyboxColorChangeFunction);
elZoneSkyboxColorBlue.addEventListener('change', zoneSkyboxColorChangeFunction);
$('#property-zone-skybox-color').colpick({
colorScheme:'dark',
layout:'rgbhex',
color:'000000',
onSubmit: function(hsb, hex, rgb, el) {
$(el).css('background-color', '#'+hex);
$(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox');
}
});
elZoneSkyboxURL.addEventListener('change', createEmitGroupTextPropertyUpdateFunction('skybox','url'));
@ -705,6 +795,12 @@
percentage: parseInt(elRescaleDimensionsPct.value),
}));
});
elCenterAtmosphereToZone.addEventListener("click", function() {
EventBridge.emitWebEvent(JSON.stringify({
type: "action",
action: "centerAtmosphereToZone",
}));
});
window.onblur = function() {
// Fake a change event
@ -739,6 +835,7 @@
};
}
}
</script>
</head>
<body class="properties" onload='loaded();'>
@ -915,6 +1012,7 @@
<div id="color-section" class="property">
<div class="label">Color</div>
<div class="value">
<div id="property-color" class='color-picker'></div>
<div class="input-area">R <input class="coord" type='number' id="property-color-red"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-color-blue"></input></div>
@ -1004,6 +1102,7 @@
<div class="text-section property">
<div class="label">Text Color</div>
<div class="value">
<div class='color-picker' id="property-text-text-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-text-text-color-red"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-text-text-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-text-text-color-blue"></input></div>
@ -1012,6 +1111,7 @@
<div class="text-section property">
<div class="label">Background Color</div>
<div class="value">
<div class='color-picker' id="property-text-background-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-text-background-color-red"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-text-background-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-text-background-color-blue"></input></div>
@ -1027,6 +1127,7 @@
<div class="light-section property">
<div class="label">Color</div>
<div class="value">
<div class='color-picker' id="property-light-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-light-color-red"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-light-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-light-color-blue"></input></div>
@ -1061,6 +1162,7 @@
<div class="zone-section property">
<div class="label">Key Light Color</div>
<div class="value">
<div class='color-picker' id="property-zone-key-light-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-zone-key-light-color-red" min="0" max="255" step="1"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-zone-key-light-color-green" min="0" max="255" step="1"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-zone-key-light-color-blue" min="0" max="255" step="1"></input></div>
@ -1139,6 +1241,7 @@
<div class="zone-section skybox-section property">
<div class="label">Skybox Color</div>
<div class="value">
<div class='color-picker' id="property-zone-skybox-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-zone-skybox-color-red"></input></div>
<div class="input-area">G <input class="coord" type='number' id="property-zone-skybox-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-zone-skybox-color-blue"></input></div>
@ -1156,6 +1259,9 @@
<div class="input-area">X <br><input class="coord" type='number' id="property-zone-atmosphere-center-x"></input></div>
<div class="input-area">Y <br><input class="coord" type='number' id="property-zone-atmosphere-center-y"></input></div>
<div class="input-area">Z <br><input class="coord" type='number' id="property-zone-atmosphere-center-z"></input></div>
<div>
<input type="button" id="center-atmosphere-in-zone" value="Center to Zone">
</div>
</div>
</div>
<div class="zone-section atmosphere-section property">

4
examples/html/jquery-2.1.4.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -313,3 +313,10 @@ input[type="number"]::-webkit-inner-spin-button:active{
input#property-name {
width: 100%;
}
.color-picker {
width: 50px;
height: 10px;
margin: 5px;
border: 1px solid white;
}

View file

@ -1,147 +0,0 @@
ZoneOverlayManager = function(isEntityFunc, entityAddedFunc, entityRemovedFunc, entityMovedFunc) {
var self = this;
var visible = false;
// List of all created overlays
var allOverlays = [];
// List of overlays not currently being used
var unusedOverlays = [];
// Map from EntityItemID.id to overlay id
var entityOverlays = {};
// Map from EntityItemID.id to EntityItemID object
var entityIDs = {};
this.updatePositions = function(ids) {
for (var id in entityIDs) {
var entityID = entityIDs[id];
var properties = Entities.getEntityProperties(entityID);
Overlays.editOverlay(entityOverlays[entityID.id].solid, {
position: properties.position,
rotation: properties.rotation,
dimensions: properties.dimensions,
});
Overlays.editOverlay(entityOverlays[entityID.id].outline, {
position: properties.position,
rotation: properties.rotation,
dimensions: properties.dimensions,
});
}
};
this.setVisible = function(isVisible) {
if (visible != isVisible) {
visible = isVisible;
Entities.setDrawZoneBoundaries(visible);
for (var id in entityOverlays) {
Overlays.editOverlay(entityOverlays[id].solid, { visible: visible });
Overlays.editOverlay(entityOverlays[id].outline, { visible: visible });
}
}
};
// Allocate or get an unused overlay
function getOverlay() {
if (unusedOverlays.length == 0) {
var overlay = Overlays.addOverlay("cube", {
});
allOverlays.push(overlay);
} else {
var overlay = unusedOverlays.pop();
};
return overlay;
}
function releaseOverlay(overlay) {
unusedOverlays.push(overlay);
Overlays.editOverlay(overlay, { visible: false });
}
function addEntity(entityID) {
var properties = Entities.getEntityProperties(entityID);
if (properties.type == "Zone" && !(entityID.id in entityOverlays)) {
var overlaySolid = getOverlay();
var overlayOutline = getOverlay();
entityOverlays[entityID.id] = {
solid: overlaySolid,
outline: overlayOutline,
}
entityIDs[entityID.id] = entityID;
var color = {
red: Math.round(Math.random() * 255),
green: Math.round(Math.random() * 255),
blue: Math.round(Math.random() * 255)
};
Overlays.editOverlay(overlaySolid, {
position: properties.position,
rotation: properties.rotation,
dimensions: properties.dimensions,
visible: visible,
solid: true,
alpha: 0.1,
color: color,
ignoreRayIntersection: true,
});
Overlays.editOverlay(overlayOutline, {
position: properties.position,
rotation: properties.rotation,
dimensions: properties.dimensions,
visible: visible,
solid: false,
dashed: false,
lineWidth: 2.0,
alpha: 1.0,
color: color,
ignoreRayIntersection: true,
});
}
}
function deleteEntity(entityID) {
if (entityID.id in entityOverlays) {
releaseOverlay(entityOverlays[entityID.id].outline);
releaseOverlay(entityOverlays[entityID.id].solid);
delete entityIDs[entityID.id];
delete entityOverlays[entityID.id];
}
}
function changeEntityID(oldEntityID, newEntityID) {
entityOverlays[newEntityID.id] = entityOverlays[oldEntityID.id];
entityIDs[newEntityID.id] = newEntityID;
delete entityOverlays[oldEntityID.id];
delete entityIDs[oldEntityID.id];
}
function clearEntities() {
for (var id in entityOverlays) {
releaseOverlay(entityOverlays[id].outline);
releaseOverlay(entityOverlays[id].solid);
}
entityOverlays = {};
entityIDs = {};
}
Entities.addingEntity.connect(addEntity);
Entities.changingEntityID.connect(changeEntityID);
Entities.deletingEntity.connect(deleteEntity);
Entities.clearingEntities.connect(clearEntities);
// Add existing entities
var ids = Entities.findEntities(MyAvatar.position, 64000);
for (var i = 0; i < ids.length; i++) {
addEntity(ids[i]);
}
Script.scriptEnding.connect(function() {
for (var i = 0; i < allOverlays.length; i++) {
Overlays.deleteOverlay(allOverlays[i]);
}
});
};

View file

@ -3223,18 +3223,40 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
// compute starfield alpha based on distance from atmosphere
float alpha = 1.0f;
bool hasStars = true;
if (Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
// TODO: handle this correctly for zones
const EnvironmentData& closestData = _environment.getClosestData(theCamera.getPosition());
if (closestData.getHasStars()) {
const float APPROXIMATE_DISTANCE_FROM_HORIZON = 0.1f;
const float DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON = 0.2f;
glm::vec3 sunDirection = (getAvatarPosition() - closestData.getSunLocation())
/ closestData.getAtmosphereOuterRadius();
float height = glm::distance(theCamera.getPosition(), closestData.getAtmosphereCenter());
if (height < closestData.getAtmosphereInnerRadius()) {
// If we're inside the atmosphere, then determine if our keyLight is below the horizon
alpha = 0.0f;
if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) {
float directionY = glm::clamp(sunDirection.y,
-APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON)
+ APPROXIMATE_DISTANCE_FROM_HORIZON;
alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON);
}
} else if (height < closestData.getAtmosphereOuterRadius()) {
alpha = (height - closestData.getAtmosphereInnerRadius()) /
(closestData.getAtmosphereOuterRadius() - closestData.getAtmosphereInnerRadius());
if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) {
float directionY = glm::clamp(sunDirection.y,
-APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON)
+ APPROXIMATE_DISTANCE_FROM_HORIZON;
alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON);
}
}
} else {
hasStars = false;

View file

@ -183,8 +183,8 @@ DdeFaceTracker::DdeFaceTracker(const QHostAddress& host, quint16 serverPort, qui
_filteredEyeBlinks(),
_lastEyeCoefficients(),
_isCalibrating(false),
_calibrationValues(),
_calibrationCount(0),
_calibrationValues(),
_calibrationBillboard(NULL),
_calibrationBillboardID(0),
_calibrationMessage(QString())

View file

@ -14,6 +14,10 @@
ClipboardScriptingInterface::ClipboardScriptingInterface() {
}
float ClipboardScriptingInterface::getClipboardContentsLargestDimension() {
return Application::getInstance()->getEntityClipboard()->getContentsLargestDimension();
}
bool ClipboardScriptingInterface::exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs) {
return Application::getInstance()->exportEntities(filename, entityIDs);
}

View file

@ -22,6 +22,7 @@ signals:
void readyToImport();
public slots:
float getClipboardContentsLargestDimension(); /// returns the largest dimension of everything on the clipboard
bool importEntities(const QString& filename);
bool exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs);
bool exportEntities(const QString& filename, float x, float y, float z, float s);

View file

@ -1226,19 +1226,17 @@ glm::vec2 ApplicationOverlay::sphericalToOverlay(const glm::vec2& sphericalPos)
result /= _textureFov;
result.x /= _textureAspectRatio;
result += 0.5f;
result.x = (-sphericalPos.x / (_textureFov * _textureAspectRatio) + 0.5f);
result.y = (sphericalPos.y / _textureFov + 0.5f);
result *= qApp->getCanvasSize();
return result;
}
glm::vec2 ApplicationOverlay::overlayToSpherical(const glm::vec2& overlayPos) const {
glm::vec2 result = overlayPos;
result.x *= -1.0;
result /= qApp->getCanvasSize();
result -= 0.5f;
result *= _textureFov;
result.x *= _textureAspectRatio;
result.x *= -1.0f;
return result;
}

View file

@ -16,6 +16,7 @@
#include <DeferredLightingEffect.h>
#include <PerfStat.h>
#include <GeometryCache.h>
#include "EntitiesRendererLogging.h"
#include "RenderableParticleEffectEntityItem.h"
@ -29,62 +30,158 @@ RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const Ent
}
void RenderableParticleEffectEntityItem::render(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableParticleEffectEntityItem::render");
assert(getType() == EntityTypes::ParticleEffect);
float pa_rad = getParticleRadius();
PerformanceTimer perfTimer("RenderableParticleEffectEntityItem::render");
const float MAX_COLOR = 255.0f;
glm::vec4 paColor(getColor()[RED_INDEX] / MAX_COLOR, getColor()[GREEN_INDEX] / MAX_COLOR,
getColor()[BLUE_INDEX] / MAX_COLOR, getLocalRenderAlpha());
// Right now we're just iterating over particles and rendering as a cross of four quads.
// This is pretty dumb, it was quick enough to code up. Really, there should be many
// rendering modes, including the all-important textured billboards.
QVector<glm::vec3>* pointVec = new QVector<glm::vec3>(_paCount * VERTS_PER_PARTICLE);
quint32 paIter = _paHead;
while (_paLife[paIter] > 0.0f) {
int j = paIter * XYZ_STRIDE;
pointVec->append(glm::vec3(_paPosition[j] - pa_rad, _paPosition[j + 1] + pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] + pa_rad, _paPosition[j + 1] + pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] + pa_rad, _paPosition[j + 1] - pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] - pa_rad, _paPosition[j + 1] - pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] + pa_rad, _paPosition[j + 1] + pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] - pa_rad, _paPosition[j + 1] + pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] - pa_rad, _paPosition[j + 1] - pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] + pa_rad, _paPosition[j + 1] - pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] + pa_rad, _paPosition[j + 2] - pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] + pa_rad, _paPosition[j + 2] + pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] - pa_rad, _paPosition[j + 2] + pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] - pa_rad, _paPosition[j + 2] - pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] + pa_rad, _paPosition[j + 2] + pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] + pa_rad, _paPosition[j + 2] - pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] - pa_rad, _paPosition[j + 2] - pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] - pa_rad, _paPosition[j + 2] + pa_rad));
paIter = (paIter + 1) % _maxParticles;
if (_texturesChangedFlag) {
if (_textures.isEmpty()) {
_texture.clear();
} else {
// for now use the textures string directly.
// Eventually we'll want multiple textures in a map or array.
_texture = DependencyManager::get<TextureCache>()->getTexture(_textures);
}
_texturesChangedFlag = false;
}
DependencyManager::get<GeometryCache>()->updateVertices(_cacheID, *pointVec, paColor);
if (!_texture) {
renderUntexturedQuads(args);
} else if (_texture && !_texture->isLoaded()) {
renderUntexturedQuads(args);
} else {
renderTexturedQuads(args);
}
};
void RenderableParticleEffectEntityItem::renderUntexturedQuads(RenderArgs* args) {
float particleRadius = getParticleRadius();
const float MAX_COLOR = 255.0f;
glm::vec4 particleColor(getColor()[RED_INDEX] / MAX_COLOR,
getColor()[GREEN_INDEX] / MAX_COLOR,
getColor()[BLUE_INDEX] / MAX_COLOR,
getLocalRenderAlpha());
glm::vec3 upOffset = args->_viewFrustum->getUp() * particleRadius;
glm::vec3 rightOffset = args->_viewFrustum->getRight() * particleRadius;
QVector<glm::vec3> vertices(getLivingParticleCount() * VERTS_PER_PARTICLE);
quint32 count = 0;
for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) {
glm::vec3 pos = _particlePositions[i];
// generate corners of quad, aligned to face the camera
vertices.append(pos - rightOffset + upOffset);
vertices.append(pos + rightOffset + upOffset);
vertices.append(pos + rightOffset - upOffset);
vertices.append(pos - rightOffset - upOffset);
count++;
}
// just double checking, cause if this invarient is false, we might have memory corruption bugs.
assert(count == getLivingParticleCount());
// update geometry cache with all the verts in model coordinates.
DependencyManager::get<GeometryCache>()->updateVertices(_cacheID, vertices, particleColor);
glPushMatrix();
glm::vec3 position = getPosition();
glTranslatef(position.x, position.y, position.z);
glm::quat rotation = getRotation();
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glPushMatrix();
glm::vec3 positionToCenter = getCenter() - position;
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
DependencyManager::get<GeometryCache>()->renderVertices(gpu::QUADS, _cacheID);
glPopMatrix();
glPopMatrix();
}
static glm::vec3 zSortAxis;
static bool zSort(const glm::vec3& rhs, const glm::vec3& lhs) {
return glm::dot(rhs, ::zSortAxis) > glm::dot(lhs, ::zSortAxis);
}
void RenderableParticleEffectEntityItem::renderTexturedQuads(RenderArgs* args) {
float particleRadius = getParticleRadius();
const float MAX_COLOR = 255.0f;
glm::vec4 particleColor(getColor()[RED_INDEX] / MAX_COLOR,
getColor()[GREEN_INDEX] / MAX_COLOR,
getColor()[BLUE_INDEX] / MAX_COLOR,
getLocalRenderAlpha());
QVector<glm::vec3> positions(getLivingParticleCount());
quint32 count = 0;
for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) {
positions.append(_particlePositions[i]);
count++;
}
// just double checking, cause if this invarient is false, we might have memory corruption bugs.
assert(count == getLivingParticleCount());
// sort particles back to front
::zSortAxis = args->_viewFrustum->getDirection();
qSort(positions.begin(), positions.end(), zSort);
QVector<glm::vec3> vertices(getLivingParticleCount() * VERTS_PER_PARTICLE);
QVector<glm::vec2> textureCoords(getLivingParticleCount() * VERTS_PER_PARTICLE);
glm::vec3 upOffset = args->_viewFrustum->getUp() * particleRadius;
glm::vec3 rightOffset = args->_viewFrustum->getRight() * particleRadius;
for (int i = 0; i < positions.size(); i++) {
glm::vec3 pos = positions[i];
// generate corners of quad aligned to face the camera.
vertices.append(pos - rightOffset + upOffset);
vertices.append(pos + rightOffset + upOffset);
vertices.append(pos + rightOffset - upOffset);
vertices.append(pos - rightOffset - upOffset);
textureCoords.append(glm::vec2(0, 1));
textureCoords.append(glm::vec2(1, 1));
textureCoords.append(glm::vec2(1, 0));
textureCoords.append(glm::vec2(0, 0));
}
// update geometry cache with all the verts in model coordinates.
DependencyManager::get<GeometryCache>()->updateVertices(_cacheID, vertices, textureCoords, particleColor);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, _texture->getID());
glPushMatrix();
glm::vec3 position = getPosition();
glTranslatef(position.x, position.y, position.z);
glm::quat rotation = getRotation();
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glPushMatrix();
glm::vec3 positionToCenter = getCenter() - position;
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
DependencyManager::get<GeometryCache>()->renderVertices(gpu::QUADS, _cacheID);
glPopMatrix();
glPopMatrix();
delete pointVec;
};
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}

View file

@ -12,6 +12,7 @@
#define hifi_RenderableParticleEffectEntityItem_h
#include <ParticleEffectEntityItem.h>
#include <TextureCache.h>
class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem {
public:
@ -19,9 +20,15 @@ public:
RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual void render(RenderArgs* args);
void renderUntexturedQuads(RenderArgs* args);
void renderTexturedQuads(RenderArgs* args);
protected:
int _cacheID;
const int VERTS_PER_PARTICLE = 16;
const int VERTS_PER_PARTICLE = 4;
NetworkTexturePointer _texture;
};

View file

@ -1068,6 +1068,27 @@ void EntityTree::debugDumpMap() {
qCDebug(entities) << "-----------------------------------------------------";
}
class ContentsDimensionOperator : public RecurseOctreeOperator {
public:
virtual bool preRecursion(OctreeElement* element);
virtual bool postRecursion(OctreeElement* element) { return true; }
float getLargestDimension() const { return _contentExtents.largestDimension(); }
private:
Extents _contentExtents;
};
bool ContentsDimensionOperator::preRecursion(OctreeElement* element) {
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
entityTreeElement->expandExtentsToContents(_contentExtents);
return true;
}
float EntityTree::getContentsLargestDimension() {
ContentsDimensionOperator theOperator;
recurseTreeWithOperator(&theOperator);
return theOperator.getLargestDimension();
}
class DebugOperator : public RecurseOctreeOperator {
public:
virtual bool preRecursion(OctreeElement* element);

View file

@ -166,6 +166,8 @@ public:
bool writeToMap(QVariantMap& entityDescription, OctreeElement* element, bool skipDefaultValues);
bool readFromMap(QVariantMap& entityDescription);
float getContentsLargestDimension();
signals:
void deletingEntity(const EntityItemID& entityID);

View file

@ -819,6 +819,16 @@ bool EntityTreeElement::pruneChildren() {
return somethingPruned;
}
void EntityTreeElement::expandExtentsToContents(Extents& extents) {
if (_entityItems->size()) {
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
extents.add(entity->getAABox());
}
}
}
void EntityTreeElement::debugDump() {
qCDebug(entities) << "EntityTreeElement...";

View file

@ -196,6 +196,8 @@ public:
bool pruneChildren();
void expandExtentsToContents(Extents& extents);
protected:
virtual void init(unsigned char * octalCode);
EntityTree* _myTree;

View file

@ -18,12 +18,8 @@
// - Add controls for spread (which is currently hard-coded) and varying emission strength (not currently implemented).
// - Add drag.
// - Add some kind of support for collisions.
// - For simplicity, I'm currently just rendering each particle as a cross of four axis-aligned quads. Really, we'd
// want multiple render modes, including (the most important) textured billboards (always facing camera). Also, these
// should support animated textures.
// - There's no synchronization of the simulation across clients at all. In fact, it's using rand() under the hood, so
// there's no gaurantee that different clients will see simulations that look anything like the other.
// - MORE?
//
// Created by Jason Rickwald on 3/2/15.
//
@ -45,6 +41,7 @@
#include "EntitiesLogging.h"
#include "ParticleEffectEntityItem.h"
const xColor ParticleEffectEntityItem::DEFAULT_COLOR = { 255, 255, 255 };
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;
@ -55,6 +52,7 @@ const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_DIRECTION(0.0f, 1.0f, 0.0
const float ParticleEffectEntityItem::DEFAULT_EMIT_STRENGTH = 25.0f;
const float ParticleEffectEntityItem::DEFAULT_LOCAL_GRAVITY = -9.8f;
const float ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS = 0.025f;
const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = "";
EntityItem* ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
@ -63,40 +61,40 @@ EntityItem* ParticleEffectEntityItem::factory(const EntityItemID& entityID, cons
// our non-pure virtual subclass for now...
ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties) {
EntityItem(entityItemID, properties),
_maxParticles(DEFAULT_MAX_PARTICLES),
_lifespan(DEFAULT_LIFESPAN),
_emitRate(DEFAULT_EMIT_RATE),
_emitDirection(DEFAULT_EMIT_DIRECTION),
_emitStrength(DEFAULT_EMIT_STRENGTH),
_localGravity(DEFAULT_LOCAL_GRAVITY),
_particleRadius(DEFAULT_PARTICLE_RADIUS),
_lastAnimated(usecTimestampNow()),
_animationLoop(),
_animationSettings(),
_textures(DEFAULT_TEXTURES),
_texturesChangedFlag(false),
_shapeType(SHAPE_TYPE_NONE),
_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)),
_timeUntilNextEmit(0.0f),
_particleHeadIndex(0),
_particleTailIndex(0),
_particleMaxBound(glm::vec3(1.0f, 1.0f, 1.0f)),
_particleMinBound(glm::vec3(-1.0f, -1.0f, -1.0f)) {
_type = EntityTypes::ParticleEffect;
_maxParticles = DEFAULT_MAX_PARTICLES;
_lifespan = DEFAULT_LIFESPAN;
_emitRate = DEFAULT_EMIT_RATE;
_emitDirection = DEFAULT_EMIT_DIRECTION;
_emitStrength = DEFAULT_EMIT_STRENGTH;
_localGravity = DEFAULT_LOCAL_GRAVITY;
_particleRadius = DEFAULT_PARTICLE_RADIUS;
setColor(DEFAULT_COLOR);
setProperties(properties);
// this is a pretty dumb thing to do, and it should probably be changed to use a more dynamic
// data structure in the future. I'm just trying to get some code out the door for now (and it's
// at least time efficient (though not space efficient).
// Also, this being a real-time application, it's doubtful we'll ever have millions of particles
// to keep track of, so this really isn't all that bad.
_paLife = new float[_maxParticles];
_paPosition = new float[_maxParticles * XYZ_STRIDE]; // x,y,z
_paVelocity = new float[_maxParticles * XYZ_STRIDE]; // x,y,z
_paXmax = _paYmax = _paZmax = 1.0f;
_paXmin = _paYmin = _paZmin = -1.0f;
_randSeed = (unsigned int) glm::abs(_lifespan + _emitRate + _localGravity + getPosition().x + getPosition().y + getPosition().z);
resetSimulation();
_lastAnimated = usecTimestampNow();
}
ParticleEffectEntityItem::~ParticleEffectEntityItem() {
delete [] _paLife;
delete [] _paPosition;
delete [] _paVelocity;
}
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(animationIsPlaying, getAnimationIsPlaying);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex);
@ -111,6 +109,7 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const {
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitStrength, getEmitStrength);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(localGravity, getLocalGravity);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(particleRadius, getParticleRadius);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
return properties;
}
@ -132,6 +131,7 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitStrength, setEmitStrength);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(localGravity, setLocalGravity);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(particleRadius, setParticleRadius);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures);
if (somethingChanged) {
bool wantDebug = false;
@ -147,8 +147,8 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
}
int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
int bytesRead = 0;
const unsigned char* dataAt = data;
@ -186,6 +186,7 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
READ_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, float, _emitStrength);
READ_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, float, _localGravity);
READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, _particleRadius);
READ_ENTITY_PROPERTY_STRING(PROP_TEXTURES, setTextures);
return bytesRead;
}
@ -194,7 +195,7 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
requestedProperties += PROP_COLOR;
requestedProperties += PROP_ANIMATION_FPS;
requestedProperties += PROP_ANIMATION_FRAME_INDEX;
@ -208,17 +209,18 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea
requestedProperties += PROP_EMIT_STRENGTH;
requestedProperties += PROP_LOCAL_GRAVITY;
requestedProperties += PROP_PARTICLE_RADIUS;
requestedProperties += PROP_TEXTURES;
return requestedProperties;
}
void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
@ -234,11 +236,12 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData,
APPEND_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, appendValue, getEmitStrength());
APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, appendValue, getLocalGravity());
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, appendValue, getParticleRadius());
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, appendValue, getTextures());
}
bool ParticleEffectEntityItem::isAnimatingSomething() const {
return getAnimationIsPlaying() &&
getAnimationFPS() != 0.0f;
// keep animating if there are particles still alive.
return (getAnimationIsPlaying() || getLivingParticleCount() > 0) && getAnimationFPS() != 0.0f;
}
bool ParticleEffectEntityItem::needsToCallUpdate() const {
@ -246,33 +249,25 @@ bool ParticleEffectEntityItem::needsToCallUpdate() const {
}
void ParticleEffectEntityItem::update(const quint64& now) {
float deltaTime = (float)(now - _lastAnimated) / (float)USECS_PER_SECOND;
_lastAnimated = now;
// only advance the frame index if we're playing
if (getAnimationIsPlaying()) {
float deltaTime = (float)(now - _lastAnimated) / (float)USECS_PER_SECOND;
_lastAnimated = now;
float lastFrame = _animationLoop.getFrameIndex();
_animationLoop.simulate(deltaTime);
float curFrame = _animationLoop.getFrameIndex();
if (curFrame > lastFrame) {
stepSimulation(deltaTime);
}
else if (curFrame < lastFrame) {
// we looped around, so restart the sim and only sim up to the point
// since the beginning of the frame range.
resetSimulation();
stepSimulation((curFrame - _animationLoop.getFirstFrame()) / _animationLoop.getFPS());
}
}
else {
_lastAnimated = now;
}
// update the dimensions
glm::vec3 dims;
dims.x = glm::max(glm::abs(_paXmin), glm::abs(_paXmax)) * 2.0f;
dims.y = glm::max(glm::abs(_paYmin), glm::abs(_paYmax)) * 2.0f;
dims.z = glm::max(glm::abs(_paZmin), glm::abs(_paZmax)) * 2.0f;
setDimensions(dims);
if (isAnimatingSomething()) {
stepSimulation(deltaTime);
// update the dimensions
glm::vec3 dims;
dims.x = glm::max(glm::abs(_particleMinBound.x), glm::abs(_particleMaxBound.x)) * 2.0f;
dims.y = glm::max(glm::abs(_particleMinBound.y), glm::abs(_particleMaxBound.y)) * 2.0f;
dims.z = glm::max(glm::abs(_particleMinBound.z), glm::abs(_particleMaxBound.z)) * 2.0f;
setDimensions(dims);
}
EntityItem::update(now); // let our base class handle it's updates...
}
@ -418,96 +413,103 @@ QString ParticleEffectEntityItem::getAnimationSettings() const {
return jsonByteString;
}
void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
_paXmin = _paYmin = _paZmin = -1.0f;
_paXmax = _paYmax = _paZmax = 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);
_particleMinBound.z = glm::min(_particleMinBound.z, point.z);
_particleMaxBound.x = glm::max(_particleMaxBound.x, point.x);
_particleMaxBound.y = glm::max(_particleMaxBound.y, point.y);
_particleMaxBound.z = glm::max(_particleMaxBound.z, point.z);
}
// update particles
quint32 updateIter = _paHead;
while (_paLife[updateIter] > 0.0f) {
_paLife[updateIter] -= deltaTime;
if (_paLife[updateIter] <= 0.0f) {
_paLife[updateIter] = -1.0f;
_paHead = (_paHead + 1) % _maxParticles;
_paCount--;
void ParticleEffectEntityItem::integrateParticle(quint32 index, float deltaTime) {
glm::vec3 atSquared(0.0f, 0.5f * _localGravity * deltaTime * deltaTime, 0.0f);
glm::vec3 at(0.0f, _localGravity * deltaTime, 0.0f);
_particlePositions[index] += _particleVelocities[index] * deltaTime + atSquared;
_particleVelocities[index] += at;
}
void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
_particleMinBound = glm::vec3(-1.0f, -1.0f, -1.0f);
_particleMaxBound = glm::vec3(1.0f, 1.0f, 1.0f);
// update particles between head and tail
for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) {
_particleLifetimes[i] -= deltaTime;
// if particle has died.
if (_particleLifetimes[i] <= 0.0f) {
// move head forward
_particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles;
}
else {
// DUMB FORWARD EULER just to get it done
int j = updateIter * XYZ_STRIDE;
_paPosition[j] += _paVelocity[j] * deltaTime;
_paPosition[j+1] += _paVelocity[j+1] * deltaTime;
_paPosition[j+2] += _paVelocity[j+2] * deltaTime;
_paXmin = glm::min(_paXmin, _paPosition[j]);
_paYmin = glm::min(_paYmin, _paPosition[j+1]);
_paZmin = glm::min(_paZmin, _paPosition[j+2]);
_paXmax = glm::max(_paXmax, _paPosition[j]);
_paYmax = glm::max(_paYmax, _paPosition[j + 1]);
_paZmax = glm::max(_paZmax, _paPosition[j + 2]);
// massless particles
_paVelocity[j + 1] += deltaTime * _localGravity;
integrateParticle(i, deltaTime);
extendBounds(_particlePositions[i]);
}
updateIter = (updateIter + 1) % _maxParticles;
}
// emit new particles
quint32 emitIdx = updateIter;
_partialEmit += ((float)_emitRate) * deltaTime;
quint32 birthed = (quint32)_partialEmit;
_partialEmit -= (float)birthed;
glm::vec3 randOffset;
// emit new particles, but only if animaiton is playing
if (getAnimationIsPlaying()) {
for (quint32 i = 0; i < birthed; i++) {
if (_paLife[emitIdx] < 0.0f) {
int j = emitIdx * XYZ_STRIDE;
_paLife[emitIdx] = _lifespan;
randOffset.x = (((double)rand() / (double)RAND_MAX) - 0.5) * 0.25 * _emitStrength;
randOffset.y = (((double)rand() / (double)RAND_MAX) - 0.5) * 0.25 * _emitStrength;
randOffset.z = (((double)rand() / (double)RAND_MAX) - 0.5) * 0.25 * _emitStrength;
_paVelocity[j] = (_emitDirection.x * _emitStrength) + randOffset.x;
_paVelocity[j + 1] = (_emitDirection.y * _emitStrength) + randOffset.y;
_paVelocity[j + 2] = (_emitDirection.z * _emitStrength) + randOffset.z;
float timeLeftInFrame = deltaTime;
while (_timeUntilNextEmit < timeLeftInFrame) {
// DUMB FORWARD EULER just to get it done
_paPosition[j] += _paVelocity[j] * deltaTime;
_paPosition[j + 1] += _paVelocity[j + 1] * deltaTime;
_paPosition[j + 2] += _paVelocity[j + 2] * deltaTime;
timeLeftInFrame -= _timeUntilNextEmit;
_timeUntilNextEmit = 1.0f / _emitRate;
_paXmin = glm::min(_paXmin, _paPosition[j]);
_paYmin = glm::min(_paYmin, _paPosition[j + 1]);
_paZmin = glm::min(_paZmin, _paPosition[j + 2]);
_paXmax = glm::max(_paXmax, _paPosition[j]);
_paYmax = glm::max(_paYmax, _paPosition[j + 1]);
_paZmax = glm::max(_paZmax, _paPosition[j + 2]);
// emit a new particle at tail index.
quint32 i = _particleTailIndex;
_particleLifetimes[i] = _lifespan;
// massless particles
// and simple gravity down
_paVelocity[j + 1] += deltaTime * _localGravity;
// jitter the _emitDirection by a random offset
glm::vec3 randOffset;
randOffset.x = (randFloat() - 0.5f) * 0.25f * _emitStrength;
randOffset.y = (randFloat() - 0.5f) * 0.25f * _emitStrength;
randOffset.z = (randFloat() - 0.5f) * 0.25f * _emitStrength;
emitIdx = (emitIdx + 1) % _maxParticles;
_paCount++;
// set initial conditions
_particlePositions[i] = glm::vec3(0.0f, 0.0f, 0.0f);
_particleVelocities[i] = _emitDirection * _emitStrength + randOffset;
integrateParticle(i, timeLeftInFrame);
extendBounds(_particlePositions[i]);
_particleTailIndex = (_particleTailIndex + 1) % _maxParticles;
// overflow! move head forward by one.
// because the case of head == tail indicates an empty array, not a full one.
// This can drop an existing older particle, but this is by design, newer particles are a higher priority.
if (_particleTailIndex == _particleHeadIndex) {
_particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles;
}
}
else
break;
_timeUntilNextEmit -= timeLeftInFrame;
}
}
void ParticleEffectEntityItem::resetSimulation() {
for (quint32 i = 0; i < _maxParticles; i++) {
quint32 j = i * XYZ_STRIDE;
_paLife[i] = -1.0f;
_paPosition[j] = 0.0f;
_paPosition[j+1] = 0.0f;
_paPosition[j+2] = 0.0f;
_paVelocity[j] = 0.0f;
_paVelocity[j+1] = 0.0f;
_paVelocity[j+2] = 0.0f;
}
_paCount = 0;
_paHead = 0;
_partialEmit = 0.0f;
void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) {
_maxParticles = maxParticles;
srand(_randSeed);
// TODO: try to do something smart here and preserve the state of existing particles.
// resize vectors
_particleLifetimes.resize(_maxParticles);
_particlePositions.resize(_maxParticles);
_particleVelocities.resize(_maxParticles);
// effectivly clear all particles and start emitting new ones from scratch.
_particleHeadIndex = 0;
_particleTailIndex = 0;
_timeUntilNextEmit = 0.0f;
}
// because particles are in a ring buffer, this isn't trivial
quint32 ParticleEffectEntityItem::getLivingParticleCount() const {
if (_particleTailIndex >= _particleHeadIndex) {
return _particleTailIndex - _particleHeadIndex;
} else {
return (_maxParticles - _particleHeadIndex) + _particleTailIndex;
}
}

View file

@ -2,29 +2,6 @@
// ParticleEffectEntityItem.h
// libraries/entities/src
//
// Some starter code for a particle simulation entity, which could ideally be used for a variety of effects.
// This is some really early and rough stuff here. It was enough for now to just get it up and running in the interface.
//
// Todo's and other notes:
// - The simulation should restart when the AnimationLoop's max frame is reached (or passed), but there doesn't seem
// to be a good way to set that max frame to something reasonable right now.
// - There seems to be a bug whereby entities on the edge of screen will just pop off or on. This is probably due
// to my lack of understanding of how entities in the octree are picked for rendering. I am updating the entity
// dimensions based on the bounds of the sim, but maybe I need to update a dirty flag or something.
// - This should support some kind of pre-roll of the simulation.
// - Just to get this out the door, I just did forward Euler integration. There are better ways.
// - Gravity always points along the Y axis. Support an actual gravity vector.
// - Add the ability to add arbitrary forces to the simulation.
// - Add controls for spread (which is currently hard-coded) and varying emission strength (not currently implemented).
// - Add drag.
// - Add some kind of support for collisions.
// - For simplicity, I'm currently just rendering each particle as a cross of four axis-aligned quads. Really, we'd
// want multiple render modes, including (the most important) textured billboards (always facing camera). Also, these
// should support animated textures.
// - There's no synchronization of the simulation across clients at all. In fact, it's using rand() under the hood, so
// there's no gaurantee that different clients will see simulations that look anything like the other.
// - MORE?
//
// Created by Jason Rickwald on 3/2/15.
//
// Distributed under the Apache License, Version 2.0.
@ -39,14 +16,14 @@
class ParticleEffectEntityItem : public EntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual ~ParticleEffectEntityItem();
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of this entity
virtual EntityItemProperties getProperties() const;
virtual bool setProperties(const EntityItemProperties& properties);
@ -54,16 +31,16 @@ public:
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const;
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const;
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
virtual void update(const quint64& now);
virtual bool needsToCallUpdate() const;
@ -71,6 +48,7 @@ public:
const rgbColor& getColor() const { return _color; }
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
static const xColor DEFAULT_COLOR;
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
void setColor(const xColor& value) {
_color[RED_INDEX] = value.red;
@ -109,7 +87,7 @@ public:
float getAnimationLastFrame() const { return _animationLoop.getLastFrame(); }
static const quint32 DEFAULT_MAX_PARTICLES;
void setMaxParticles(quint32 maxParticles) { _maxParticles = maxParticles; }
void setMaxParticles(quint32 maxParticles);
quint32 getMaxParticles() const { return _maxParticles; }
static const float DEFAULT_LIFESPAN;
@ -121,7 +99,7 @@ public:
float getEmitRate() const { return _emitRate; }
static const glm::vec3 DEFAULT_EMIT_DIRECTION;
void setEmitDirection(glm::vec3 emitDirection) { _emitDirection = emitDirection; }
void setEmitDirection(glm::vec3 emitDirection) { _emitDirection = glm::normalize(emitDirection); }
const glm::vec3& getEmitDirection() const { return _emitDirection; }
static const float DEFAULT_EMIT_STRENGTH;
@ -141,11 +119,22 @@ public:
float getAnimationFPS() const { return _animationLoop.getFPS(); }
QString getAnimationSettings() const;
static const QString DEFAULT_TEXTURES;
const QString& getTextures() const { return _textures; }
void setTextures(const QString& textures) {
if (_textures != textures) {
_textures = textures;
_texturesChangedFlag = true;
}
}
protected:
bool isAnimatingSomething() const;
void stepSimulation(float deltaTime);
void resetSimulation();
void extendBounds(const glm::vec3& point);
void integrateParticle(quint32 index, float deltaTime);
quint32 getLivingParticleCount() const;
// the properties of this entity
rgbColor _color;
@ -159,25 +148,24 @@ protected:
quint64 _lastAnimated;
AnimationLoop _animationLoop;
QString _animationSettings;
QString _textures;
bool _texturesChangedFlag;
ShapeType _shapeType = SHAPE_TYPE_NONE;
// all the internals of running the particle sim
const quint32 XYZ_STRIDE = 3;
float* _paLife;
float* _paPosition;
float* _paVelocity;
float _partialEmit;
quint32 _paCount;
quint32 _paHead;
float _paXmin;
float _paXmax;
float _paYmin;
float _paYmax;
float _paZmin;
float _paZmax;
unsigned int _randSeed;
QVector<float> _particleLifetimes;
QVector<glm::vec3> _particlePositions;
QVector<glm::vec3> _particleVelocities;
float _timeUntilNextEmit;
// particle arrays are a ring buffer, use these indicies
// to keep track of the living particles.
quint32 _particleHeadIndex;
quint32 _particleTailIndex;
// bounding volume
glm::vec3 _particleMaxBound;
glm::vec3 _particleMinBound;
};
#endif // hifi_ParticleEffectEntityItem_h

View file

@ -54,8 +54,6 @@ void SimpleEntitySimulation::removeEntityInternal(EntityItem* entity) {
_hasSimulationOwnerEntities.remove(entity);
}
const int SIMPLE_SIMULATION_DIRTY_FLAGS = EntityItem::DIRTY_VELOCITIES | EntityItem::DIRTY_MOTION_TYPE;
void SimpleEntitySimulation::changeEntityInternal(EntityItem* entity) {
EntitySimulation::changeEntityInternal(entity);
if (!entity->getSimulatorID().isNull()) {

View file

@ -12,6 +12,7 @@
#include <glm/gtx/transform.hpp>
#include <math.h>
#include <qcompilerdetection.h>
#include "SkyFromAtmosphere_vert.h"
#include "SkyFromAtmosphere_frag.h"
@ -292,17 +293,19 @@ void SunSkyStage::updateGraphicsObject() const {
}
// Background
switch (getBackgroundMode()) {
case NO_BACKGROUND: {
break;
}
case SKY_DOME: {
break;
}
case SKY_BOX: {
break;
}
};
switch (getBackgroundMode()) {
case NO_BACKGROUND: {
break;
}
case SKY_DOME: {
break;
}
case SKY_BOX: {
break;
}
case NUM_BACKGROUND_MODES:
Q_UNREACHABLE();
};
static int firstTime = 0;
if (firstTime == 0) {

View file

@ -38,9 +38,10 @@ public:
~TextureStorage();
const QUrl& getUrl() const { return _url; }
const gpu::Texture::Type getType() const { return _usage._type; }
gpu::Texture::Type getType() const { return _usage._type; }
const gpu::TexturePointer& getGPUTexture() const { return _gpuTexture; }
virtual void reset() { Storage::reset(); }
void reset(const QUrl& url, const TextureUsage& usage);
protected:

View file

@ -72,7 +72,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
return 1;
case PacketTypeEntityAddOrEdit:
case PacketTypeEntityData:
return VERSION_ENTITIES_ZONE_ENTITIES_STAGE_HAS_AUTOMATIC_HOURDAY;
return VERSION_ENTITIES_PARTICLE_ENTITIES_HAVE_TEXTURES;
case PacketTypeEntityErase:
return 2;
case PacketTypeAudioStreamStats:

View file

@ -173,5 +173,6 @@ const PacketVersion VERSION_ENTITIES_HAVE_NAMES = 19;
const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_ATMOSPHERE = 20;
const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_SKYBOX = 21;
const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_STAGE_HAS_AUTOMATIC_HOURDAY = 22;
const PacketVersion VERSION_ENTITIES_PARTICLE_ENTITIES_HAVE_TEXTURES = 23;
#endif // hifi_PacketHeaders_h

View file

@ -721,6 +721,76 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec3>& points, con
#endif
}
void GeometryCache::updateVertices(int id, const QVector<glm::vec3>& points, const QVector<glm::vec2>& texCoords, const glm::vec4& color) {
BatchItemDetails& details = _registeredVertices[id];
if (details.isCreated) {
details.clear();
#ifdef WANT_DEBUG
qCDebug(renderutils) << "updateVertices()... RELEASING REGISTERED";
#endif // def WANT_DEBUG
}
const int FLOATS_PER_VERTEX = 5;
details.isCreated = true;
details.vertices = points.size();
details.vertexSize = FLOATS_PER_VERTEX;
gpu::BufferPointer verticesBuffer(new gpu::Buffer());
gpu::BufferPointer colorBuffer(new gpu::Buffer());
gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format());
gpu::BufferStreamPointer stream(new gpu::BufferStream());
details.verticesBuffer = verticesBuffer;
details.colorBuffer = colorBuffer;
details.streamFormat = streamFormat;
details.stream = stream;
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
details.streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), 3 * sizeof(float));
details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA));
details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);
details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride);
assert(points.size() == texCoords.size());
details.vertices = points.size();
details.vertexSize = FLOATS_PER_VERTEX;
int compactColor = ((int(color.x * 255.0f) & 0xFF)) |
((int(color.y * 255.0f) & 0xFF) << 8) |
((int(color.z * 255.0f) & 0xFF) << 16) |
((int(color.w * 255.0f) & 0xFF) << 24);
GLfloat* vertexData = new GLfloat[details.vertices * FLOATS_PER_VERTEX];
GLfloat* vertex = vertexData;
int* colorData = new int[details.vertices];
int* colorDataAt = colorData;
for (int i = 0; i < points.size(); i++) {
glm::vec3 point = points[i];
glm::vec2 texCoord = texCoords[i];
*(vertex++) = point.x;
*(vertex++) = point.y;
*(vertex++) = point.z;
*(vertex++) = texCoord.x;
*(vertex++) = texCoord.y;
*(colorDataAt++) = compactColor;
}
details.verticesBuffer->append(sizeof(GLfloat) * FLOATS_PER_VERTEX * details.vertices, (gpu::Byte*) vertexData);
details.colorBuffer->append(sizeof(int) * details.vertices, (gpu::Byte*) colorData);
delete[] vertexData;
delete[] colorData;
#ifdef WANT_DEBUG
qCDebug(renderutils) << "new registered linestrip buffer made -- _registeredVertices.size():" << _registeredVertices.size();
#endif
}
void GeometryCache::renderVertices(gpu::Primitive primitiveType, int id) {
BatchItemDetails& details = _registeredVertices[id];
if (details.isCreated) {

View file

@ -198,6 +198,7 @@ public:
void updateVertices(int id, const QVector<glm::vec2>& points, const glm::vec4& color);
void updateVertices(int id, const QVector<glm::vec3>& points, const glm::vec4& color);
void updateVertices(int id, const QVector<glm::vec3>& points, const QVector<glm::vec2>& texCoords, const glm::vec4& color);
void renderVertices(gpu::Primitive primitiveType, int id);
/// Loads geometry from the specified URL.

View file

@ -117,18 +117,6 @@ void GlowEffect::end() {
glBlendColor(0.0f, 0.0f, 0.0f, _intensity = _intensityStack.pop());
}
static void maybeBind(const gpu::FramebufferPointer& fbo) {
if (fbo) {
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(fbo));
}
}
static void maybeRelease(const gpu::FramebufferPointer& fbo) {
if (fbo) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
}
gpu::FramebufferPointer GlowEffect::render() {
PerformanceTimer perfTimer("glowEffect");

View file

@ -14,6 +14,7 @@
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/transform.hpp>
#include "AABox.h"
#include "Extents.h"
void Extents::reset() {
@ -37,6 +38,11 @@ void Extents::addPoint(const glm::vec3& point) {
maximum = glm::max(maximum, point);
}
void Extents::add(const AABox& box) {
minimum = glm::min(minimum, box.getMinimumPoint());
maximum = glm::max(maximum, box.getMaximumPoint());
}
void Extents::rotate(const glm::quat& rotation) {
glm::vec3 bottomLeftNear(minimum.x, minimum.y, minimum.z);
glm::vec3 bottomRightNear(maximum.x, minimum.y, minimum.z);

View file

@ -19,6 +19,8 @@
#include <QDebug>
#include "StreamUtils.h"
class AABox;
class Extents {
public:
/// set minimum and maximum to FLT_MAX and -FLT_MAX respectively
@ -28,6 +30,10 @@ public:
/// expand current limits to contain other extents
void addExtents(const Extents& extents);
/// \param aabox another intance of extents
/// expand current limits to contain other aabox
void add(const AABox& box);
/// \param point new point to compare against existing limits
/// compare point to current limits and expand them if necessary to contain point
void addPoint(const glm::vec3& point);