Merge pull request #5010 from ericrius1/lineEntity

Modified the line entity to take two new properties: lineWidth and linePoints
This commit is contained in:
Brad Hefta-Gaub 2015-06-02 14:25:44 -07:00
commit 2a8e758559
16 changed files with 159 additions and 20 deletions

View file

@ -12,6 +12,7 @@
#include <glm/gtx/quaternion.hpp>
#include <gpu/GPUConfig.h>
#include <GeometryCache.h>
#include <DeferredLightingEffect.h>
#include <PerfStat.h>
@ -30,12 +31,20 @@ void RenderableLineEntityItem::render(RenderArgs* args) {
glm::quat rotation = getRotation();
glm::vec4 lineColor(toGlm(getXColor()), getLocalRenderAlpha());
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glLineWidth(getLineWidth());
auto geometryCache = DependencyManager::get<GeometryCache>();
if (_lineVerticesID == GeometryCache::UNKNOWN_ID) {
_lineVerticesID = geometryCache ->allocateID();
}
//TODO: Figure out clean , efficient way to do relative line positioning. For now we'll just use absolute positioning.
//glTranslatef(position.x, position.y, position.z);
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glm::vec3 p1 = {0.0f, 0.0f, 0.0f};
glm::vec3& p2 = dimensions;
DependencyManager::get<DeferredLightingEffect>()->renderLine(p1, p2, lineColor, lineColor);
if (_pointsChanged) {
geometryCache->updateVertices(_lineVerticesID, getLinePoints(), lineColor);
_pointsChanged = false;
}
geometryCache->renderVertices(gpu::LINE_STRIP, _lineVerticesID);
glPopMatrix();
RenderableDebugableEntityItem::render(this, args);

View file

@ -14,15 +14,21 @@
#include <LineEntityItem.h>
#include "RenderableDebugableEntityItem.h"
#include <GeometryCache.h>
class RenderableLineEntityItem : public LineEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
LineEntityItem(entityItemID, properties) { }
LineEntityItem(entityItemID, properties),
_lineVerticesID(GeometryCache::UNKNOWN_ID)
{ }
virtual void render(RenderArgs* args);
protected:
int _lineVerticesID;
};

View file

@ -27,6 +27,7 @@
#include "TextEntityItem.h"
#include "ZoneEntityItem.h"
#include "PolyVoxEntityItem.h"
#include "LineEntityItem.h"
AtmospherePropertyGroup EntityItemProperties::_staticAtmosphere;
SkyboxPropertyGroup EntityItemProperties::_staticSkybox;
@ -94,6 +95,8 @@ CONSTRUCT_PROPERTY(voxelSurfaceStyle, PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_S
CONSTRUCT_PROPERTY(name, ENTITY_ITEM_DEFAULT_NAME),
CONSTRUCT_PROPERTY(backgroundMode, BACKGROUND_MODE_INHERIT),
CONSTRUCT_PROPERTY(sourceUrl, ""),
CONSTRUCT_PROPERTY(lineWidth, LineEntityItem::DEFAULT_LINE_WIDTH),
CONSTRUCT_PROPERTY(linePoints, QVector<glm::vec3>()),
_id(UNKNOWN_ENTITY_ID),
@ -344,7 +347,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize);
CHECK_PROPERTY_CHANGE(PROP_VOXEL_DATA, voxelData);
CHECK_PROPERTY_CHANGE(PROP_VOXEL_SURFACE_STYLE, voxelSurfaceStyle);
CHECK_PROPERTY_CHANGE(PROP_LINE_WIDTH, lineWidth);
CHECK_PROPERTY_CHANGE(PROP_LINE_POINTS, linePoints);
changedProperties += _stage.getChangedProperties();
changedProperties += _atmosphere.getChangedProperties();
changedProperties += _skybox.getChangedProperties();
@ -426,10 +430,11 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightDirection);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundMode, getBackgroundModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(sourceUrl);
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelVolumeSize);
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelData);
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelSurfaceStyle);
COPY_PROPERTY_TO_QSCRIPTVALUE(lineWidth);
COPY_PROPERTY_TO_QSCRIPTVALUE(linePoints);
// Sitting properties support
if (!skipDefaults) {
@ -535,10 +540,11 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightDirection, glmVec3, setKeyLightDirection);
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(backgroundMode, BackgroundMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl);
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, glmVec3, setVoxelVolumeSize);
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelData, QByteArray, setVoxelData);
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelSurfaceStyle, uint16_t, setVoxelSurfaceStyle);
COPY_PROPERTY_FROM_QSCRIPTVALUE(lineWidth, float, setLineWidth);
COPY_PROPERTY_FROM_QSCRIPTVALUE(linePoints, qVectorVec3, setLinePoints);
_stage.copyFromScriptValue(object, _defaultSettings);
_atmosphere.copyFromScriptValue(object, _defaultSettings);
@ -763,6 +769,11 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, properties.getVoxelSurfaceStyle());
}
if (properties.getType() == EntityTypes::Line) {
APPEND_ENTITY_PROPERTY(PROP_LINE_WIDTH, properties.getLineWidth());
APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, properties.getLinePoints());
}
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
@ -1003,6 +1014,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_SURFACE_STYLE, uint16_t, setVoxelSurfaceStyle);
}
if (properties.getType() == EntityTypes::Line) {
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_WIDTH, float, setLineWidth);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_POINTS, QVector<glm::vec3>, setLinePoints);
}
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
@ -1107,10 +1123,13 @@ void EntityItemProperties::markAllChanged() {
_skybox.markAllChanged();
_sourceUrlChanged = true;
_voxelVolumeSizeChanged = true;
_voxelDataChanged = true;
_voxelSurfaceStyleChanged = true;
_lineWidthChanged = true;
_linePointsChanged = true;
}
/// The maximum bounding cube for the entity, independent of it's rotation.

