예제 #1
0
bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& propertiesIn, EntityItemProperties& propertiesOut,
        bool& wasChanged, EntityTree::FilterType filterType, EntityItemID& itemID, EntityItemPointer& existingEntity) {
    
    // get the ids of all the zones (plus the global entity edit filter) that the position
    // lies within
    auto zoneIDs = getZonesByPosition(position);
    for (auto id : zoneIDs) {
        if (!itemID.isInvalidID() && id == itemID) {
            continue;
        }
        
        // get the filter pair, etc...  
        _lock.lockForRead();
        FilterData filterData = _filterDataMap.value(id);
        _lock.unlock();
    
        if (filterData.valid()) {
            if (filterData.rejectAll) {
                return false;
            }

            // check to see if this filter wants to filter this message type
            if ((!filterData.wantsToFilterEdit && filterType == EntityTree::FilterType::Edit) ||
                (!filterData.wantsToFilterPhysics && filterType == EntityTree::FilterType::Physics) ||
                (!filterData.wantsToFilterDelete && filterType == EntityTree::FilterType::Delete) ||
                (!filterData.wantsToFilterAdd && filterType == EntityTree::FilterType::Add)) {

                wasChanged = false;
                return true; // accept the message
            }

            auto oldProperties = propertiesIn.getDesiredProperties();
            auto specifiedProperties = propertiesIn.getChangedProperties();
            propertiesIn.setDesiredProperties(specifiedProperties);
            QScriptValue inputValues = propertiesIn.copyToScriptValue(filterData.engine, false, true, true);
            propertiesIn.setDesiredProperties(oldProperties);

            auto in = QJsonValue::fromVariant(inputValues.toVariant()); // grab json copy now, because the inputValues might be side effected by the filter.

            QScriptValueList args;
            args << inputValues;
            args << filterType;

            // get the current properties for then entity and include them for the filter call
            if (existingEntity && filterData.wantsOriginalProperties) {
                auto currentProperties = existingEntity->getProperties(filterData.includedOriginalProperties);
                QScriptValue currentValues = currentProperties.copyToScriptValue(filterData.engine, false, true, true);
                args << currentValues;
            }


            // get the zone properties
            if (filterData.wantsZoneProperties) {
                auto zoneEntity = _tree->findEntityByEntityItemID(id);
                if (zoneEntity) {
                    auto zoneProperties = zoneEntity->getProperties(filterData.includedZoneProperties);
                    QScriptValue zoneValues = zoneProperties.copyToScriptValue(filterData.engine, false, true, true);

                    if (filterData.wantsZoneBoundingBox) {
                        bool success = true;
                        AABox aaBox = zoneEntity->getAABox(success);
                        if (success) {
                            QScriptValue boundingBox = filterData.engine->newObject();
                            QScriptValue bottomRightNear = vec3ToScriptValue(filterData.engine, aaBox.getCorner());
                            QScriptValue topFarLeft = vec3ToScriptValue(filterData.engine, aaBox.calcTopFarLeft());
                            QScriptValue center = vec3ToScriptValue(filterData.engine, aaBox.calcCenter());
                            QScriptValue boundingBoxDimensions = vec3ToScriptValue(filterData.engine, aaBox.getDimensions());
                            boundingBox.setProperty("brn", bottomRightNear);
                            boundingBox.setProperty("tfl", topFarLeft);
                            boundingBox.setProperty("center", center);
                            boundingBox.setProperty("dimensions", boundingBoxDimensions);
                            zoneValues.setProperty("boundingBox", boundingBox);
                        }
                    }

                    // If this is an add or delete, or original properties weren't requested
                    // there won't be original properties in the args, but zone properties need
                    // to be the fourth parameter, so we need to pad the args accordingly
                    int EXPECTED_ARGS = 3;
                    if (args.length() < EXPECTED_ARGS) {
                        args << QScriptValue();
                    }
                    assert(args.length() == EXPECTED_ARGS); // we MUST have 3 args by now!
                    args << zoneValues;
                }
            }

            QScriptValue result = filterData.filterFn.call(_nullObjectForFilter, args);

            if (filterData.uncaughtExceptions()) {
                return false;
            }

            if (result.isObject()) {
                // make propertiesIn reflect the changes, for next filter...
                propertiesIn.copyFromScriptValue(result, false);

                // and update propertiesOut too.  TODO: this could be more efficient...
                propertiesOut.copyFromScriptValue(result, false);
                // Javascript objects are == only if they are the same object. To compare arbitrary values, we need to use JSON.
                auto out = QJsonValue::fromVariant(result.toVariant());
                wasChanged |= (in != out);
            } else if (result.isBool()) {

                // if the filter returned false, then it's authoritative
                if (!result.toBool()) {
                    return false;
                }

                // otherwise, assume it wants to pass all properties
                propertiesOut = propertiesIn;
                wasChanged = false;
                
            } else {
                return false;
            }
        }
    }
    // if we made it here, 
    return true;
}
예제 #2
0
void AudioMixer::sendAudioEnvironmentPacket(SharedNodePointer node) {
    // Send stream properties
    bool hasReverb = false;
    float reverbTime, wetLevel;
    // find reverb properties
    for (int i = 0; i < _zoneReverbSettings.size(); ++i) {
        AudioMixerClientData* data = static_cast<AudioMixerClientData*>(node->getLinkedData());
        glm::vec3 streamPosition = data->getAvatarAudioStream()->getPosition();
        AABox box = _audioZones[_zoneReverbSettings[i].zone];
        if (box.contains(streamPosition)) {
            hasReverb = true;
            reverbTime = _zoneReverbSettings[i].reverbTime;
            wetLevel = _zoneReverbSettings[i].wetLevel;

            break;
        }
    }

    AudioMixerClientData* nodeData = static_cast<AudioMixerClientData*>(node->getLinkedData());
    AvatarAudioStream* stream = nodeData->getAvatarAudioStream();
    bool dataChanged = (stream->hasReverb() != hasReverb) ||
    (stream->hasReverb() && (stream->getRevebTime() != reverbTime ||
                             stream->getWetLevel() != wetLevel));
    if (dataChanged) {
        // Update stream
        if (hasReverb) {
            stream->setReverb(reverbTime, wetLevel);
        } else {
            stream->clearReverb();
        }
    }

    // Send at change or every so often
    float CHANCE_OF_SEND = 0.01f;
    bool sendData = dataChanged || (randFloat() < CHANCE_OF_SEND);

    if (sendData) {
        auto nodeList = DependencyManager::get<NodeList>();

        unsigned char bitset = 0;

        int packetSize = sizeof(bitset);

        if (hasReverb) {
            packetSize += sizeof(reverbTime) + sizeof(wetLevel);
        }

        auto envPacket = NLPacket::create(PacketType::AudioEnvironment, packetSize);

        if (hasReverb) {
            setAtBit(bitset, HAS_REVERB_BIT);
        }

        envPacket->writePrimitive(bitset);

        if (hasReverb) {
            envPacket->writePrimitive(reverbTime);
            envPacket->writePrimitive(wetLevel);
        }
        nodeList->sendPacket(std::move(envPacket), *node);
    }
}
예제 #3
0
void BBoxDeco::render(RenderContext* renderContext)
{
  AABox bbox = renderContext->scene->getBoundingBox();

  if (bbox.isValid()) {
  
    Vertex center = bbox.getCenter();
    bbox += center + (bbox.vmin - center)*expand;
    bbox += center + (bbox.vmax - center)*expand;

    // Sphere bsphere(bbox);

    glPushAttrib(GL_ENABLE_BIT);

    int i,j;

    // vertex array:

    Vertex4 boxv[8] = {
      Vertex4( bbox.vmin.x, bbox.vmin.y, bbox.vmin.z ),
      Vertex4( bbox.vmax.x, bbox.vmin.y, bbox.vmin.z ),
      Vertex4( bbox.vmin.x, bbox.vmax.y, bbox.vmin.z ),
      Vertex4( bbox.vmax.x, bbox.vmax.y, bbox.vmin.z ),
      Vertex4( bbox.vmin.x, bbox.vmin.y, bbox.vmax.z ),
      Vertex4( bbox.vmax.x, bbox.vmin.y, bbox.vmax.z ),
      Vertex4( bbox.vmin.x, bbox.vmax.y, bbox.vmax.z ),
      Vertex4( bbox.vmax.x, bbox.vmax.y, bbox.vmax.z )
    };

    Vertex4 eyev[8];

    // transform vertices: used for edge distance criterion and text justification

    Matrix4x4 modelview(renderContext->modelview);

    for(i=0;i<8;i++)
      eyev[i] = modelview * boxv[i];
 
    // setup material
    
    material.beginUse(renderContext);

    if (material.line_antialias || material.isTransparent()) {
      // SETUP BLENDING
      if (renderContext->gl2psActive == GL2PS_NONE) 
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
      else
	gl2psBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
      // ENABLE BLENDING
      glEnable(GL_BLEND);
      
    }
    
    // edge adjacent matrix

    int adjacent[8][8] = { { 0 } };

    // draw back faces
    // construct adjacent matrix

    glBegin(GL_QUADS);

    for(i=0;i<6;i++) {

      const Vertex4 q = modelview * side[i].normal;
      const Vertex4 view(0.0f,0.0f,1.0f,0.0f);
      
      float cos_a = view * q;

      const bool front = (cos_a >= 0.0f) ? true : false;

      if (draw_front || !front) {

        // draw face

        glNormal3f(side[i].normal.x, side[i].normal.y, side[i].normal.z);

        for(j=0;j<4;j++) {

	  if (!front) {
            // modify adjacent matrix

            int from = side[i].vidx[j];
            int to   = side[i].vidx[(j+1)%4];

            adjacent[from][to] = 1;
          }          
          
          // feed vertex

          Vertex4& v = boxv[ side[i].vidx[j] ];
          glVertex3f(v.x, v.y, v.z);

        }

      }
    }

    glEnd();

    // setup mark length

    Vertex marklen = getMarkLength(bbox);


    // draw axis and tickmarks
    // find contours
    
    glDisable(GL_LIGHTING);

    material.useColor(1);

    for(i=0;i<3;i++) {

      Vertex4 v;
      AxisInfo*  axis;
      Edge*  axisedge;
      int    nedges;
      float* valueptr;
      float  low, high;

      switch(i)
      {
        case 0:
          axis     = &xaxis;       
          axisedge = xaxisedge;
          nedges   = 4;
          valueptr = &v.x;
          low      = bbox.vmin.x;
          high     = bbox.vmax.x;
          break;
        case 1:
          axis     = &yaxis;
          axisedge = yaxisedge;
          nedges   = 8;
          valueptr = &v.y;
          low      = bbox.vmin.y;
          high     = bbox.vmax.y;
          break;
        case 2:
	default:
          axis     = &zaxis;
          axisedge = zaxisedge;
          nedges   = 4;
          valueptr = &v.z;
          low      = bbox.vmin.z;
          high     = bbox.vmax.z;
          break;
      }

      if (axis->mode == AXIS_NONE)
        continue;

      // search z-nearest contours
      
      float d = FLT_MAX;
      Edge* edge = NULL;

      for(j=0;j<nedges;j++) {
  
        int from = axisedge[j].from;
        int to   = axisedge[j].to;

        if ((adjacent[from][to] == 1) && (adjacent[to][from] == 0)) {

          // found contour
          
          float dtmp = -(eyev[from].z + eyev[to].z)/2.0f;

          if (dtmp < d) {
  
            // found near contour

            d = dtmp;
            edge = &axisedge[j];

          }

        } 

      }

      if (edge) {

        v = boxv[edge->from];

        switch (axis->mode) {
          case AXIS_CUSTOM:
            {
              // draw axis and tickmarks

              StringArrayIterator iter(&axis->textArray);


              for (iter.first(), j=0; (j<axis->nticks) && (!iter.isDone());j++, iter.next()) {

                float value = axis->ticks[j];

                // clip marks

                if ((value >= low) && (value <= high)) {
                
                  String string = iter.getCurrent();
                  *valueptr = value;
                  axis->draw(renderContext, v, edge->dir, modelview, marklen, string);
                }

              }
            }
            break;
          case AXIS_LENGTH:
            {
              float delta = (axis->len>1) ? (high-low)/((axis->len)-1) : 0;

              for(int k=0;k<axis->len;k++)
              {
                float value = low + delta * (float)k;
                
                *valueptr = value;

                char text[32];
                sprintf(text, "%.4g", value);

                String string(strlen(text),text);

                axis->draw(renderContext, v, edge->dir, modelview, marklen, string);
              }
            }
            break;
          case AXIS_UNIT:
            {
              float value =  ( (float) ( (int) ( ( low+(axis->unit-1) ) / (axis->unit) ) ) ) * (axis->unit);
              while(value < high) {

                *valueptr = value;

                char text[32];
                sprintf(text, "%.4g", value);

                String s (strlen(text),text);

                axis->draw(renderContext, v, edge->dir, modelview, marklen, s );

                value += axis->unit;
              }
            }
            break;
          case AXIS_PRETTY:
            {
              /* These are the defaults from the R pretty() function, except min_n is 3 */
              double lo=low, up=high, shrink_sml=0.75, high_u_fact[2];
              int ndiv=axis->len, min_n=3, eps_correction=0;
              
              high_u_fact[0] = 1.5;
              high_u_fact[1] = 2.75;
              axis->unit = R_pretty0(&lo, &up, &ndiv, min_n, shrink_sml, high_u_fact, 
                                     eps_correction, 0);
              
              for (int i=(int)lo; i<=up; i++) {
                float value = i*axis->unit;
		if (value >= low && value <= high) {
                  *valueptr = value;

                  char text[32];
                  sprintf(text, "%.4g", value);

                  String s (strlen(text),text);

                  axis->draw(renderContext, v, edge->dir, modelview, marklen, s );
		}
              }
            }
            break;
            
        }
      }
    }
    material.endUse(renderContext);
    glPopAttrib();
  }
}
예제 #4
0
void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
    ShapeType type = getShapeType();
    if (type != SHAPE_TYPE_COMPOUND) {
        ModelEntityItem::computeShapeInfo(info);
        info.setParams(type, 0.5f * getDimensions());
    } else {
        const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();

        // should never fall in here when collision model not fully loaded
        // hence we assert collisionNetworkGeometry is not NULL
        assert(collisionNetworkGeometry);

        const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry();
        const QSharedPointer<NetworkGeometry> renderNetworkGeometry = _model->getGeometry();
        const FBXGeometry& renderGeometry = renderNetworkGeometry->getFBXGeometry();

        _points.clear();
        unsigned int i = 0;

        // the way OBJ files get read, each section under a "g" line is its own meshPart.  We only expect
        // to find one actual "mesh" (with one or more meshParts in it), but we loop over the meshes, just in case.
        foreach (const FBXMesh& mesh, collisionGeometry.meshes) {
            // each meshPart is a convex hull
            foreach (const FBXMeshPart &meshPart, mesh.parts) {
                QVector<glm::vec3> pointsInPart;

                // run through all the triangles and (uniquely) add each point to the hull
                unsigned int triangleCount = meshPart.triangleIndices.size() / 3;
                for (unsigned int j = 0; j < triangleCount; j++) {
                    unsigned int p0Index = meshPart.triangleIndices[j*3];
                    unsigned int p1Index = meshPart.triangleIndices[j*3+1];
                    unsigned int p2Index = meshPart.triangleIndices[j*3+2];
                    glm::vec3 p0 = mesh.vertices[p0Index];
                    glm::vec3 p1 = mesh.vertices[p1Index];
                    glm::vec3 p2 = mesh.vertices[p2Index];
                    if (!pointsInPart.contains(p0)) {
                        pointsInPart << p0;
                    }
                    if (!pointsInPart.contains(p1)) {
                        pointsInPart << p1;
                    }
                    if (!pointsInPart.contains(p2)) {
                        pointsInPart << p2;
                    }
                }

                // run through all the quads and (uniquely) add each point to the hull
                unsigned int quadCount = meshPart.quadIndices.size() / 4;
                assert((unsigned int)meshPart.quadIndices.size() == quadCount*4);
                for (unsigned int j = 0; j < quadCount; j++) {
                    unsigned int p0Index = meshPart.quadIndices[j*4];
                    unsigned int p1Index = meshPart.quadIndices[j*4+1];
                    unsigned int p2Index = meshPart.quadIndices[j*4+2];
                    unsigned int p3Index = meshPart.quadIndices[j*4+3];
                    glm::vec3 p0 = mesh.vertices[p0Index];
                    glm::vec3 p1 = mesh.vertices[p1Index];
                    glm::vec3 p2 = mesh.vertices[p2Index];
                    glm::vec3 p3 = mesh.vertices[p3Index];
                    if (!pointsInPart.contains(p0)) {
                        pointsInPart << p0;
                    }
                    if (!pointsInPart.contains(p1)) {
                        pointsInPart << p1;
                    }
                    if (!pointsInPart.contains(p2)) {
                        pointsInPart << p2;
                    }
                    if (!pointsInPart.contains(p3)) {
                        pointsInPart << p3;
                    }
                }

                if (pointsInPart.size() == 0) {
                    qCDebug(entitiesrenderer) << "Warning -- meshPart has no faces";
                    continue;
                }

                // add next convex hull
                QVector<glm::vec3> newMeshPoints;
                _points << newMeshPoints;
                // add points to the new convex hull
                _points[i++] << pointsInPart;
            }
        }

        // We expect that the collision model will have the same units and will be displaced
        // from its origin in the same way the visual model is.  The visual model has
        // been centered and probably scaled.  We take the scaling and offset which were applied
        // to the visual model and apply them to the collision model (without regard for the
        // collision model's extents).

        glm::vec3 scale = getDimensions() / renderGeometry.getUnscaledMeshExtents().size();
        // multiply each point by scale before handing the point-set off to the physics engine.
        // also determine the extents of the collision model.
        AABox box;
        for (int i = 0; i < _points.size(); i++) {
            for (int j = 0; j < _points[i].size(); j++) {
                // compensate for registraion
                _points[i][j] += _model->getOffset();
                // scale so the collision points match the model points
                _points[i][j] *= scale;
                box += _points[i][j];
            }
        }

        glm::vec3 collisionModelDimensions = box.getDimensions();
        info.setParams(type, collisionModelDimensions, _compoundShapeURL);
        info.setConvexHulls(_points);
    }
}