void StructuredVolume::getVolumeFromMemory() { //! Create the equivalent ISPC volume container and allocate memory for voxel data. createEquivalentISPC(); //! Get a pointer to the source voxel data. const Data *voxelData = getParamData("voxelData", NULL); exitOnCondition(voxelData == NULL, "no voxel data specified"); const uint8 *data = (const uint8 *) voxelData->data; //! The dimensions of the source voxel data and target volume must match. exitOnCondition(size_t(volumeDimensions.x) * volumeDimensions.y * volumeDimensions.z != voxelData->numItems, "unexpected source voxel data dimensions"); //! The source and target voxel types must match. exitOnCondition(getVoxelType() != voxelData->type, "unexpected source voxel type"); //! Size of a volume slice in bytes. size_t sliceSizeInBytes = volumeDimensions.x * volumeDimensions.y * getVoxelSizeInBytes(); //! Copy voxel data into the volume in slices to avoid overflow in ISPC offset calculations. for (size_t z=0 ; z < volumeDimensions.z ; z++) setRegion(&data[z * sliceSizeInBytes], vec3i(0, 0, z), vec3i(volumeDimensions.x, volumeDimensions.y, 1)); }
void LinearTransferFunction::createEquivalentISPC() { // The equivalent ISPC transfer function must not exist yet. exitOnCondition(ispcEquivalent != NULL, "attempt to overwrite an existing ISPC transfer function"); // Create the equivalent ISPC transfer function. ispcEquivalent = ispc::LinearTransferFunction_createInstance(); // The object may not have been created. exitOnCondition(ispcEquivalent == NULL, "unable to create ISPC transfer function"); }
void VolumeViewer::initObjects(const std::string &renderer_type) { // Create an OSPRay renderer. renderer = ospNewRenderer(renderer_type.c_str()); exitOnCondition(renderer == NULL, "could not create OSPRay renderer object"); // Set renderer defaults (if not using 'aoX' renderers) if (renderer_type[0] != 'a' && renderer_type[1] != 'o') { ospSet1i(renderer, "aoSamples", 1); ospSet1i(renderer, "shadowsEnabled", 1); } // Create OSPRay ambient and directional lights. GUI elements will modify their parameters. ambientLight = ospNewLight(renderer, "AmbientLight"); exitOnCondition(ambientLight == NULL, "could not create ambient light"); ospCommit(ambientLight); directionalLight = ospNewLight(renderer, "DirectionalLight"); exitOnCondition(directionalLight == NULL, "could not create directional light"); ospCommit(directionalLight); // Set the light sources on the renderer. std::vector<OSPLight> lights; lights.push_back(ambientLight); lights.push_back(directionalLight); ospSetData(renderer, "lights", ospNewData(lights.size(), OSP_OBJECT, &lights[0])); // Create an OSPRay transfer function. transferFunction = ospNewTransferFunction("piecewise_linear"); exitOnCondition(transferFunction == NULL, "could not create OSPRay transfer function object"); ospCommit(transferFunction); // Load OSPRay objects from files. for (size_t i=0 ; i < objectFileFilenames.size() ; i++) importObjectsFromFile(objectFileFilenames[i]); // Get the bounding box of all volumes of the first model. if(modelStates.size() > 0 && modelStates[0].volumes.size() > 0) { ospGetVec3f(modelStates[0].volumes[0], "boundingBoxMin", (osp::vec3f*)&boundingBox.lower); ospGetVec3f(modelStates[0].volumes[0], "boundingBoxMax", (osp::vec3f*)&boundingBox.upper); for (size_t i=1; i<modelStates[0].volumes.size(); i++) { ospcommon::box3f volumeBoundingBox; ospGetVec3f(modelStates[0].volumes[i], "boundingBoxMin", (osp::vec3f*)&volumeBoundingBox.lower); ospGetVec3f(modelStates[0].volumes[i], "boundingBoxMax", (osp::vec3f*)&volumeBoundingBox.upper); boundingBox.extend(volumeBoundingBox); } } }
OSPLight OSPObjectFile::importLight(const tinyxml2::XMLNode *root) { // Create the OSPRay object. OSPLight light = ospNewLight(NULL, root->ToElement()->Attribute("type")); // Iterate over object attributes. for (const tinyxml2::XMLNode *node = root->FirstChild() ; node ; node = node->NextSibling()) { // Light color. if (!strcmp(node->ToElement()->Name(), "color")) { importAttributeFloat3(node, light); continue; } // Light direction. if (!strcmp(node->ToElement()->Name(), "direction")) { importAttributeFloat3(node, light); continue; } // Light half angle for spot lights. if (!strcmp(node->ToElement()->Name(), "halfAngle")) { importAttributeFloat(node, light); continue; } // Light position. if (!strcmp(node->ToElement()->Name(), "position")) { importAttributeFloat3(node, light); continue; } // Light illumination distance cutoff. if (!strcmp(node->ToElement()->Name(), "range")) { importAttributeFloat(node, light); continue; } // Error check. exitOnCondition(true, "unrecognized XML element type '" + std::string(node->ToElement()->Name()) + "'"); } // The populated light object. return light; }
void OSPObjectFile::importAttributeString(const tinyxml2::XMLNode *node, OSPObject parent) { // Get the attribute value. const char *value = node->ToElement()->GetText(); // Error check. exitOnCondition(strlen(value) == 0, "malformed XML element '" + std::string(node->ToElement()->Name()) + "'"); // Set the attribute on the parent object. ospSetString(parent, node->ToElement()->Name(), value); }
void OSPObjectFile::importAttributeInteger(const tinyxml2::XMLNode *node, OSPObject parent) { // The attribute value is encoded in a string. const char *text = node->ToElement()->GetText(); int value = 0; char guard[8]; // Get the attribute value. exitOnCondition(sscanf(text, "%d %7s", &value, guard) != 1, "malformed XML element '" + std::string(node->ToElement()->Name()) + "'"); // Set the attribute on the parent object. ospSet1i(parent, node->ToElement()->Name(), value); }
void GhostBlockBrickedVolume::createEquivalentISPC() { // Get the voxel type. voxelType = getParamString("voxelType", "unspecified"); exitOnCondition(getVoxelType() == OSP_UNKNOWN, "unrecognized voxel type (must be set before calling " "ospSetRegion())"); // Get the volume dimensions. this->dimensions = getParam3i("dimensions", vec3i(0)); exitOnCondition(reduce_min(this->dimensions) <= 0, "invalid volume dimensions (must be set before calling " "ospSetRegion())"); // Create an ISPC GhostBlockBrickedVolume object and assign type-specific // function pointers. ispcEquivalent = ispc::GBBV_createInstance(this, (int)getVoxelType(), (const ispc::vec3i &)this->dimensions); }
void OSPObjectFile::importAttributeFloat3(const tinyxml2::XMLNode *node, OSPObject parent) { //! The attribute value is encoded in a string. const char *text = node->ToElement()->GetText(); vec3f value = vec3f(0.0f); char guard[8]; //! Get the attribute value. exitOnCondition(sscanf(text, "%f %f %f %7s", &value.x, &value.y, &value.z, guard) != 3, "malformed XML element '" + std::string(node->ToElement()->Name()) + "'"); //! Set the attribute on the parent object. ospSetVec3f(parent, node->ToElement()->Name(), value); }
void BlockBrickedVolume::createEquivalentISPC() { //! Get the voxel type. voxelType = getParamString("voxelType", "unspecified"); exitOnCondition(getVoxelType() == OSP_UNKNOWN, "unrecognized voxel type"); //! Create an ISPC BlockBrickedVolume object and assign type-specific function pointers. ispcEquivalent = ispc::BlockBrickedVolume_createInstance((int) getVoxelType()); //! Get the volume dimensions. volumeDimensions = getParam3i("dimensions", vec3i(0)); exitOnCondition(reduce_min(volumeDimensions) <= 0, "invalid volume dimensions"); //! Get the transfer function. transferFunction = (TransferFunction *) getParamObject("transferFunction", NULL); exitOnCondition(transferFunction == NULL, "no transfer function specified"); //! Get the value range. //! Voxel range not used for now. // vec2f voxelRange = getParam2f("voxelRange", vec2f(0.0f)); exitOnCondition(voxelRange == vec2f(0.0f), "no voxel range specified"); //! Get the gamma correction coefficient and exponent. vec2f gammaCorrection = getParam2f("gammaCorrection", vec2f(1.0f)); //! Set the volume dimensions. ispc::BlockBrickedVolume_setVolumeDimensions(ispcEquivalent, (const ispc::vec3i &) volumeDimensions); //! Set the value range (must occur before setting the transfer function). //ispc::BlockBrickedVolume_setValueRange(ispcEquivalent, (const ispc::vec2f &) voxelRange); //! Set the transfer function. ispc::BlockBrickedVolume_setTransferFunction(ispcEquivalent, transferFunction->getEquivalentISPC()); //! Set the recommended sampling rate for ray casting based renderers. ispc::BlockBrickedVolume_setSamplingRate(ispcEquivalent, getParam1f("samplingRate", 1.0f)); //! Set the gamma correction coefficient and exponent. ispc::BlockBrickedVolume_setGammaCorrection(ispcEquivalent, (const ispc::vec2f &) gammaCorrection); //! Allocate memory for the voxel data in the ISPC object. ispc::BlockBrickedVolume_allocateMemory(ispcEquivalent); }
void GhostBlockBrickedVolume::commit() { // The ISPC volume container should already exist. We (currently) // require 'dimensions' etc to be set first, followed by call(s) // to 'setRegion', and only a final commit at the // end. 'dimensions' etc may/will _not_ be committed before // setregion. exitOnCondition(ispcEquivalent == nullptr, "the volume data must be set via ospSetRegion() " "prior to commit for this volume type"); // StructuredVolume commit actions. StructuredVolume::commit(); }
OSPObjectCatalog OSPObjectFile::importObject(const tinyxml2::XMLNode *node) { //! OSPRay light object. if (!strcmp(node->ToElement()->Name(), "light")) return(importLight(node)); //! OSPRay triangle mesh object. if (!strcmp(node->ToElement()->Name(), "triangleMesh")) return(importTriangleMesh(node)); //! OSPRay volume object. if (!strcmp(node->ToElement()->Name(), "volume")) return(importVolume(node)); //! No other object types are currently supported. exitOnCondition(true, "unrecognized XML element type '" + std::string(node->ToElement()->Name()) + "'"); return(NULL); }
OSPGeometry OSPObjectFile::importTriangleMesh(const tinyxml2::XMLNode *root) { // Create the OSPRay object. OSPGeometry triangleMesh = ospNewGeometry("trianglemesh"); // Temporary storage for the file name attribute if specified. const char *triangleMeshFilename = NULL; // Iterate over object attributes. for (const tinyxml2::XMLNode *node = root->FirstChild() ; node ; node = node->NextSibling()) { // File containing a triangle mesh specification and / or data. if (!strcmp(node->ToElement()->Name(), "filename")) { triangleMeshFilename = node->ToElement()->GetText(); continue; } // Scaling for vertex coordinates. if (!strcmp(node->ToElement()->Name(), "scale")) { importAttributeFloat3(node, triangleMesh); continue; } // Error check. exitOnCondition(true, "unrecognized XML element type '" + std::string(node->ToElement()->Name()) + "'"); } // Load the contents of the triangle mesh file if specified. if (triangleMeshFilename != NULL) { // Some implementations of 'dirname()' are destructive. char *duplicateFilename = strdup(filename.c_str()); // The triangle mesh file path is absolute. if (triangleMeshFilename[0] == '/') { return(TriangleMeshFile::importTriangleMesh(triangleMeshFilename, triangleMesh)); } // The triangle mesh file path is relative to the object file path. if (triangleMeshFilename[0] != '/') { return(TriangleMeshFile::importTriangleMesh((std::string(dirname(duplicateFilename)) + "/" + triangleMeshFilename).c_str(), triangleMesh)); } // Free the temporary character array. if (duplicateFilename != NULL) free(duplicateFilename); } // The populated triangle mesh object. return triangleMesh; }
OSPLoadDataMode OSPObjectFile::importLoadDataMode(const tinyxml2::XMLNode *node) { //! The flag is optionally encoded in a string. const char *text = node->ToElement()->Attribute("mode"); //! Load volume data immediately, data will be copied from the host to the device. if (text && !strcmp(text, "loadDataImmediate")) return(OSP_LOAD_DATA_IMMEDIATE); //! Defer the load of volume data to the device, no data copy is necessary. if (text == NULL || !strcmp(text, "loadDataDeferred")) return(OSP_LOAD_DATA_DEFERRED); //! Error check. exitOnCondition(true, "malformed XML element '" + std::string(node->ToElement()->Name()) + "'"); //! The program will never get here. return(OSP_LOAD_DATA_DEFERRED); }
OSPObject *OSPObjectFile::importObjects() { // The XML document container. tinyxml2::XMLDocument xml(true, tinyxml2::COLLAPSE_WHITESPACE); // Read the XML object file. exitOnCondition(xml.LoadFile(filename.c_str()) != tinyxml2::XML_SUCCESS, "unable to read object file '" + filename + "'"); // A list of OSPRay objects and their attributes contained in the file. std::vector<OSPObject> objects; // Iterate over the object entries, skip the XML declaration and comments. for (const tinyxml2::XMLNode *node = xml.FirstChild() ; node ; node = node->NextSibling()) if (node->ToElement()) objects.push_back(importObject(node)); // Copy the objects into a list. OSPObject *pointer = new OSPObject[objects.size() + 1]; memcpy(pointer, &objects[0], objects.size() * sizeof(OSPObject)); // Mark the end of the list. pointer[objects.size()] = NULL; return(pointer); }
OSPObjectCatalog OSPObjectFile::importObjects() { //! The XML document container. tinyxml2::XMLDocument xml(true, tinyxml2::COLLAPSE_WHITESPACE); //! Read the XML object file. exitOnCondition(xml.LoadFile(filename.c_str()) != tinyxml2::XML_SUCCESS, "unable to read object file '" + filename + "'"); //! A catalog of the OSPRay objects and attributes contained in the file. ObjectCatalog *catalog = new ObjectCatalog(); std::vector<OSPObjectCatalog> entries; //! Iterate over the object entries, skip the XML declaration and comments. for (const tinyxml2::XMLNode *node = xml.FirstChild() ; node ; node = node->NextSibling()) if (node->ToElement()) entries.push_back(importObject(node)); //! Copy the object entries into the catalog. catalog->entries = new OSPObjectCatalog[entries.size() + 1](); memcpy(catalog->entries, &entries[0], entries.size() * sizeof(OSPObjectCatalog)); //! The populated catalog. return(catalog); }
void OSPObjectFile::importLightAttribute(const tinyxml2::XMLNode *node, OSPLight light) { //! Light color. if (!strcmp(node->ToElement()->Name(), "color")) return(importAttributeFloat3(node, light)); //! Light direction. if (!strcmp(node->ToElement()->Name(), "direction")) return(importAttributeFloat3(node, light)); //! Light half angle for spot lights. if (!strcmp(node->ToElement()->Name(), "halfAngle")) return(importAttributeFloat(node, light)); //! Light position. if (!strcmp(node->ToElement()->Name(), "position")) return(importAttributeFloat3(node, light)); //! Light illumination distance cutoff. if (!strcmp(node->ToElement()->Name(), "range")) return(importAttributeFloat(node, light)); //! Error check. exitOnCondition(true, "unrecognized XML element type '" + std::string(node->ToElement()->Name()) + "'"); }
void OSPObjectFile::importVolumeAttribute(const tinyxml2::XMLNode *node, OSPVolume volume) { //! Volume size in voxels per dimension. if (!strcmp(node->ToElement()->Name(), "dimensions")) return(importAttributeInteger3(node, volume)); //! File containing a volume specification and / or voxel data. if (!strcmp(node->ToElement()->Name(), "filename")) return(importVolumeFile(node, volume)); //! Gamma correction coefficient and exponent. if (!strcmp(node->ToElement()->Name(), "gammaCorrection")) return(importAttributeFloat2(node, volume)); //! Sampling rate for ray casting based renderers. if (!strcmp(node->ToElement()->Name(), "samplingRate")) return(importAttributeFloat(node, volume)); //! Subvolume offset from origin within the full volume. if (!strcmp(node->ToElement()->Name(), "subvolumeOffsets")) return(importAttributeInteger3(node, volume)); //! Subvolume dimensions within the full volume. if (!strcmp(node->ToElement()->Name(), "subvolumeDimensions")) return(importAttributeInteger3(node, volume)); //! Subvolume steps in each dimension; can be used to subsample the volume. if (!strcmp(node->ToElement()->Name(), "subvolumeSteps")) return(importAttributeInteger3(node, volume)); //! Voxel value range. if (!strcmp(node->ToElement()->Name(), "voxelRange")) return(importAttributeFloat2(node, volume)); //! Voxel spacing in world coordinates (currently unused). if (!strcmp(node->ToElement()->Name(), "voxelSpacing")) return(importAttributeFloat3(node, volume)); //! Voxel type string. if (!strcmp(node->ToElement()->Name(), "voxelType")) return(importAttributeString(node, volume)); //! Error check. exitOnCondition(true, "unrecognized XML element type '" + std::string(node->ToElement()->Name()) + "'"); }
void BlockBrickedVolume::updateEditableParameters() { //! Get the transfer function. transferFunction = (TransferFunction *) getParamObject("transferFunction", NULL); exitOnCondition(transferFunction == NULL, "no transfer function specified"); //! Get the gamma correction coefficient and exponent. vec2f gammaCorrection = getParam2f("gammaCorrection", vec2f(1.0f)); //! Set the gamma correction coefficient and exponent. ispc::BlockBrickedVolume_setGammaCorrection(ispcEquivalent, (const ispc::vec2f &) gammaCorrection); //! Set the recommended sampling rate for ray casting based renderers. ispc::BlockBrickedVolume_setSamplingRate(ispcEquivalent, getParam1f("samplingRate", 1.0f)); //! Set the transfer function. ispc::BlockBrickedVolume_setTransferFunction(ispcEquivalent, transferFunction->getEquivalentISPC()); }
OSPVolume OSPObjectFile::importVolume(const tinyxml2::XMLNode *root) { const char *dpFromEnv = getenv("OSPRAY_DATA_PARALLEL"); OSPVolume volume = NULL; if (dpFromEnv) { // Create the OSPRay object. osp::vec3i blockDims; int rc = sscanf(dpFromEnv,"%dx%dx%d",&blockDims.x,&blockDims.y,&blockDims.z); if (rc !=3) throw std::runtime_error("could not parse OSPRAY_DATA_PARALLEL env-var. Must be of format <X>x<Y>x<>Z (e.g., '4x4x4'"); volume = ospNewVolume("data_distributed_volume"); if (volume == NULL) throw std::runtime_error("#loaders.ospObjectFile: could not create volume ..."); ospSetVec3i(volume,"num_dp_blocks",blockDims); } else { // Create the OSPRay object. volume = ospNewVolume("block_bricked_volume"); } if (volume == NULL) throw std::runtime_error("#loaders.ospObjectFile: could not create volume ..."); // Temporary storage for the file name attribute if specified. const char *volumeFilename = NULL; // Iterate over object attributes. for (const tinyxml2::XMLNode *node = root->FirstChild() ; node ; node = node->NextSibling()) { // Volume size in voxels per dimension. if (!strcmp(node->ToElement()->Name(), "dimensions")) { importAttributeInteger3(node, volume); continue; } // File containing a volume specification and / or voxel data. if (!strcmp(node->ToElement()->Name(), "filename")) { volumeFilename = node->ToElement()->GetText(); continue; } // Grid origin in world coordinates. if (!strcmp(node->ToElement()->Name(), "gridOrigin")) { importAttributeFloat3(node, volume); continue; } // Grid spacing in each dimension in world coordinates. if (!strcmp(node->ToElement()->Name(), "gridSpacing")) { importAttributeFloat3(node, volume); continue; } // Sampling rate for ray casting based renderers. if (!strcmp(node->ToElement()->Name(), "samplingRate")) { importAttributeFloat(node, volume); continue; } // Subvolume offset from origin within the full volume. if (!strcmp(node->ToElement()->Name(), "subvolumeOffsets")) { importAttributeInteger3(node, volume); continue; } // Subvolume dimensions within the full volume. if (!strcmp(node->ToElement()->Name(), "subvolumeDimensions")) { importAttributeInteger3(node, volume); continue; } // Subvolume steps in each dimension; can be used to subsample the volume. if (!strcmp(node->ToElement()->Name(), "subvolumeSteps")) { importAttributeInteger3(node, volume); continue; } // Voxel value range. if (!strcmp(node->ToElement()->Name(), "voxelRange")) { importAttributeFloat2(node, volume); continue; } // Voxel type string. if (!strcmp(node->ToElement()->Name(), "voxelType")) { importAttributeString(node, volume); continue; } // Error check. exitOnCondition(true, "unrecognized XML element type '" + std::string(node->ToElement()->Name()) + "'"); } // Load the contents of the volume file if specified. if (volumeFilename != NULL) { // Some implementations of 'dirname()' are destructive. char *duplicateFilename = strdup(filename.c_str()); // The volume file path is absolute. if (volumeFilename[0] == '/') return(VolumeFile::importVolume(volumeFilename, volume)); // The volume file path is relative to the object file path. if (volumeFilename[0] != '/') return(VolumeFile::importVolume((std::string(dirname(duplicateFilename)) + "/" + volumeFilename).c_str(), volume)); // Free the temporary character array. if (duplicateFilename != NULL) free(duplicateFilename); } // The populated volume object. return volume; }