View file

@ -145,6 +145,8 @@ public:
DEFINE_PROPERTY_GROUP(Atmosphere, atmosphere, AtmospherePropertyGroup);
DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup);
DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString);
DEFINE_PROPERTY(PROP_LINE_WIDTH, LineWidth, lineWidth, float);
DEFINE_PROPERTY_REF(LINE_POINTS, LinePoints, linePoints, QVector<glm::vec3>);
static QString getBackgroundModeString(BackgroundMode mode);

View file

@ -95,6 +95,7 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QString& v) { ret
inline QScriptValue convertScriptValue(QScriptEngine* e, const xColor& v) { return xColorToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QScriptValue& v) { return v; }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector<glm::vec3>& v) {return qVectorVec3ToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) {
QByteArray b64 = v.toBase64();
@ -131,6 +132,7 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) {
typedef glm::vec3 glmVec3;
typedef glm::quat glmQuat;
typedef QVector<glm::vec3> qVectorVec3;
inline float float_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); }
inline uint16_t uint16_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
@ -167,6 +169,11 @@ inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isVal
return glm::vec3(0);
}
inline qVectorVec3 qVectorVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = true;
return qVectorVec3FromScriptValue(v);
}
inline glmQuat glmQuat_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = false; /// assume it can't be converted
QScriptValue x = v.property("x");

View file

@ -114,6 +114,10 @@ enum EntityPropertyList {
PROP_VOXEL_DATA,
PROP_VOXEL_SURFACE_STYLE,
//for lines
PROP_LINE_WIDTH,
PROP_LINE_POINTS,
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties ABOVE this line
PROP_AFTER_LAST_ITEM,

View file

@ -20,24 +20,41 @@
#include "EntityTreeElement.h"
const float LineEntityItem::DEFAULT_LINE_WIDTH = 2.0f;
EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer result { new LineEntityItem(entityID, properties) };
return result;
}
LineEntityItem::LineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID)
EntityItem(entityItemID) ,
_lineWidth(DEFAULT_LINE_WIDTH),
_pointsChanged(true),
_points(QVector<glm::vec3>(0))
{
_type = EntityTypes::Line;
_created = properties.getCreated();
setProperties(properties);
}
EntityItemProperties LineEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
properties._color = getXColor();
properties._colorChanged = false;
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineWidth, getLineWidth);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(linePoints, getLinePoints);
properties._glowLevel = getGlowLevel();
properties._glowLevelChanged = false;
@ -48,8 +65,11 @@ EntityItemProperties LineEntityItem::getProperties() const {
bool LineEntityItem::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = false;
somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineWidth, setLineWidth);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(linePoints, setLinePoints);
if (somethingChanged) {
bool wantDebug = false;
@ -64,7 +84,12 @@ bool LineEntityItem::setProperties(const EntityItemProperties& properties) {
return somethingChanged;
}
int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
void LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
_points = points;
_pointsChanged = true;
}
int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
@ -72,6 +97,9 @@ int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor);
READ_ENTITY_PROPERTY(PROP_LINE_WIDTH, float, setLineWidth);
READ_ENTITY_PROPERTY(PROP_LINE_POINTS, QVector<glm::vec3>, setLinePoints);
return bytesRead;
}
@ -81,6 +109,8 @@ int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
EntityPropertyFlags LineEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
requestedProperties += PROP_COLOR;
requestedProperties += PROP_LINE_WIDTH;
requestedProperties += PROP_LINE_POINTS;
return requestedProperties;
}
@ -95,6 +125,8 @@ void LineEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor());
APPEND_ENTITY_PROPERTY(PROP_LINE_WIDTH, getLineWidth());
APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, getLinePoints());
}
void LineEntityItem::debugDump() const {

View file

@ -51,6 +51,13 @@ class LineEntityItem : public EntityItem {
_color[BLUE_INDEX] = value.blue;
}
void setLineWidth(float lineWidth){ _lineWidth = lineWidth; }
float getLineWidth() const{ return _lineWidth; }
void setLinePoints(const QVector<glm::vec3>& points);
const QVector<glm::vec3>& getLinePoints() const{ return _points; }
virtual ShapeType getShapeType() const { return SHAPE_TYPE_LINE; }
// never have a ray intersection pick a LineEntityItem.
@ -60,9 +67,13 @@ class LineEntityItem : public EntityItem {
void** intersectedObject, bool precisionPicking) const { return false; }
virtual void debugDump() const;
static const float DEFAULT_LINE_WIDTH;
protected:
rgbColor _color;
float _lineWidth;
bool _pointsChanged;
QVector<glm::vec3> _points;
};
#endif // hifi_LineEntityItem_h

View file

@ -73,7 +73,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketTypeEntityAdd:
case PacketTypeEntityEdit:
case PacketTypeEntityData:
return VERSION_NO_ENTITY_ID_SWAP;
return VERSION_ENTITIES_LINE_POINTS;
case PacketTypeEntityErase:
return 2;
case PacketTypeAudioStreamStats:
@ -135,7 +135,6 @@ QString nameForPacketType(PacketType packetType) {
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPingReply);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAdd);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEdit);
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleEntitiesFix);
default:
return QString("Type: ") + QString::number((int)packetType);
}

View file

@ -79,8 +79,7 @@ enum PacketType {
PacketTypeSignedTransactionPayment,
PacketTypeIceServerHeartbeat, // 50
PacketTypeUnverifiedPing,
PacketTypeUnverifiedPingReply,
PacketTypeParticleEntitiesFix
PacketTypeUnverifiedPingReply
};
typedef char PacketVersion;
@ -183,5 +182,6 @@ const PacketVersion VERSION_ENTITIES_HAVE_COLLISION_SOUND_URL = 25;
const PacketVersion VERSION_ENTITIES_HAVE_FRICTION = 26;
const PacketVersion VERSION_NO_ENTITY_ID_SWAP = 27;
const PacketVersion VERSION_ENTITIES_PARTICLE_FIX = 28;
const PacketVersion VERSION_ENTITIES_LINE_POINTS = 29;
#endif // hifi_PacketHeaders_h

View file

@ -325,6 +325,7 @@ bool OctreePacketData::appendValue(uint8_t value) {
bool OctreePacketData::appendValue(uint16_t value) {
const unsigned char* data = (const unsigned char*)&value;
int length = sizeof(value);
bool success = append(data, length);
if (success) {
@ -358,6 +359,7 @@ bool OctreePacketData::appendValue(quint64 value) {
}
bool OctreePacketData::appendValue(float value) {
const unsigned char* data = (const unsigned char*)&value;
int length = sizeof(value);
bool success = append(data, length);
@ -379,6 +381,17 @@ bool OctreePacketData::appendValue(const glm::vec3& value) {
return success;
}
bool OctreePacketData::appendValue(const QVector<glm::vec3>& value) {
uint16_t qVecSize = value.size();
bool success = appendValue(qVecSize);
success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3));
if (success) {
_bytesOfValues += qVecSize * sizeof(glm::vec3);
_totalBytesOfValues += qVecSize * sizeof(glm::vec3);
}
return success;
}
bool OctreePacketData::appendValue(const glm::quat& value) {
const size_t VALUES_PER_QUAT = 4;
const size_t PACKED_QUAT_SIZE = sizeof(uint16_t) * VALUES_PER_QUAT;
@ -585,6 +598,15 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, xColor
return sizeof(rgbColor);
}
int OctreePacketData::unpackDataFromBytes(const unsigned char *dataBytes, QVector<glm::vec3>& result) {
uint16_t length;
memcpy(&length, dataBytes, sizeof(uint16_t));
dataBytes += sizeof(length);
result.resize(length);
memcpy(result.data(), dataBytes, length * sizeof(glm::vec3));
return sizeof(uint16_t) + length * sizeof(glm::vec3);
}
int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result) {
uint16_t length;
memcpy(&length, dataBytes, sizeof(length));

View file

@ -162,6 +162,9 @@ public:
/// appends a non-position vector to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const glm::vec3& value);
//appends a QVector of vec3's to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const QVector<glm::vec3>& value);
/// appends a packed quat to the end of the stream, may fail if new data stream is too long to fit in packet
bool appendValue(const glm::quat& value);
@ -185,7 +188,7 @@ public:
bool appendRawData(const unsigned char* data, int length);
bool appendRawData(QByteArray data);
/// returns a byte offset from beginning of the uncompressed stream based on offset from end.
/// returns a byte offset from beginning of the uncompressed stream based on offset from end.
/// Positive offsetFromEnd returns that many bytes before the end of uncompressed stream
int getUncompressedByteOffset(int offsetFromEnd = 0) const { return _bytesInUse - offsetFromEnd; }
@ -241,8 +244,10 @@ public:
static int unpackDataFromBytes(const unsigned char* dataBytes, QString& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QUuid& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, xColor& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QVector<glm::vec3>& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result);
private:
/// appends raw bytes, might fail if byte would cause packet to be too large
bool append(const unsigned char* data, int length);

View file

@ -660,7 +660,6 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec2>& points, con
void GeometryCache::updateVertices(int id, const QVector<glm::vec3>& points, const glm::vec4& color) {
BatchItemDetails& details = _registeredVertices[id];
if (details.isCreated) {
details.clear();
#ifdef WANT_DEBUG
@ -799,7 +798,7 @@ void GeometryCache::renderVertices(gpu::Primitive primitiveType, int id) {
batch.setInputFormat(details.streamFormat);
batch.setInputStream(0, *details.stream);
batch.draw(primitiveType, details.vertices, 0);
gpu::GLBackend::renderBatch(batch);
glDisableClientState(GL_VERTEX_ARRAY);

View file

@ -515,7 +515,6 @@ private:
Q_DECLARE_METATYPE(QPointer<Model>)
Q_DECLARE_METATYPE(QWeakPointer<NetworkGeometry>)
Q_DECLARE_METATYPE(QVector<glm::vec3>)
/// Handle management of pending models that need blending
class ModelBlender : public QObject, public Dependency {

View file

@ -27,6 +27,7 @@ static int pickRayMetaTypeId = qRegisterMetaType<PickRay>();
static int collisionMetaTypeId = qRegisterMetaType<Collision>();
void registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue);
qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue);
@ -72,6 +73,26 @@ void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3) {
vec3.z = object.property("z").toVariant().toFloat();
}
QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector<glm::vec3>& vector){
QScriptValue array = engine->newArray();
for (int i = 0; i < vector.size(); i++) {
array.setProperty(i, vec3toScriptValue(engine, vector.at(i)));
}
return array;
}
QVector<glm::vec3> qVectorVec3FromScriptValue(const QScriptValue& array){
QVector<glm::vec3> newVector;
int length = array.property("length").toInteger();
for (int i = 0; i < length; i++) {
glm::vec3 newVec3 = glm::vec3();
vec3FromScriptValue(array.property(i), newVec3);
newVector << newVec3;
}
return newVector;
}
QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2) {
QScriptValue obj = engine->newObject();
obj.setProperty("x", vec2.x);

View file

@ -28,6 +28,7 @@ Q_DECLARE_METATYPE(glm::vec3)
Q_DECLARE_METATYPE(glm::vec2)
Q_DECLARE_METATYPE(glm::quat)
Q_DECLARE_METATYPE(xColor)
Q_DECLARE_METATYPE(QVector<glm::vec3>)
void registerMetaTypes(QScriptEngine* engine);
@ -55,6 +56,9 @@ void qColorFromScriptValue(const QScriptValue& object, QColor& color);
QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url);
void qURLFromScriptValue(const QScriptValue& object, QUrl& url);
QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector<glm::vec3>& vector);
QVector<glm::vec3> qVectorVec3FromScriptValue( const QScriptValue& array);
class PickRay {
public:
PickRay() : origin(0.0f), direction(0.0f) { }